C# PlayWright 使用 Selenium Grid 錯誤解決方式

在 Docker 內的 Selenium 或是 Selenium Grid 執行 PlayWright 時出現下面的錯誤:
    
正在啟動測試執行,請稍候...
總共有 1 個測試檔案與指定的模式相符。
  失敗 Test1 [30 s]
  錯誤訊息:
   Microsoft.Playwright.PlaywrightException : WebSocket error: connect ETIMEDOUT 172.18.0.3:4444
=========================== logs ===========================
<selenium> connecting to http://localhost:4444/
<selenium> connected to sessionId=6b7b18721e10fbc049b02946d36a7602
<selenium> using selenium v4
<selenium> retrieved endpoint ws://172.18.0.3:4444/session/6b7b18511e10fbc049b02946d36a7602/se/cdp for sessionId=6b7b18721e10fbc049b02946d36a7602
<ws connecting> ws://172.18.0.3:4444/session/6b7b18721e10fbc049b02946d36a7602/se/cdp
<ws error> ws://172.18.0.3:4444/session/6b7b18721e10fbc049b02946d36a7602/se/cdp error connect ETIMEDOUT 172.18.0.3:4444
<ws connect error> ws://172.18.0.3:4444/session/6b7b18721e10fbc049b02946d36a7602/se/cdp connect ETIMEDOUT 172.18.0.3:4444
<ws disconnected> ws://172.18.0.3:4444/session/6b7b18721e10fbc049b02946d36a7602/se/cdp code=1006 reason=
<selenium> disconnecting from sessionId=6b7b18721e10fbc049b02946d36a7602
<selenium> disconnected from sessionId=6b7b18721e10fbc049b02946d36a7602
============================================================
  堆疊追蹤:
     at Microsoft.Playwright.Transport.Connection.InnerSendMessageToServerAsync[T](String guid, String method, Dictionary`2 dictionary) in /_/src/Playwright/Transport/Connection.cs:line 143
   at Microsoft.Playwright.Transport.Connection.WrapApiCallAsync[T](Func`1 action, Boolean isInternal) in /_/src/Playwright/Transport/Connection.cs:line 465
   at Microsoft.Playwright.Core.BrowserType.LaunchAsync(BrowserTypeLaunchOptions options) in /_/src/Playwright/Core/BrowserType.cs:line 61
   at Microsoft.Playwright.NUnit.BrowserService.<>c__DisplayClass4_0.<<Register>b__0>d.MoveNext() in /_/src/Playwright.NUnit/BrowserService.cs:line 36
--- End of stack trace from previous location ---
   at Microsoft.Playwright.NUnit.WorkerAwareTest.RegisterService[T](String name, Func`1 factory) in /_/src/Playwright.NUnit/WorkerAwareTest.cs:line 55
   at Microsoft.Playwright.NUnit.BrowserTest.BrowserSetup() in /_/src/Playwright.NUnit/BrowserTest.cs:line 46
   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.RunSetUp(TestExecutionContext context)
   at NUnit.Framework.Internal.Commands.SetUpTearDownCommand.<>c__DisplayClass0_0.<.ctor>b__0(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)


失敗!  - 失敗:     1,通過:     0,略過:     0,總計:     1,持續時間: 30 s - TestProjectPlaywrightTest.dll (net7.0)
    

這個 172 的 ip 一看就像是 Docker 內部的 ip ,一直不知道該怎麼解決,研究了很久,發現其實在官方文件一開始就有說需要設定 SE_NODE_GRID_URL 環境變數了,只是不是要執行 dotnet test 時使用,而是要設定到 Docker 內部。

單容器附加環境變數範例:
    
docker run -d -p 4444:4444 --shm-size="2g" -e SE_NODE_GRID_URL="http://localhost:4444" selenium/standalone-chrome:4.3.0-20220726
    

Docker Compose 設定檔案附加環境變數範例:
    
version: "3"
services:
  node-docker:
    image: selenium/node-docker:4.8.3-20230404
    volumes:
      - ./assets:/opt/selenium/assets
      - ./NodeDocker/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

  selenium-hub:
    image: selenium/hub:4.8.3-20230404
    container_name: selenium-hub
    ports:
      - "4442:4442"
      - "4443:4443"
      - "4444:4444"
    

完整範例可以查看: 使用 Docker 快速建立 Selenium Grid

使用 Selenium Grid 執行方式

加上 SELENIUM_REMOTE_URL 環境變數指定 Selenium URL

Windows:
    
$env:SELENIUM_REMOTE_URL="http://localhost:4444"
    

macOS:
    
export SELENIUM_REMOTE_URL="http://localhost:4444"
    
註: 接下來都會以 Windows 為主,其他作業系統請自行替換設定環境變數方式。

設定完環境變數後直接執行測試即可
    
dotnet test
    

啟用有頭模式

成功使用 Selenium Grid 執行後連進去會發現沒有瀏覽器,一開始以為沒有成功,後來想到在 C# 中的 PlayWright 預設就是無頭模式,不會有 GUI 介面。

若要啟用有頭模式(顯示瀏覽器介面)可以透過設定 HEADED 環境變數的方式:
    
$env:HEADED=1
    

對了,以防忘記,Selenium Grid 的預設密碼是 secret



參考資料:
PlayWright - Selenium Grid
PlayWright - Test Runners

留言