After last week’s success with BrowserStack, I tried to run Playwright on Selenium Grid. The user experience for this use case is at the opposite end of the scale. The documentation is not much help and Selenium Grid has its own incompatibilities. Let’s look at how we can still make it work.
Preparation
I added this little test that shows me what browser runs the test:
1 2 3 4 5 6 7 8 9 |
[Test] public async Task Where() { await Page.GotoAsync("https://www.whatismybrowser.com/"); var version = await Page.Locator("#primary-browser-detection") .InnerTextAsync(); Console.WriteLine(version); } |
If I run it directly through Visual Studio, I get this output:
YOUR WEB BROWSER IS:
Headless Chrome 108 on Windows 10
When we run this test in Selenium Grid, the operating system should change to Linux.
Create a dynamic Selenium Grid
You can follow along my post on how to create a dynamic Selenium Grid. However, we need different container versions and two additional environment variables. It is a small wonder that Playwright works, but it is super specific what versions it accepts (see issue #18892 on GitHub).
Make sure that your config.toml looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[docker] # Configs have a mapping between the Docker image to use # and the capabilities that need to be matched to # start a container with the given image. configs = [ "selenium/standalone-firefox:4.5.0-20221017", "{\"browserName\": \"firefox\"}", "selenium/standalone-chrome:4.5.0-20221017", "{\"browserName\": \"chrome\"}", "selenium/standalone-edge:4.5.0-20221017", "{\"browserName\": \"MicrosoftEdge\"}" ] # URL for connecting to the docker daemon url = "http://host.docker.internal:2375" # Docker image used for video recording video-image = "selenium/video:ffmpeg-4.3.1-20221017" |
The docker-compose-v3-dynamic-grid.yml needs version 4.5.0-20221017 for the containers and you must add SE_NODE_PORT
and SE_NODE_GRID_URL
as environment variables:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
version: "3" services: node-docker: image: selenium/node-docker:4.5.0-20221017 volumes: - ./assets:/opt/selenium/assets - ./config.toml:/opt/bin/config.toml # - /var/run/docker.sock:/var/run/docker.sock depends_on: - selenium-hub environment: - SE_EVENT_BUS_HOST=selenium-hub - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 - SE_NODE_GRID_URL=http://localhost:4444/wd/hub - SE_NODE_PORT=5555 selenium-hub: image: selenium/hub:4.5.0-20221017 container_name: selenium-hub ports: - "4442:4442" - "4443:4443" - "4444:4444" |
You can start the dynamic Grid with this command:
1 |
docker-compose -f docker-compose-v3-dynamic-grid.yml up |
Run codegen with Selenium Grid
We can run the test code generator in a PowerShell terminal with these two commands:
1 2 |
$env:SELENIUM_REMOTE_URL='http://localhost:4444/wd/hub' .\playwright.ps1 codegen https://www.google.com |
If everything works, only the Playwright Inspector window will start. The browser runs in the Selenium Grid where you can connect to the session in http://127.0.0.1:4444/ui#/sessions (password: secret).
You can click inside the Selenium Grid session and the code gets recorded in the Playwright Inspector window:
Run the library project inside Selenium Grid
As with codegen, we must set the environment variable pointing to our Selenium Grid. Otherwise, the Playwright code looks as if we want to run it locally:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
private static async Task SeleniumGrid() { Environment.SetEnvironmentVariable("SELENIUM_REMOTE_URL", "http://localhost:4444/wd/hub"); using var playwright = await Playwright.CreateAsync(); await using var browser = await playwright.Chromium.LaunchAsync(); var context = await browser.NewContextAsync( new() { RecordVideoDir = "videos/", Locale = "en-GB" }); var page = await context.NewPageAsync(); await page.GotoAsync("chrome://version/"); Thread.Sleep(5000); await page.GotoAsync("https://www.google.com/"); await page.GetByRole(AriaRole.Button, new() { NameString = "Accept all" }).ClickAsync(); await page.WaitForURLAsync("https://www.google.com/"); await page.Locator("[aria-label='Search']").ClickAsync(); await page.FillAsync("[aria-label='Search']", "BrowserStack"); await page.Locator("[aria-label='Google Search'] >> nth=0").ClickAsync(); var title = await page.TitleAsync(); await browser.CloseAsync(); } |
The video recording is done by Playwright and not by Selenium Grid. Therefore, your video will be in the videos folder and not in the assets folder of the Selenium Grid.
Run NUnit tests inside Selenium Grid
Since the tests need no changes, we can set the environment variable and the run dotnet test to use our Selenium Grid:
1 2 |
$env:SELENIUM_REMOTE_URL='http://localhost:4444/wd/hub' dotnet test |
The output of the Where() test should write something like this to the console:
YOUR WEB BROWSER IS:
Headless Chrome 106 on Linux
Next
Selenium Grid can be used with Playwright but prepare yourself for a lot of fiddling before you can use it. Selenium works a lot smoother and with better support should something go wrong. With these challenges out of the way, it is an elegant way to change to a remote execution of your tests – all it takes is an environment variable and you are good to go.
Next week we take a deeper look on the production-readiness of Playwright.