English 中文(简体)
How to test different browser using specflow and Playwright (cross browsing)
原标题:

I m new on Playwright and specflow, i would like to know what s the best approach for testing scenario on all browser (chromium, firefox, webkit). The current project used Selenium, but now we want to use playwright to achieve this. Do you have any idea of how to achieve this in an efficient way ? Thank you !

I tried to use tags @chromium @firefox @webkit on scenario and create a hook class :

using TechTalk.SpecFlow;
using System;
using Microsoft.Playwright;
using System.Linq;
using BoDi;
using NLog.Targets;

namespace mynamespace.Steps
{
    [Binding]
    public class Hooks : IDisposable
    {
        private readonly IObjectContainer _container;
        private readonly IPlaywright _playwright;

        public Hooks(IObjectContainer container, IPlaywright playwright)
        {
            this._container = container;
            this._playwright = playwright;
        }

        [BeforeScenario(Order = 0)]
        public void InitializePlaywrightContext()
        {
            // Get the browser types from the command-line parameters
            var browserTypes = GetBrowserTypesFromCommandLine();
            var iBrowserTypes = browserTypes.Cast<IBrowserType>().ToArray();

            // Initialize the Playwright context and register it in the ObjectContainer
            var playwrightContext = new PlaywrightContext(iBrowserTypes);
            _container.RegisterInstanceAs(playwrightContext);
        }

        private IBrowserType[] GetBrowserTypesFromCommandLine()
        {
            var browserArg = Environment.GetEnvironmentVariable("browser");

            if (string.IsNullOrEmpty(browserArg))
            {
                var chromium = BrowserType.Chromium.ToArray();
                // If no browser argument is specified, default to Chromium
                return new IBrowserType[] { _playwright.Chromium };
            }
            else
            {
                // Split the browserArg by commas to get multiple browsers
                var browserNames = browserArg.ToLower().Split(new char[] {  ,  }, StringSplitOptions.RemoveEmptyEntries);
                // Map the browser names to corresponding BrowserType
                IBrowserType[] browserTypes = browserNames.Select(browserName =>
                {
                    
                    return browserName switch
                    {
                        "chromium" => _playwright.Chromium,
                        "firefox" => _playwright.Firefox,
                        "webkit" => _playwright.Webkit,
                        _ => _playwright.Chromium,// If an invalid browser name is specified, default to Chromium
                    };
                }).ToArray();

                return browserTypes;
            }
        }
        public void Dispose()
        {
            _container?.Dispose();
        }
    }

}

Then create a playwright context :

using Microsoft.Playwright;
using BoDi;
using System.Collections.Generic;
using System;
using System.Threading.Tasks;

public class PlaywrightContext
{
    private readonly IBrowserType[] browserTypes;
    private readonly IPage[] pages;
    public IBrowser[] Browsers { get; private set; }
    public IPage[] Pages { get; private set; }

    public PlaywrightContext(IObjectContainer container, IBrowserType[] browserTypes)
    {
        this.browserTypes = browserTypes;
        Initialize(container);
    }

    private void Initialize(IObjectContainer container)
    {
        Browsers = new IBrowser[browserTypes.Length];
        Pages = new IPage[browserTypes.Length];

        for (int i = 0; i < browserTypes.Length; i++)
        {
            Browsers[i] = browserTypes[i].LaunchAsync().GetAwaiter().GetResult();
            Pages[i] = Browsers[i].NewPageAsync().GetAwaiter().GetResult();
            container.RegisterInstanceAs(Browsers[i]);
            container.RegisterInstanceAs(Pages[i]);
        }
    }

    public IBrowser GetBrowserForBrand(string branding)
    {
        // Implement logic to return the corresponding browser based on branding
        // For example:
        if (branding == "Chrome")
        {
            return Browsers[0]; // Assuming Chrome is the first browser in the array
        }
        else if (branding == "Firefox")
        {
            return Browsers[1]; // Assuming Firefox is the second browser in the array
        }
        else if (branding == "Webkit")
        {
            return Browsers[2]; // Assuming Webkit is the third browser in the array
        }
        else
        {
            throw new ArgumentException($"Invalid branding: {branding}");
        }
    }

    public async ValueTask DisposeAsync()
    {
        foreach (var browser in Browsers)
        {
            await browser?.CloseAsync();
        }
    }
}

But can t figure out how to use it in my step class :

namespace mynamespace.Steps
{
    [Binding]
    public sealed class TransactionStepsPlaywright
    {
        private readonly ScenarioContext _scenarioContext;
        private readonly ITransactionService _transactionService;
        private readonly ApiSettings _apiSettings;
        private readonly ILoggingService _loggingService;
        private readonly int _maxRetries = 3;
        private readonly INavigationPane _navigationPane;
        private readonly IOtpService _otpService;
        private readonly IObjectContainer _container;
        private readonly PlaywrightContext _playwrightContext;
        private readonly IPlaywright _playwright; // Add IPlaywright dependency

        public TransactionStepsPlaywright(ScenarioContext scenarioContext, PlaywrightContext playwrightContext, IObjectContainer container, ILoggingService loggingService, ITransactionService transactionService, IOtpService otpService, IPlaywright playwright, IOptions<ApiSettings> apiSettingsOption, INavigationPane navigationPane) // Add IPlaywright here
        {
            _scenarioContext = scenarioContext;
            _transactionService = transactionService;
            _playwright = playwright; // Use IPlaywright here
            _apiSettings = apiSettingsOption.Value;
            _loggingService = loggingService;
            _navigationPane = navigationPane;
            _otpService = otpService;
            _container = container;
            _playwrightContext = playwrightContext;
        }

        [Given(@"pw I open the login page for (.*)")]
        public void GivenIOpenTheLoginPageFor(string branding)
        {
            try
            {
                var url = _apiSettings.EndPoints.FirstOrDefault(
                    ep => string.Compare(ep.Name, branding, StringComparison.InvariantCultureIgnoreCase) == 0
                ).Url;

                var browser = _playwrightContext.GetBrowserForBrand(branding); // Get the corresponding browser for the given branding
                var page = browser.NewPageAsync().GetAwaiter().GetResult(); // Create a new page for the browser

                page.GotoAsync(url).GetAwaiter().GetResult();
                Console.WriteLine($"Opened the login page for branding: {branding} in {browser.Name}.");
            }
            catch (Exception)
            {
                throw new Exception($"Could not navigate to login page for branding: {branding}.");
            }
        }
问题回答

I m not familiar with PlayWright, but based on what you provided, it initializes browsers based on environment variable. Set environment variable named "browser" with value "chromium,firefox,webkit" and use it in your "Given" as "pw I open the login page for Chrome" or "pw I open the login page for Firefox".

Initialization defaults to chromium and you can test your Given by using "pw I open the login page for Chrome" and see if it works.





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签