From a7599ad509ab1f66b14239727f3156d9cfcebca4 Mon Sep 17 00:00:00 2001 From: cavivie Date: Mon, 27 May 2024 17:24:23 +0800 Subject: [PATCH 01/15] feat(api): add host option in launchServer options (#30999) --- docs/src/api/class-android.md | 6 ++++++ docs/src/api/class-browserserver.md | 2 ++ docs/src/api/class-browsertype.md | 6 ++++++ .../playwright-core/src/androidServerImpl.ts | 2 +- .../playwright-core/src/browserServerImpl.ts | 2 +- packages/playwright-core/src/client/types.ts | 2 ++ packages/playwright-core/types/types.d.ts | 17 +++++++++++++++++ tests/android/launch-server.spec.ts | 11 +++++++++++ tests/library/browsertype-launch-server.spec.ts | 7 +++++++ 9 files changed, 53 insertions(+), 2 deletions(-) diff --git a/docs/src/api/class-android.md b/docs/src/api/class-android.md index c889ee5d0b..c976c9bba8 100644 --- a/docs/src/api/class-android.md +++ b/docs/src/api/class-android.md @@ -202,6 +202,12 @@ Prevents automatic playwright driver installation on attach. Assumes that the dr Optional device serial number to launch the browser on. If not specified, it will throw if multiple devices are connected. +### option: Android.launchServer.host +* since: v1.45 +- `host` <[string]> + +Host to use for the web socket. It is optional and if it is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise. Consider hardening it with picking a specific interface. + ### option: Android.launchServer.port * since: v1.28 - `port` <[int]> diff --git a/docs/src/api/class-browserserver.md b/docs/src/api/class-browserserver.md index 21f318a70a..0de5c1228b 100644 --- a/docs/src/api/class-browserserver.md +++ b/docs/src/api/class-browserserver.md @@ -31,3 +31,5 @@ Browser websocket url. Browser websocket endpoint which can be used as an argument to [`method: BrowserType.connect`] to establish connection to the browser. + +Note that if the listen `host` option in `launchServer` options is not specified, localhost will be output anyway, even if the actual listening address is an unspecified address. diff --git a/docs/src/api/class-browsertype.md b/docs/src/api/class-browsertype.md index 6a776f1cee..176f696e1d 100644 --- a/docs/src/api/class-browsertype.md +++ b/docs/src/api/class-browsertype.md @@ -380,6 +380,12 @@ const { chromium } = require('playwright'); // Or 'webkit' or 'firefox'. ### option: BrowserType.launchServer.logger = %%-browser-option-logger-%% * since: v1.8 +### option: BrowserType.launchServer.host +* since: v1.45 +- `host` <[string]> + +Host to use for the web socket. It is optional and if it is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise. Consider hardening it with picking a specific interface. + ### option: BrowserType.launchServer.port * since: v1.8 - `port` <[int]> diff --git a/packages/playwright-core/src/androidServerImpl.ts b/packages/playwright-core/src/androidServerImpl.ts index 4c3685076e..a0d7bb5496 100644 --- a/packages/playwright-core/src/androidServerImpl.ts +++ b/packages/playwright-core/src/androidServerImpl.ts @@ -50,7 +50,7 @@ export class AndroidServerLauncherImpl { // 2. Start the server const server = new PlaywrightServer({ mode: 'launchServer', path, maxConnections: 1, preLaunchedAndroidDevice: device }); - const wsEndpoint = await server.listen(options.port); + const wsEndpoint = await server.listen(options.port, options.host); // 3. Return the BrowserServer interface const browserServer = new ws.EventEmitter() as (BrowserServer & WebSocketEventEmitter); diff --git a/packages/playwright-core/src/browserServerImpl.ts b/packages/playwright-core/src/browserServerImpl.ts index 41f9c2c2e4..dfe960c5ea 100644 --- a/packages/playwright-core/src/browserServerImpl.ts +++ b/packages/playwright-core/src/browserServerImpl.ts @@ -58,7 +58,7 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher { // 2. Start the server const server = new PlaywrightServer({ mode: 'launchServer', path, maxConnections: Infinity, preLaunchedBrowser: browser, preLaunchedSocksProxy: socksProxy }); - const wsEndpoint = await server.listen(options.port); + const wsEndpoint = await server.listen(options.port, options.host); // 3. Return the BrowserServer interface const browserServer = new ws.EventEmitter() as (BrowserServer & WebSocketEventEmitter); diff --git a/packages/playwright-core/src/client/types.ts b/packages/playwright-core/src/client/types.ts index 2fc2cea0d1..e649a21303 100644 --- a/packages/playwright-core/src/client/types.ts +++ b/packages/playwright-core/src/client/types.ts @@ -111,6 +111,7 @@ export type LaunchServerOptions = { }, downloadsPath?: string, chromiumSandbox?: boolean, + host?: string, port?: number, wsPath?: string, logger?: Logger, @@ -122,6 +123,7 @@ export type LaunchAndroidServerOptions = { adbHost?: string, adbPort?: number, omitDriverInstall?: boolean, + host?: string, port?: number, wsPath?: string, }; diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index fa24e066b6..54d79f9ca1 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -13745,6 +13745,13 @@ export interface BrowserType { */ headless?: boolean; + /** + * Host to use for the web socket. It is optional and if it is omitted, the server will accept connections on the + * unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise. Consider + * hardening it with picking a specific interface. + */ + host?: string; + /** * If `true`, Playwright does not pass its own configurations args and only uses the ones from `args`. If an array is * given, then filters out the given default arguments. Dangerous option; use with care. Defaults to `false`. @@ -14621,6 +14628,13 @@ export interface Android { */ deviceSerialNumber?: string; + /** + * Host to use for the web socket. It is optional and if it is omitted, the server will accept connections on the + * unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise. Consider + * hardening it with picking a specific interface. + */ + host?: string; + /** * Prevents automatic playwright driver installation on attach. Assumes that the drivers have been installed already. */ @@ -17201,6 +17215,9 @@ export interface BrowserServer { * Browser websocket endpoint which can be used as an argument to * [browserType.connect(wsEndpoint[, options])](https://playwright.dev/docs/api/class-browsertype#browser-type-connect) * to establish connection to the browser. + * + * Note that if the listen `host` option in `launchServer` options is not specified, localhost will be output anyway, + * even if the actual listening address is an unspecified address. */ wsEndpoint(): string; diff --git a/tests/android/launch-server.spec.ts b/tests/android/launch-server.spec.ts index c90a25b0a0..80c9760f2e 100644 --- a/tests/android/launch-server.spec.ts +++ b/tests/android/launch-server.spec.ts @@ -30,6 +30,17 @@ test('android.launchServer should connect to a device', async ({ playwright }) = await browserServer.close(); }); +test('android.launchServer should work with host', async ({ playwright }) => { + const host = '0.0.0.0'; + const browserServer = await playwright._android.launchServer({ host }); + expect(browserServer.wsEndpoint()).toContain(String(host)); + const device = await playwright._android.connect(browserServer.wsEndpoint()); + const output = await device.shell('echo 123'); + expect(output.toString()).toBe('123\n'); + await device.close(); + await browserServer.close(); +}); + test('android.launchServer should handle close event correctly', async ({ playwright }) => { const receivedEvents: string[] = []; const browserServer = await playwright._android.launchServer(); diff --git a/tests/library/browsertype-launch-server.spec.ts b/tests/library/browsertype-launch-server.spec.ts index dcb69d614b..f56d9d500e 100644 --- a/tests/library/browsertype-launch-server.spec.ts +++ b/tests/library/browsertype-launch-server.spec.ts @@ -26,6 +26,13 @@ it.describe('launch server', () => { await browserServer.close(); }); + it('should work with host', async ({ browserType }) => { + const host = '0.0.0.0'; + const browserServer = await browserType.launchServer({ host }); + expect(browserServer.wsEndpoint()).toContain(String(host)); + await browserServer.close(); + }); + it('should work with port', async ({ browserType }, testInfo) => { const port = 8800 + testInfo.workerIndex; const browserServer = await browserType.launchServer({ port }); From ef65cff2e168077b5f82d54b4282accfbdbd8313 Mon Sep 17 00:00:00 2001 From: Playwright Service <89237858+playwrightmachine@users.noreply.github.com> Date: Mon, 27 May 2024 09:40:06 -0700 Subject: [PATCH 02/15] feat(chromium-tip-of-tree): roll to r1225 (#31035) Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- packages/playwright-core/browsers.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/playwright-core/browsers.json b/packages/playwright-core/browsers.json index 062ec55ea1..f20bfca986 100644 --- a/packages/playwright-core/browsers.json +++ b/packages/playwright-core/browsers.json @@ -9,9 +9,9 @@ }, { "name": "chromium-tip-of-tree", - "revision": "1223", + "revision": "1225", "installByDefault": false, - "browserVersion": "127.0.6492.0" + "browserVersion": "127.0.6504.0" }, { "name": "firefox", From 6a055434cee9861a4b35953c993a8fb2d2cac990 Mon Sep 17 00:00:00 2001 From: Playwright Service <89237858+playwrightmachine@users.noreply.github.com> Date: Tue, 28 May 2024 05:15:32 -0700 Subject: [PATCH 03/15] feat(chromium-tip-of-tree): roll to r1226 (#31044) Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- packages/playwright-core/browsers.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/playwright-core/browsers.json b/packages/playwright-core/browsers.json index f20bfca986..268692bb1b 100644 --- a/packages/playwright-core/browsers.json +++ b/packages/playwright-core/browsers.json @@ -9,9 +9,9 @@ }, { "name": "chromium-tip-of-tree", - "revision": "1225", + "revision": "1226", "installByDefault": false, - "browserVersion": "127.0.6504.0" + "browserVersion": "127.0.6505.0" }, { "name": "firefox", From a300a15afe5471c7e307de6dd8be89241f041eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20H=C3=A4kkinen?= Date: Tue, 28 May 2024 15:17:34 +0300 Subject: [PATCH 04/15] docs(test-fixtures): fix minor grammar mistake (#31046) --- docs/src/test-fixtures-js.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/src/test-fixtures-js.md b/docs/src/test-fixtures-js.md index 48c9d074ba..0971922d35 100644 --- a/docs/src/test-fixtures-js.md +++ b/docs/src/test-fixtures-js.md @@ -926,9 +926,9 @@ export default defineConfig({ Each fixture has a setup and teardown phase separated by the `await use()` call in the fixture. Setup is executed before the fixture is used by the test/hook, and teardown is executed when the fixture will not be used by the test/hook anymore. Fixtures follow these rules to determine the execution order: -* When fixture A depends on fixture B: B is always set up before A and teared down after A. +* When fixture A depends on fixture B: B is always set up before A and torn down after A. * Non-automatic fixtures are executed lazily, only when the test/hook needs them. -* Test-scoped fixtures are teared down after each test, while worker-scoped fixtures are only teared down when the worker process executing tests is shutdown. +* Test-scoped fixtures are torn down after each test, while worker-scoped fixtures are only torn down when the worker process executing tests is shutdown. Consider the following example: @@ -1036,8 +1036,8 @@ Normally, if all tests pass and no errors are thrown, the order of execution is * `beforeEach` runs. * `first test` runs. * `afterEach` runs. - * `page` teardown because it is a test-scoped fixture and should be teared down after the test finishes. - * `autoTestFixture` teardown because it is a test-scoped fixture and should be teared down after the test finishes. + * `page` teardown because it is a test-scoped fixture and should be torn down after the test finishes. + * `autoTestFixture` teardown because it is a test-scoped fixture and should be torn down after the test finishes. * `second test` section: * `autoTestFixture` setup because automatic test fixtures are always set up before test and `beforeEach` hooks. * `page` setup because it is required in `beforeEach` hook. @@ -1046,20 +1046,20 @@ Normally, if all tests pass and no errors are thrown, the order of execution is * `testFixture` setup because it is required by the `second test`. * `second test` runs. * `afterEach` runs. - * `testFixture` teardown because it is a test-scoped fixture and should be teared down after the test finishes. - * `page` teardown because it is a test-scoped fixture and should be teared down after the test finishes. - * `autoTestFixture` teardown because it is a test-scoped fixture and should be teared down after the test finishes. + * `testFixture` teardown because it is a test-scoped fixture and should be torn down after the test finishes. + * `page` teardown because it is a test-scoped fixture and should be torn down after the test finishes. + * `autoTestFixture` teardown because it is a test-scoped fixture and should be torn down after the test finishes. * `afterAll` and worker teardown section: * `afterAll` runs. - * `workerFixture` teardown because it is a workers-scoped fixture and should be teared down once at the end. - * `autoWorkerFixture` teardown because it is a workers-scoped fixture and should be teared down once at the end. - * `browser` teardown because it is a workers-scoped fixture and should be teared down once at the end. + * `workerFixture` teardown because it is a workers-scoped fixture and should be torn down once at the end. + * `autoWorkerFixture` teardown because it is a workers-scoped fixture and should be torn down once at the end. + * `browser` teardown because it is a workers-scoped fixture and should be torn down once at the end. A few observations: -* `page` and `autoTestFixture` are set up and teared down for each test, as test-scoped fixtures. +* `page` and `autoTestFixture` are set up and torn down for each test, as test-scoped fixtures. * `unusedFixture` is never set up because it is not used by any tests/hooks. * `testFixture` depends on `workerFixture` and triggers its setup. -* `workerFixture` is lazily set up before the second test, but teared down once during worker shutdown, as a worker-scoped fixture. +* `workerFixture` is lazily set up before the second test, but torn down once during worker shutdown, as a worker-scoped fixture. * `autoWorkerFixture` is set up for `beforeAll` hook, but `autoTestFixture` is not. ## Combine custom fixtures from multiple modules From ef023c4f401857e8e2e23e80d2c2a6a7872ce8fc Mon Sep 17 00:00:00 2001 From: Ernst de Jong <46344663+ErnstdeJong@users.noreply.github.com> Date: Tue, 28 May 2024 16:14:21 +0200 Subject: [PATCH 05/15] chore(types): fix typo in screenshot mode (#31047) --- docs/src/test-api/class-testoptions.md | 2 +- packages/playwright/types/test.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/test-api/class-testoptions.md b/docs/src/test-api/class-testoptions.md index e8cbfa373c..6a4dfd55c7 100644 --- a/docs/src/test-api/class-testoptions.md +++ b/docs/src/test-api/class-testoptions.md @@ -559,7 +559,7 @@ Whether to record trace for each test. Defaults to `'off'`. * `'on-first-retry'`: Record trace only when retrying a test for the first time. * `'on-all-retries'`: Record trace only when retrying a test. * `'retain-on-failure'`: Record trace for each test. When test run passes, remove the recorded trace. -* `'retain-on-first-failure'`: Record trace for the first run of each test, but not for retires. When test run passes, remove the recorded trace. +* `'retain-on-first-failure'`: Record trace for the first run of each test, but not for retries. When test run passes, remove the recorded trace. For more control, pass an object that specifies `mode` and trace features to enable. diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index e1299272a8..a7c5c8a6a4 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -5075,7 +5075,7 @@ export interface PlaywrightWorkerOptions { * - `'on-first-retry'`: Record trace only when retrying a test for the first time. * - `'on-all-retries'`: Record trace only when retrying a test. * - `'retain-on-failure'`: Record trace for each test. When test run passes, remove the recorded trace. - * - `'retain-on-first-failure'`: Record trace for the first run of each test, but not for retires. When test run + * - `'retain-on-first-failure'`: Record trace for the first run of each test, but not for retries. When test run * passes, remove the recorded trace. * * For more control, pass an object that specifies `mode` and trace features to enable. From fb8f8681280fdbac3dfb034bbebd243bb6c2ea28 Mon Sep 17 00:00:00 2001 From: Playwright Service <89237858+playwrightmachine@users.noreply.github.com> Date: Tue, 28 May 2024 08:20:55 -0700 Subject: [PATCH 06/15] feat(webkit): roll to r2013 (#31045) Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- packages/playwright-core/browsers.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/playwright-core/browsers.json b/packages/playwright-core/browsers.json index 268692bb1b..4f0533c3e9 100644 --- a/packages/playwright-core/browsers.json +++ b/packages/playwright-core/browsers.json @@ -27,7 +27,7 @@ }, { "name": "webkit", - "revision": "2012", + "revision": "2013", "installByDefault": true, "revisionOverrides": { "mac10.14": "1446", From 1fafbe580cdf09baaaccf9b9ee6e6ee2b87fabd1 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Tue, 28 May 2024 18:08:34 +0200 Subject: [PATCH 07/15] docs(test-cli): remove --tag from docs (#31041) Fixes https://github.com/microsoft/playwright/issues/31038 --- docs/src/test-cli-js.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/src/test-cli-js.md b/docs/src/test-cli-js.md index aa4430bd42..290fb7df96 100644 --- a/docs/src/test-cli-js.md +++ b/docs/src/test-cli-js.md @@ -100,7 +100,6 @@ Complete set of Playwright Test options is available in the [configuration file] | `--reporter ` | Choose a reporter: minimalist `dot`, concise `line` or detailed `list`. See [reporters](./test-reporters.md) for more information. You can also pass a path to a [custom reporter](./test-reporters.md#custom-reporters) file. | | `--retries ` | The maximum number of [retries](./test-retries.md#retries) for flaky tests, defaults to zero (no retries). | | `--shard ` | [Shard](./test-parallel.md#shard-tests-between-multiple-machines) tests and execute only selected shard, specified in the form `current/all`, 1-based, for example `3/5`.| -| `--tag ` | Only run tests with a tag matching this tag expression. Learn more about [tagging](./test-annotations.md#tag-tests). | | `--timeout ` | Maximum timeout in milliseconds for each test, defaults to 30 seconds. Learn more about [various timeouts](./test-timeouts.md).| | `--trace ` | Force tracing mode, can be `on`, `off`, `on-first-retry`, `on-all-retries`, `retain-on-failure` | | `--update-snapshots` or `-u` | Whether to update [snapshots](./test-snapshots.md) with actual results instead of comparing them. Use this when snapshot expectations have changed.| From 3d7bd70aea53c6f1e147e1fce32d2ea7a91db806 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Tue, 28 May 2024 18:10:53 +0200 Subject: [PATCH 08/15] devops: bump actions/github-script@v6 to actions/github-script@v7 (#31028) --- .github/workflows/cherry_pick_into_release_branch.yml | 2 +- .github/workflows/create_test_report.yml | 2 +- .github/workflows/pr_check_client_side_changes.yml | 2 +- .github/workflows/roll_browser_into_playwright.yml | 2 +- .github/workflows/roll_driver_nodejs.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cherry_pick_into_release_branch.yml b/.github/workflows/cherry_pick_into_release_branch.yml index f48028b14b..08c5562f35 100644 --- a/.github/workflows/cherry_pick_into_release_branch.yml +++ b/.github/workflows/cherry_pick_into_release_branch.yml @@ -60,7 +60,7 @@ jobs: git checkout -b "$BRANCH_NAME" git push origin $BRANCH_NAME - name: Create Pull Request - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} script: | diff --git a/.github/workflows/create_test_report.yml b/.github/workflows/create_test_report.yml index 4da024272d..8ae54609e4 100644 --- a/.github/workflows/create_test_report.yml +++ b/.github/workflows/create_test_report.yml @@ -58,7 +58,7 @@ jobs: path: '.' - name: Comment on PR - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/pr_check_client_side_changes.yml b/.github/workflows/pr_check_client_side_changes.yml index c048bc3ca0..4b973ba392 100644 --- a/.github/workflows/pr_check_client_side_changes.yml +++ b/.github/workflows/pr_check_client_side_changes.yml @@ -16,7 +16,7 @@ jobs: if: github.repository == 'microsoft/playwright' steps: - name: Create GitHub issue - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} script: | diff --git a/.github/workflows/roll_browser_into_playwright.yml b/.github/workflows/roll_browser_into_playwright.yml index 69dba0804d..da90513160 100644 --- a/.github/workflows/roll_browser_into_playwright.yml +++ b/.github/workflows/roll_browser_into_playwright.yml @@ -38,7 +38,7 @@ jobs: git commit -m "feat(${{ github.event.client_payload.browser }}): roll to r${{ github.event.client_payload.revision }}" git push origin $BRANCH_NAME - name: Create Pull Request - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} script: | diff --git a/.github/workflows/roll_driver_nodejs.yml b/.github/workflows/roll_driver_nodejs.yml index 2019303d58..ee0d3d262c 100644 --- a/.github/workflows/roll_driver_nodejs.yml +++ b/.github/workflows/roll_driver_nodejs.yml @@ -35,7 +35,7 @@ jobs: git push origin $BRANCH_NAME - name: Create Pull Request if: ${{ steps.prepare-branch.outputs.HAS_CHANGES == '1' }} - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} script: | From 63fd28e038c41650cd288a4a2d790159c7e8c704 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Tue, 28 May 2024 19:30:47 +0200 Subject: [PATCH 09/15] docs(grep): contains tags (#31042) --- docs/src/test-api/class-testconfig.md | 2 +- docs/src/test-api/class-testproject.md | 2 +- packages/playwright/types/test.d.ts | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/src/test-api/class-testconfig.md b/docs/src/test-api/class-testconfig.md index fc21a4d9d9..85fbd3e86f 100644 --- a/docs/src/test-api/class-testconfig.md +++ b/docs/src/test-api/class-testconfig.md @@ -164,7 +164,7 @@ export default defineConfig({ * since: v1.10 - type: ?<[RegExp]|[Array]<[RegExp]>> -Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only run tests with "cart" in the title. Also available in the [command line](../test-cli.md) with the `-g` option. The regular expression will be tested against the string that consists of the test file name, `test.describe` name (if any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`. +Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only run tests with "cart" in the title. Also available in the [command line](../test-cli.md) with the `-g` option. The regular expression will be tested against the string that consists of the project name, the test file name, the `test.describe` name (if any), the test name and the test tags divided by spaces, e.g. `chromium my-test.spec.ts my-suite my-test`. `grep` option is also useful for [tagging tests](../test-annotations.md#tag-tests). diff --git a/docs/src/test-api/class-testproject.md b/docs/src/test-api/class-testproject.md index 562dc76e09..a15a836010 100644 --- a/docs/src/test-api/class-testproject.md +++ b/docs/src/test-api/class-testproject.md @@ -123,7 +123,7 @@ You can configure entire test project to concurrently run all tests in all files * since: v1.10 - type: ?<[RegExp]|[Array]<[RegExp]>> -Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only run tests with "cart" in the title. Also available globally and in the [command line](../test-cli.md) with the `-g` option. The regular expression will be tested against the string that consists of the test file name, `test.describe` name (if any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`. +Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only run tests with "cart" in the title. Also available globally and in the [command line](../test-cli.md) with the `-g` option. The regular expression will be tested against the string that consists of the project name, the test file name, the `test.describe` name (if any), the test name and the test tags divided by spaces, e.g. `chromium my-test.spec.ts my-suite my-test`. `grep` option is also useful for [tagging tests](../test-annotations.md#tag-tests). diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index a7c5c8a6a4..59ae5256b7 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -266,8 +266,9 @@ interface TestProject { /** * Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only * run tests with "cart" in the title. Also available globally and in the [command line](https://playwright.dev/docs/test-cli) with the `-g` - * option. The regular expression will be tested against the string that consists of the test file name, - * `test.describe` name (if any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`. + * option. The regular expression will be tested against the string that consists of the project name, the test file + * name, the `test.describe` name (if any), the test name and the test tags divided by spaces, e.g. `chromium + * my-test.spec.ts my-suite my-test`. * * `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). */ @@ -1130,8 +1131,9 @@ interface TestConfig { /** * Filter to only run tests with a title matching one of the patterns. For example, passing `grep: /cart/` should only * run tests with "cart" in the title. Also available in the [command line](https://playwright.dev/docs/test-cli) with the `-g` option. The - * regular expression will be tested against the string that consists of the test file name, `test.describe` name (if - * any) and the test name divided by spaces, e.g. `my-test.spec.ts my-suite my-test`. + * regular expression will be tested against the string that consists of the project name, the test file name, the + * `test.describe` name (if any), the test name and the test tags divided by spaces, e.g. `chromium my-test.spec.ts + * my-suite my-test`. * * `grep` option is also useful for [tagging tests](https://playwright.dev/docs/test-annotations#tag-tests). * From 67181c9f1193fd72a19ade4335f87bd2884ff474 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Tue, 28 May 2024 20:19:29 +0200 Subject: [PATCH 10/15] devops: have client side changes issue per Playwright version (#31052) This should address the issue which we had before of manually taking entries over into a new issue. Closes https://github.com/microsoft/playwright/pull/31027 --- .github/workflows/pr_check_client_side_changes.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr_check_client_side_changes.yml b/.github/workflows/pr_check_client_side_changes.yml index 4b973ba392..236da1cc88 100644 --- a/.github/workflows/pr_check_client_side_changes.yml +++ b/.github/workflows/pr_check_client_side_changes.yml @@ -15,11 +15,13 @@ jobs: runs-on: ubuntu-20.04 if: github.repository == 'microsoft/playwright' steps: + - uses: actions/checkout@v4 - name: Create GitHub issue uses: actions/github-script@v7 with: github-token: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }} script: | + const currentPlaywrightVersion = require('./package.json').version.match(/\d+\.\d+/)[0]; const { data } = await github.rest.git.getCommit({ owner: context.repo.owner, repo: context.repo.repo, @@ -27,10 +29,10 @@ jobs: }); const commitHeader = data.message.split('\n')[0]; - const title = '[Ports]: Backport client side changes'; + const title = '[Ports]: Backport client side changes for ' + currentPlaywrightVersion; for (const repo of ['playwright-python', 'playwright-java', 'playwright-dotnet']) { const { data: issuesData } = await github.rest.search.issuesAndPullRequests({ - q: `is:issue is:open repo:microsoft/${repo} in:title "${title}"` + q: `is:issue is:open repo:microsoft/${repo} in:title "${title}" author:playwrightmachine"` }) let issueNumber = null; let issueBody = ''; From e047c478a4943467cda926ff646e279f4bd01df0 Mon Sep 17 00:00:00 2001 From: Sander Date: Tue, 28 May 2024 21:29:52 +0200 Subject: [PATCH 11/15] feat(ct): resolve hooksConfig import refs (#31024) closes https://github.com/microsoft/playwright/issues/30453 --- packages/playwright-ct-core/src/mount.ts | 1 + packages/playwright-ct-core/types/component.d.ts | 9 ++------- packages/playwright-ct-react/hooks.d.ts | 6 ++---- packages/playwright-ct-react/index.d.ts | 5 ++--- packages/playwright-ct-react17/hooks.d.ts | 6 ++---- packages/playwright-ct-react17/index.d.ts | 5 ++--- packages/playwright-ct-solid/hooks.d.ts | 7 +++---- packages/playwright-ct-solid/index.d.ts | 5 ++--- packages/playwright-ct-svelte/hooks.d.ts | 5 ++--- packages/playwright-ct-svelte/index.d.ts | 5 ++--- packages/playwright-ct-vue/hooks.d.ts | 5 ++--- packages/playwright-ct-vue/index.d.ts | 9 ++++----- packages/playwright-ct-vue2/hooks.d.ts | 15 +++++++-------- packages/playwright-ct-vue2/index.d.ts | 9 ++++----- tests/components/ct-vue-vite/playwright/index.ts | 9 ++++++--- .../ct-vue-vite/tests/slots/slots.spec.js | 4 ++++ .../ct-vue-vite/tests/slots/slots.spec.ts | 4 ++++ 17 files changed, 51 insertions(+), 58 deletions(-) diff --git a/packages/playwright-ct-core/src/mount.ts b/packages/playwright-ct-core/src/mount.ts index 7220916a4b..e743a6aaa1 100644 --- a/packages/playwright-ct-core/src/mount.ts +++ b/packages/playwright-ct-core/src/mount.ts @@ -102,6 +102,7 @@ async function innerMount(page: Page, componentRef: JsxComponent | ImportRef, op const selector = await page.evaluate(async ({ component, hooksConfig }) => { component = await window.__pwUnwrapObject(component); + hooksConfig = await window.__pwUnwrapObject(hooksConfig); let rootElement = document.getElementById('root'); if (!rootElement) { rootElement = document.createElement('div'); diff --git a/packages/playwright-ct-core/types/component.d.ts b/packages/playwright-ct-core/types/component.d.ts index 5bd5d7e017..ed5c616bfa 100644 --- a/packages/playwright-ct-core/types/component.d.ts +++ b/packages/playwright-ct-core/types/component.d.ts @@ -14,11 +14,6 @@ * limitations under the License. */ -type JsonPrimitive = string | number | boolean | null; -type JsonValue = JsonPrimitive | JsonObject | JsonArray; -type JsonArray = JsonValue[]; -export type JsonObject = { [Key in string]?: JsonValue }; - export type JsxComponent = { __pw_type: 'jsx', type: any, @@ -47,10 +42,10 @@ declare global { playwrightMount(component: Component, rootElement: Element, hooksConfig?: any): Promise; playwrightUnmount(rootElement: Element): Promise; playwrightUpdate(rootElement: Element, component: Component): Promise; - __pw_hooks_before_mount?: (( + __pw_hooks_before_mount?: (( params: { hooksConfig?: HooksConfig; [key: string]: any } ) => Promise)[]; - __pw_hooks_after_mount?: (( + __pw_hooks_after_mount?: (( params: { hooksConfig?: HooksConfig; [key: string]: any } ) => Promise)[]; // Can't start with __pw due to core reuse bindings logic for __pw*. diff --git a/packages/playwright-ct-react/hooks.d.ts b/packages/playwright-ct-react/hooks.d.ts index 0fa7cf3e1a..1093f1a3a3 100644 --- a/packages/playwright-ct-react/hooks.d.ts +++ b/packages/playwright-ct-react/hooks.d.ts @@ -14,11 +14,9 @@ * limitations under the License. */ -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; - -export declare function beforeMount( +export declare function beforeMount( callback: (params: { hooksConfig?: HooksConfig; App: () => JSX.Element }) => Promise ): void; -export declare function afterMount( +export declare function afterMount( callback: (params: { hooksConfig?: HooksConfig }) => Promise ): void; diff --git a/packages/playwright-ct-react/index.d.ts b/packages/playwright-ct-react/index.d.ts index 7cfcf04ba0..c086d4bec5 100644 --- a/packages/playwright-ct-react/index.d.ts +++ b/packages/playwright-ct-react/index.d.ts @@ -15,10 +15,9 @@ */ import type { Locator } from 'playwright/test'; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; import type { TestType } from '@playwright/experimental-ct-core'; -export interface MountOptions { +export interface MountOptions { hooksConfig?: HooksConfig; } @@ -28,7 +27,7 @@ export interface MountResult extends Locator { } export const test: TestType<{ - mount( + mount( component: JSX.Element, options?: MountOptions ): Promise; diff --git a/packages/playwright-ct-react17/hooks.d.ts b/packages/playwright-ct-react17/hooks.d.ts index 0fa7cf3e1a..1093f1a3a3 100644 --- a/packages/playwright-ct-react17/hooks.d.ts +++ b/packages/playwright-ct-react17/hooks.d.ts @@ -14,11 +14,9 @@ * limitations under the License. */ -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; - -export declare function beforeMount( +export declare function beforeMount( callback: (params: { hooksConfig?: HooksConfig; App: () => JSX.Element }) => Promise ): void; -export declare function afterMount( +export declare function afterMount( callback: (params: { hooksConfig?: HooksConfig }) => Promise ): void; diff --git a/packages/playwright-ct-react17/index.d.ts b/packages/playwright-ct-react17/index.d.ts index 7cfcf04ba0..c086d4bec5 100644 --- a/packages/playwright-ct-react17/index.d.ts +++ b/packages/playwright-ct-react17/index.d.ts @@ -15,10 +15,9 @@ */ import type { Locator } from 'playwright/test'; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; import type { TestType } from '@playwright/experimental-ct-core'; -export interface MountOptions { +export interface MountOptions { hooksConfig?: HooksConfig; } @@ -28,7 +27,7 @@ export interface MountResult extends Locator { } export const test: TestType<{ - mount( + mount( component: JSX.Element, options?: MountOptions ): Promise; diff --git a/packages/playwright-ct-solid/hooks.d.ts b/packages/playwright-ct-solid/hooks.d.ts index 38d483ec6d..097c8cf11f 100644 --- a/packages/playwright-ct-solid/hooks.d.ts +++ b/packages/playwright-ct-solid/hooks.d.ts @@ -14,12 +14,11 @@ * limitations under the License. */ -import { JSXElement } from "solid-js"; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; +import { JSXElement } from 'solid-js'; -export declare function beforeMount( +export declare function beforeMount( callback: (params: { hooksConfig?: HooksConfig, App: () => JSXElement }) => Promise ): void; -export declare function afterMount( +export declare function afterMount( callback: (params: { hooksConfig?: HooksConfig }) => Promise ): void; diff --git a/packages/playwright-ct-solid/index.d.ts b/packages/playwright-ct-solid/index.d.ts index 7cfcf04ba0..c086d4bec5 100644 --- a/packages/playwright-ct-solid/index.d.ts +++ b/packages/playwright-ct-solid/index.d.ts @@ -15,10 +15,9 @@ */ import type { Locator } from 'playwright/test'; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; import type { TestType } from '@playwright/experimental-ct-core'; -export interface MountOptions { +export interface MountOptions { hooksConfig?: HooksConfig; } @@ -28,7 +27,7 @@ export interface MountResult extends Locator { } export const test: TestType<{ - mount( + mount( component: JSX.Element, options?: MountOptions ): Promise; diff --git a/packages/playwright-ct-svelte/hooks.d.ts b/packages/playwright-ct-svelte/hooks.d.ts index 03f801c338..dfa037c7de 100644 --- a/packages/playwright-ct-svelte/hooks.d.ts +++ b/packages/playwright-ct-svelte/hooks.d.ts @@ -15,15 +15,14 @@ */ import type { ComponentConstructorOptions, SvelteComponent } from 'svelte'; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; -export declare function beforeMount( +export declare function beforeMount( callback: (params: { hooksConfig?: HooksConfig, App: new (options: Partial) => SvelteComponent }) => Promise ): void; -export declare function afterMount( +export declare function afterMount( callback: (params: { hooksConfig?: HooksConfig; svelteComponent: SvelteComponent; diff --git a/packages/playwright-ct-svelte/index.d.ts b/packages/playwright-ct-svelte/index.d.ts index bd1ddd5b36..eb6d464032 100644 --- a/packages/playwright-ct-svelte/index.d.ts +++ b/packages/playwright-ct-svelte/index.d.ts @@ -15,7 +15,6 @@ */ import type { Locator } from 'playwright/test'; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; import type { SvelteComponent, ComponentProps } from 'svelte/types/runtime'; import type { TestType } from '@playwright/experimental-ct-core'; @@ -23,7 +22,7 @@ type ComponentSlot = string | string[]; type ComponentSlots = Record & { default?: ComponentSlot }; type ComponentEvents = Record; -export interface MountOptions { +export interface MountOptions { props?: ComponentProps; slots?: ComponentSlots; on?: ComponentEvents; @@ -39,7 +38,7 @@ export interface MountResult extends Locator } export const test: TestType<{ - mount( + mount( component: new (...args: any[]) => Component, options?: MountOptions ): Promise>; diff --git a/packages/playwright-ct-vue/hooks.d.ts b/packages/playwright-ct-vue/hooks.d.ts index 2a18496007..69b91cc2cb 100644 --- a/packages/playwright-ct-vue/hooks.d.ts +++ b/packages/playwright-ct-vue/hooks.d.ts @@ -15,12 +15,11 @@ */ import type { App, ComponentPublicInstance } from 'vue'; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; -export declare function beforeMount( +export declare function beforeMount( callback: (params: { app: App; hooksConfig?: HooksConfig }) => Promise ): void; -export declare function afterMount( +export declare function afterMount( callback: (params: { app: App; hooksConfig?: HooksConfig; diff --git a/packages/playwright-ct-vue/index.d.ts b/packages/playwright-ct-vue/index.d.ts index 308e47c18c..f755a6bcf3 100644 --- a/packages/playwright-ct-vue/index.d.ts +++ b/packages/playwright-ct-vue/index.d.ts @@ -15,7 +15,6 @@ */ import type { Locator } from 'playwright/test'; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; import type { TestType } from '@playwright/experimental-ct-core'; type ComponentSlot = string | string[]; @@ -29,14 +28,14 @@ type ComponentProps = T extends (props: infer P, ...args: any) => any ? P : {}; -export interface MountOptions { +export interface MountOptions { props?: ComponentProps; slots?: ComponentSlots; on?: ComponentEvents; hooksConfig?: HooksConfig; } -export interface MountOptionsJsx { +export interface MountOptionsJsx { hooksConfig?: HooksConfig; } @@ -55,11 +54,11 @@ export interface MountResultJsx extends Locator { } export const test: TestType<{ - mount( + mount( component: JSX.Element, options: MountOptionsJsx ): Promise; - mount( + mount( component: Component, options?: MountOptions ): Promise>; diff --git a/packages/playwright-ct-vue2/hooks.d.ts b/packages/playwright-ct-vue2/hooks.d.ts index 4c3a391117..5009f44348 100644 --- a/packages/playwright-ct-vue2/hooks.d.ts +++ b/packages/playwright-ct-vue2/hooks.d.ts @@ -14,17 +14,16 @@ * limitations under the License. */ -import { ComponentOptions } from 'vue'; -import { CombinedVueInstance, Vue, VueConstructor } from 'vue/types/vue'; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; +import type { ComponentOptions } from 'vue'; +import type { CombinedVueInstance, Vue, VueConstructor } from 'vue/types/vue'; -export declare function beforeMount( - callback: (params: { - hooksConfig?: HooksConfig, - Vue: VueConstructor, +export declare function beforeMount( + callback: (params: { + hooksConfig?: HooksConfig, + Vue: VueConstructor, }) => Promise & Record> ): void; -export declare function afterMount( +export declare function afterMount( callback: (params: { hooksConfig?: HooksConfig; instance: CombinedVueInstance< diff --git a/packages/playwright-ct-vue2/index.d.ts b/packages/playwright-ct-vue2/index.d.ts index f76285fb8f..b4fd75e395 100644 --- a/packages/playwright-ct-vue2/index.d.ts +++ b/packages/playwright-ct-vue2/index.d.ts @@ -15,7 +15,6 @@ */ import type { Locator } from 'playwright/test'; -import type { JsonObject } from '@playwright/experimental-ct-core/types/component'; import type { TestType } from '@playwright/experimental-ct-core'; type Slot = string | string[]; @@ -29,14 +28,14 @@ type ComponentProps = T extends (props: infer P, ...args: any) => any ? P : {}; -export interface MountOptions { +export interface MountOptions { props?: ComponentProps; slots?: ComponentSlots; on?: ComponentEvents; hooksConfig?: HooksConfig; } -export interface MountOptionsJsx { +export interface MountOptionsJsx { hooksConfig?: HooksConfig; } @@ -55,11 +54,11 @@ export interface MountResultJsx extends Locator { } export const test: TestType<{ - mount( + mount( component: JSX.Element, options?: MountOptionsJsx ): Promise; - mount( + mount( component: Component, options?: MountOptions ): Promise>; diff --git a/tests/components/ct-vue-vite/playwright/index.ts b/tests/components/ct-vue-vite/playwright/index.ts index 977ee33845..f23ab5a90a 100644 --- a/tests/components/ct-vue-vite/playwright/index.ts +++ b/tests/components/ct-vue-vite/playwright/index.ts @@ -4,14 +4,17 @@ import Button from '../src/components/Button.vue'; import '../src/assets/index.css'; export type HooksConfig = { - route?: string; routing?: boolean; + components?: Record; } beforeMount(async ({ app, hooksConfig }) => { - if (hooksConfig?.routing) + if (hooksConfig?.routing) app.use(router as any); // TODO: remove any and fix the various installed conflicting Vue versions - app.component('Button', Button); + + for (const [name, component] of Object.entries(hooksConfig?.components || {})) + app.component(name, component); + console.log(`Before mount: ${JSON.stringify(hooksConfig)}, app: ${!!app}`); }); diff --git a/tests/components/ct-vue-vite/tests/slots/slots.spec.js b/tests/components/ct-vue-vite/tests/slots/slots.spec.js index 2af38036b5..a33c9dac92 100644 --- a/tests/components/ct-vue-vite/tests/slots/slots.spec.js +++ b/tests/components/ct-vue-vite/tests/slots/slots.spec.js @@ -1,6 +1,7 @@ import { test, expect } from '@playwright/experimental-ct-vue'; import DefaultSlot from '@/components/DefaultSlot.vue'; import NamedSlots from '@/components/NamedSlots.vue'; +import Button from '@/components/Button.vue'; test('render a default slot', async ({ mount }) => { const component = await mount(DefaultSlot, { @@ -16,6 +17,9 @@ test('render a component as slot', async ({ mount }) => { slots: { default: '