Search code examples
c#playwright-dotnet

Playwright with C# issue- TearDown : System.InvalidOperationException OR Microsoft.Playwright.TargetClosedException


I have written 4 or 5 tests in one test class which are getting execute parallelly. If those are getting executed sequentially no issue occurs, but any how I want to execute those parallelly.

This is very random issue.

  • Operating System: [Windows 11]
  • CPU: [x64]
  • Browser: [All, Chromium, Firefox, WebKit]
  • .NET Version (TFM): [net8.0]
  • Playwright.NUnit 1.44.0 But when executing those test any alternate tests are getting failed and some of them are getting passed.

Failed tests showing following issue.

TearDown : System.InvalidOperationException : Collection was modified; enumeration operation may not execute.
--TearDown
   at System.Collections.Generic.List`1.Enumerator.MoveNext()
   at Microsoft.Playwright.NUnit.BrowserTest.BrowserTearDown() in /_/src/Playwright.NUnit/BrowserTest.cs:line 55
   at NUnit.Framework.Internal.TaskAwaitAdapter.GenericAdapter`1.BlockUntilCompleted()
   at NUnit.Framework.Internal.MessagePumpStrategy.NoMessagePumpStrategy.WaitForCompletion(AwaitAdapter awaiter)
   at NUnit.Framework.Internal.AsyncToSyncAdapter.Await(Func`1 invoke)
   at NUnit.Framework.Internal.Commands.SetUpTearDownItem.RunSetUpOrTearDownMethod(TestExecutionContext context, IMethodInfo method)
   at NUnit.Framework.Internal.Commands.SetUpTearDownItem.RunTearDown(TestExecutionContext context)
Microsoft.Playwright.TargetClosedException : Target page, context or browser has been closed
   at Microsoft.Playwright.Transport.Connection.InnerSendMessageToServerAsync[T](ChannelOwner object, String method, Dictionary`2 dictionary, Boolean keepNulls) in /_/src/Playwright/Transport/Connection.cs:line 206
   at Microsoft.Playwright.Transport.Connection.WrapApiCallAsync[T](Func`1 action, Boolean isInternal) in /_/src/Playwright/Transport/Connection.cs:line 532
   at Microsoft.Playwright.Core.Page.ScreenshotAsync(PageScreenshotOptions options) in /_/src/Playwright/Core/Page.cs:line 675
   at MyTests.Utilities.Traces.AllureScreenshot.TakeAllureScreenshot(IPage page, String stepDetail, Status status) in C:\Users\kedarg\Documents\Project\AutomationTool\MGB-Member-Portal-Automation\MyTests\Utilities\Traces\AllureScreenshot.cs:line 19
   at MyTests.Tests.Sections.LoginTests.LoginTest.LogInInfo(Login login) in C:\Users\kedarg\Documents\Project\AutomationTool\MGB-Member-Portal-Automation\MyTests\Tests\Sections\LoginTests\LoginTest.cs:line 170
   at Allure.Net.Commons.Steps.AllureAbstractStepAspect.WrapAsync(Func`2 target, Object[] args, MethodBase metadata, String stepName, List`1 stepParameters)
   at NUnit.Framework.Internal.TaskAwaitAdapter.GenericAdapter`1.BlockUntilCompleted()
   at NUnit.Framework.Internal.MessagePumpStrategy.NoMessagePumpStrategy.WaitForCompletion(AwaitAdapter awaiter)
   at NUnit.Framework.Internal.AsyncToSyncAdapter.Await(Func`1 invoke)
   at NUnit.Framework.Internal.Commands.TestMethodCommand.RunTestMethod(TestExecutionContext context)
   at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context)
   at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0()
   at NUnit.Framework.Internal.Commands.DelegatingTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action)

My code is as below:

namespace MyTests.Tests.Sections.LoginTests
{
    [Parallelizable(ParallelScope.All)]
    [TestFixture]
    [AllureNUnit]
    public class LoginTest : BaseTestSetup
    {
        [OneTimeSetUp]
        public void OneTimeSetup()
        {
            _baseUrl = JsonDataManager.Instance.GetApplicationUrl();
        }

        [Test]
        [AllureStep]
        //[Parallelizable(ParallelScope.Self)]
        public async Task UserNameEditable()
        {
            var page = Browser
                .NewContextAsync(new CustomBrowserNewContextOptions().Create())
                .Result.NewPageAsync()
                .Result;
            try
            {
                //* Arrange

                //var newPage = await Browser.NewContextAsync(new CustomBrowserNewContextOptions().Create()).Result.NewPageAsync();
                LoginPage loginPage = new LoginPage(page);
                //* Act
                await loginPage.VisitPage(_baseUrl);
                var userNameField = loginPage.GetUserNameLocator();
                //* Assert
                await Assertions.Expect(userNameField).ToBeEditableAsync();
                await AllureScreenshot.TakeAllureScreenshot(
                    page,
                    "Username field is editable",
                    Status.passed
                );
                await page.CloseAsync();
            }
            catch (Exception ex)
            {
                await AllureScreenshot.TakeAllureScreenshot(
                    page,
                    "Username editable test failed",
                    Status.failed
                );
                await page.CloseAsync();
                Assert.Fail($"Username field on login page is not editable : {ex.Message}");
            }
        }

        [Test]
        [AllureStep]
        //[Parallelizable(ParallelScope.Self)]
        public async Task PasswordEditable()
        {
            var page = Browser
                .NewContextAsync(new CustomBrowserNewContextOptions().Create())
                .Result.NewPageAsync()
                .Result;
            try
            {
                //* Arrange

                //var newPage = await Browser.NewContextAsync(new CustomBrowserNewContextOptions().Create()).Result.NewPageAsync();
                LoginPage loginPage = new LoginPage(page);
                //* Act
                await loginPage.VisitPage(_baseUrl);
                var passwordField = loginPage.GetPasswordLocator();
                //* Assert
                await Assertions.Expect(passwordField).ToBeEditableAsync();
                await AllureScreenshot.TakeAllureScreenshot(
                    page,
                    "Password field is editable",
                    Status.passed
                );
                await page.CloseAsync();
            }
            catch (Exception ex)
            {
                await AllureScreenshot.TakeAllureScreenshot(
                    page,
                    "Password editable test failed",
                    Status.failed
                );
                await page.CloseAsync();
                Assert.Fail($"Password field on login page is not editable : {ex.Message}");
            }
        }

        [Test]
        [AllureStep]
        //[Parallelizable(ParallelScope.Self)]
        public async Task SignInClickable()
        {
            var page = Browser
                .NewContextAsync(new CustomBrowserNewContextOptions().Create())
                .Result.NewPageAsync()
                .Result;
            try
            {
                //* Arrange
                LoginPage loginPage = new LoginPage(page);
                //* Act
                await loginPage.VisitPage(_baseUrl);
                var signInBtn = loginPage.GetSignInLocator();
                //* Assert
                await Assertions.Expect(signInBtn).ToBeEnabledAsync();
                await AllureScreenshot.TakeAllureScreenshot(
                    page,
                    "Sign in button is clickable",
                    Status.passed
                );
                await page.CloseAsync();
            }
            catch (Exception ex)
            {
                await AllureScreenshot.TakeAllureScreenshot(
                    page,
                    "Sign in button is not clickable",
                    Status.failed
                );
                await page.CloseAsync();
                Assert.Fail($"Sign In button on login page is not clickable : {ex.Message}");
            }
        }

        [Test]
        [AllureStep]
        [TestCaseSource(typeof(TestDataProvider), nameof(TestDataProvider.GetLogins))]
        public async Task LogInInfo(Login login)
        {
            var page = Browser
                .NewContextAsync(new CustomBrowserNewContextOptions().Create())
                .Result.NewPageAsync()
                .Result;
            try
            {
                //* Arrange
                LoginPage loginPage = new LoginPage(page);
                string password = AesOperation.DecryptString(null, login.password);
                //* Act
                var loginLocator = await loginPage.LogInInfo(
                    url: _baseUrl,
                    user: login.username,
                    pass: password
                );

                //* Assert
                await Assertions
                    .Expect(loginLocator.WelcomeMenu)
                    .ToHaveTextAsync(new Regex("PERSON NAME"));
                await AllureScreenshot.TakeAllureScreenshot(
                    page,
                    "Login Performed Successfully",
                    Status.passed
                );
                await page.CloseAsync();
            }
            catch (Exception ex)
            {
                await AllureScreenshot.TakeAllureScreenshot(page, "Login Failed", Status.failed);
                await page.CloseAsync();
                Assert.Fail($"Failed to log in with user '{login.username}': {ex.Message}");
            }
        }
    }

Solution

  • As per the Microsoft team, method level parallel execution is not possible till version 1.45.1

    https://github.com/microsoft/playwright-dotnet/issues/2979