diff --git a/packages/playwright-cloudflare/examples/todomvc/src/index.ts b/packages/playwright-cloudflare/examples/todomvc/src/index.ts index acf701df5..47a9c700c 100644 --- a/packages/playwright-cloudflare/examples/todomvc/src/index.ts +++ b/packages/playwright-cloudflare/examples/todomvc/src/index.ts @@ -1,6 +1,7 @@ import type { Fetcher } from '@cloudflare/workers-types'; -import { launch, fs } from "@cloudflare/playwright"; +import { launch } from "@cloudflare/playwright"; import { expect } from "@cloudflare/playwright/test"; +import fs from "@cloudflare/playwright/fs"; interface Env { MYBROWSER: Fetcher; diff --git a/packages/playwright-cloudflare/fs.d.ts b/packages/playwright-cloudflare/fs.d.ts new file mode 100644 index 000000000..b301bda0b --- /dev/null +++ b/packages/playwright-cloudflare/fs.d.ts @@ -0,0 +1 @@ +export * from 'fs'; diff --git a/packages/playwright-cloudflare/index.d.ts b/packages/playwright-cloudflare/index.d.ts index 5e9f4d08f..35f8ddd97 100644 --- a/packages/playwright-cloudflare/index.d.ts +++ b/packages/playwright-cloudflare/index.d.ts @@ -3,8 +3,6 @@ import { Playwright, Browser } from './types/types'; export * from './types/types'; -export const fs: typeof FS; - /** * @public */ diff --git a/packages/playwright-cloudflare/package.json b/packages/playwright-cloudflare/package.json index 9621dd982..0355e7b70 100644 --- a/packages/playwright-cloudflare/package.json +++ b/packages/playwright-cloudflare/package.json @@ -25,7 +25,18 @@ "import": "./lib/esm/internal.js", "require": "./lib/cjs/internal.js", "default": "./lib/esm/internal.js" - } + }, + "./fs": { + "types": "./fs.d.ts", + "import": "./lib/esm/bundles/fs.js", + "require": "./lib/cjs/bundles/fs.js", + "default": "./lib/esm/bundles/fs.js" + }, + "./lib/*": { + "import": "./lib/esm/playwright-core/src/*.js", + "require": "./lib/cjs/playwright-core/src/*.js", + "default": "./lib/esm/playwright-core/src/*.js" + } }, "scripts": { "generate-injected:core": "cd ../.. && node ./utils/generate_injected.js", diff --git a/packages/playwright-cloudflare/src/index.ts b/packages/playwright-cloudflare/src/index.ts index 48e7b7f83..e75bab977 100644 --- a/packages/playwright-cloudflare/src/index.ts +++ b/packages/playwright-cloudflare/src/index.ts @@ -1,5 +1,4 @@ import './patch'; -import fs from 'fs'; import { createInProcessPlaywright } from 'playwright-core/lib/inProcessFactory'; @@ -11,8 +10,6 @@ import { wrapClientApis } from './cloudflare/wrapClientApis'; import { kBrowserCloseMessageId } from 'playwright-core/lib/server/chromium/crConnection'; import { isUnderTest } from 'playwright-core/lib/utils'; -export { fs }; - const playwright = createInProcessPlaywright(); wrapClientApis(); diff --git a/packages/playwright-cloudflare/tests/src/browser-rendering/api.spec.ts b/packages/playwright-cloudflare/tests/src/browser-rendering/api.spec.ts index 066706304..f7f8eb344 100644 --- a/packages/playwright-cloudflare/tests/src/browser-rendering/api.spec.ts +++ b/packages/playwright-cloudflare/tests/src/browser-rendering/api.spec.ts @@ -1,9 +1,6 @@ -import { setCurrentTestFile } from '@cloudflare/playwright/internal'; import { test, expect } from '../workerFixtures'; import { launch, connect, sessions, BrowserWorker, Browser, history, acquire } from '@cloudflare/playwright'; -setCurrentTestFile("browser-rendering/api.spec.ts"); - async function launchAndGetSession(endpoint: BrowserWorker): Promise<[Browser, string]> { const browser = await launch(endpoint); const sessionId = (browser as any).__sessionIdForTest; @@ -55,5 +52,3 @@ test(`should add new session to history when launching browser`, async ({ env }) await launchedBrowse.close(); }); - -setCurrentTestFile(undefined); diff --git a/packages/playwright-cloudflare/tests/src/tests.ts b/packages/playwright-cloudflare/tests/src/tests.ts index 72513dc27..5888f543c 100644 --- a/packages/playwright-cloudflare/tests/src/tests.ts +++ b/packages/playwright-cloudflare/tests/src/tests.ts @@ -1,129 +1,129 @@ -import './browser-rendering/api.spec.ts'; +import '@cloudflareTests/browser-rendering/api.spec'; -import '../workerTests/page/elementhandle-bounding-box.spec.ts'; -import '../workerTests/page/elementhandle-click.spec.ts'; -import '../workerTests/page/elementhandle-content-frame.spec.ts'; -import '../workerTests/page/elementhandle-convenience.spec.ts'; -import '../workerTests/page/elementhandle-eval-on-selector.spec.ts'; -import '../workerTests/page/elementhandle-misc.spec.ts'; -import '../workerTests/page/elementhandle-owner-frame.spec.ts'; -import '../workerTests/page/elementhandle-press.spec.ts'; -import '../workerTests/page/elementhandle-query-selector.spec.ts'; -import '../workerTests/page/elementhandle-screenshot.spec.ts'; -import '../workerTests/page/elementhandle-scroll-into-view.spec.ts'; -import '../workerTests/page/elementhandle-select-text.spec.ts'; -import '../workerTests/page/elementhandle-type.spec.ts'; -import '../workerTests/page/elementhandle-wait-for-element-state.spec.ts'; -import '../workerTests/page/eval-on-selector-all.spec.ts'; -import '../workerTests/page/eval-on-selector.spec.ts'; -import '../workerTests/page/expect-boolean.spec.ts'; -import '../workerTests/page/expect-matcher-result.spec.ts'; -import '../workerTests/page/expect-misc.spec.ts'; -import '../workerTests/page/expect-timeout.spec.ts'; -import '../workerTests/page/expect-to-have-text.spec.ts'; -import '../workerTests/page/expect-to-have-value.spec.ts'; -import '../workerTests/page/frame-evaluate.spec.ts'; -import '../workerTests/page/frame-frame-element.spec.ts'; -import '../workerTests/page/frame-goto.spec.ts'; -import '../workerTests/page/frame-hierarchy.spec.ts'; -// import '../workerTests/page/interception.spec.ts'; -import '../workerTests/page/jshandle-as-element.spec.ts'; -import '../workerTests/page/jshandle-evaluate.spec.ts'; -import '../workerTests/page/jshandle-json-value.spec.ts'; -import '../workerTests/page/jshandle-properties.spec.ts'; -import '../workerTests/page/jshandle-to-string.spec.ts'; -import '../workerTests/page/locator-click.spec.ts'; -import '../workerTests/page/locator-convenience.spec.ts'; -import '../workerTests/page/locator-element-handle.spec.ts'; -import '../workerTests/page/locator-evaluate.spec.ts'; -import '../workerTests/page/locator-frame.spec.ts'; -import '../workerTests/page/locator-highlight.spec.ts'; -import '../workerTests/page/locator-is-visible.spec.ts'; -import '../workerTests/page/locator-list.spec.ts'; -import '../workerTests/page/locator-misc-1.spec.ts'; -import '../workerTests/page/locator-misc-2.spec.ts'; -import '../workerTests/page/locator-query.spec.ts'; -import '../workerTests/page/matchers.misc.spec.ts'; -import '../workerTests/page/network-post-data.spec.ts'; -import '../workerTests/page/page-accessibility.spec.ts'; -import '../workerTests/page/page-add-init-script.spec.ts'; -import '../workerTests/page/page-add-locator-handler.spec.ts'; -import '../workerTests/page/page-add-script-tag.spec.ts'; -import '../workerTests/page/page-add-style-tag.spec.ts'; -import '../workerTests/page/page-autowaiting-basic.spec.ts'; -import '../workerTests/page/page-autowaiting-no-hang.spec.ts'; -import '../workerTests/page/page-basic.spec.ts'; -import '../workerTests/page/page-check.spec.ts'; -import '../workerTests/page/page-click-during-navigation.spec.ts'; -import '../workerTests/page/page-click-react.spec.ts'; -import '../workerTests/page/page-click-scroll.spec.ts'; -import '../workerTests/page/page-click-timeout-1.spec.ts'; -import '../workerTests/page/page-click-timeout-2.spec.ts'; -import '../workerTests/page/page-click-timeout-3.spec.ts'; -import '../workerTests/page/page-click-timeout-4.spec.ts'; -import '../workerTests/page/page-click.spec.ts'; -import '../workerTests/page/page-close.spec.ts'; -import '../workerTests/page/page-dialog.spec.ts'; -import '../workerTests/page/page-dispatchevent.spec.ts'; -import '../workerTests/page/page-drag.spec.ts'; -import '../workerTests/page/page-emulate-media.spec.ts'; -import '../workerTests/page/page-evaluate-handle.spec.ts'; -import '../workerTests/page/page-evaluate-no-stall.spec.ts'; -import '../workerTests/page/page-evaluate.spec.ts'; -import '../workerTests/page/page-event-console.spec.ts'; -import '../workerTests/page/page-event-load.spec.ts'; -import '../workerTests/page/page-event-network.spec.ts'; -import '../workerTests/page/page-event-pageerror.spec.ts'; -import '../workerTests/page/page-event-popup.spec.ts'; -import '../workerTests/page/page-event-request.spec.ts'; -import '../workerTests/page/page-expose-function.spec.ts'; -import '../workerTests/page/page-fill.spec.ts'; -import '../workerTests/page/page-focus.spec.ts'; -import '../workerTests/page/page-goto.spec.ts'; -import '../workerTests/page/page-history.spec.ts'; -import '../workerTests/page/page-keyboard.spec.ts'; -// import '../workerTests/page/page-leaks.spec.ts'; -import '../workerTests/page/page-mouse.spec.ts'; -import '../workerTests/page/page-navigation.spec.ts'; -import '../workerTests/page/page-network-idle.spec.ts'; -import '../workerTests/page/page-network-request.spec.ts'; -import '../workerTests/page/page-network-response.spec.ts'; -import '../workerTests/page/page-network-sizes.spec.ts'; -import '../workerTests/page/page-object-count.spec.ts'; -import '../workerTests/page/page-request-continue.spec.ts'; -import '../workerTests/page/page-request-fallback.spec.ts'; -import '../workerTests/page/page-request-fulfill.spec.ts'; -import '../workerTests/page/page-request-intercept.spec.ts'; -import '../workerTests/page/page-route.spec.ts'; -// import '../workerTests/page/page-screenshot.spec.ts'; -import '../workerTests/page/page-select-option.spec.ts'; -import '../workerTests/page/page-set-content.spec.ts'; -import '../workerTests/page/page-set-extra-http-headers.spec.ts'; -// import '../workerTests/page/page-set-input-files.spec.ts'; -import '../workerTests/page/page-strict.spec.ts'; -import '../workerTests/page/page-wait-for-function.spec.ts'; -import '../workerTests/page/page-wait-for-load-state.spec.ts'; -import '../workerTests/page/page-wait-for-navigation.spec.ts'; -import '../workerTests/page/page-wait-for-request.spec.ts'; -import '../workerTests/page/page-wait-for-response.spec.ts'; -import '../workerTests/page/page-wait-for-selector-1.spec.ts'; -import '../workerTests/page/page-wait-for-selector-2.spec.ts'; -import '../workerTests/page/page-wait-for-url.spec.ts'; -import '../workerTests/page/queryselector.spec.ts'; -import '../workerTests/page/retarget.spec.ts'; -import '../workerTests/page/selectors-css.spec.ts'; -import '../workerTests/page/selectors-frame.spec.ts'; -import '../workerTests/page/selectors-get-by.spec.ts'; -import '../workerTests/page/selectors-misc.spec.ts'; -import '../workerTests/page/selectors-react.spec.ts'; -import '../workerTests/page/selectors-register.spec.ts'; -import '../workerTests/page/selectors-role.spec.ts'; -import '../workerTests/page/selectors-text.spec.ts'; -import '../workerTests/page/selectors-vue.spec.ts'; -import '../workerTests/page/wheel.spec.ts'; -import '../workerTests/page/workers.spec.ts'; +import '@workerTests/page/elementhandle-bounding-box.spec'; +import '@workerTests/page/elementhandle-click.spec'; +import '@workerTests/page/elementhandle-content-frame.spec'; +import '@workerTests/page/elementhandle-convenience.spec'; +import '@workerTests/page/elementhandle-eval-on-selector.spec'; +import '@workerTests/page/elementhandle-misc.spec'; +import '@workerTests/page/elementhandle-owner-frame.spec'; +import '@workerTests/page/elementhandle-press.spec'; +import '@workerTests/page/elementhandle-query-selector.spec'; +import '@workerTests/page/elementhandle-screenshot.spec'; +import '@workerTests/page/elementhandle-scroll-into-view.spec'; +import '@workerTests/page/elementhandle-select-text.spec'; +import '@workerTests/page/elementhandle-type.spec'; +import '@workerTests/page/elementhandle-wait-for-element-state.spec'; +import '@workerTests/page/eval-on-selector-all.spec'; +import '@workerTests/page/eval-on-selector.spec'; +import '@workerTests/page/expect-boolean.spec'; +import '@workerTests/page/expect-matcher-result.spec'; +import '@workerTests/page/expect-misc.spec'; +import '@workerTests/page/expect-timeout.spec'; +import '@workerTests/page/expect-to-have-text.spec'; +import '@workerTests/page/expect-to-have-value.spec'; +import '@workerTests/page/frame-evaluate.spec'; +import '@workerTests/page/frame-frame-element.spec'; +import '@workerTests/page/frame-goto.spec'; +import '@workerTests/page/frame-hierarchy.spec'; +// import '@workerTests/page/interception.spec'; +import '@workerTests/page/jshandle-as-element.spec'; +import '@workerTests/page/jshandle-evaluate.spec'; +import '@workerTests/page/jshandle-json-value.spec'; +import '@workerTests/page/jshandle-properties.spec'; +import '@workerTests/page/jshandle-to-string.spec'; +import '@workerTests/page/locator-click.spec'; +import '@workerTests/page/locator-convenience.spec'; +import '@workerTests/page/locator-element-handle.spec'; +import '@workerTests/page/locator-evaluate.spec'; +import '@workerTests/page/locator-frame.spec'; +import '@workerTests/page/locator-highlight.spec'; +import '@workerTests/page/locator-is-visible.spec'; +import '@workerTests/page/locator-list.spec'; +import '@workerTests/page/locator-misc-1.spec'; +import '@workerTests/page/locator-misc-2.spec'; +import '@workerTests/page/locator-query.spec'; +import '@workerTests/page/matchers.misc.spec'; +import '@workerTests/page/network-post-data.spec'; +import '@workerTests/page/page-accessibility.spec'; +import '@workerTests/page/page-add-init-script.spec'; +import '@workerTests/page/page-add-locator-handler.spec'; +import '@workerTests/page/page-add-script-tag.spec'; +import '@workerTests/page/page-add-style-tag.spec'; +import '@workerTests/page/page-autowaiting-basic.spec'; +import '@workerTests/page/page-autowaiting-no-hang.spec'; +import '@workerTests/page/page-basic.spec'; +import '@workerTests/page/page-check.spec'; +import '@workerTests/page/page-click-during-navigation.spec'; +import '@workerTests/page/page-click-react.spec'; +import '@workerTests/page/page-click-scroll.spec'; +import '@workerTests/page/page-click-timeout-1.spec'; +import '@workerTests/page/page-click-timeout-2.spec'; +import '@workerTests/page/page-click-timeout-3.spec'; +import '@workerTests/page/page-click-timeout-4.spec'; +import '@workerTests/page/page-click.spec'; +import '@workerTests/page/page-close.spec'; +import '@workerTests/page/page-dialog.spec'; +import '@workerTests/page/page-dispatchevent.spec'; +import '@workerTests/page/page-drag.spec'; +import '@workerTests/page/page-emulate-media.spec'; +import '@workerTests/page/page-evaluate-handle.spec'; +import '@workerTests/page/page-evaluate-no-stall.spec'; +import '@workerTests/page/page-evaluate.spec'; +import '@workerTests/page/page-event-console.spec'; +import '@workerTests/page/page-event-load.spec'; +import '@workerTests/page/page-event-network.spec'; +import '@workerTests/page/page-event-pageerror.spec'; +import '@workerTests/page/page-event-popup.spec'; +import '@workerTests/page/page-event-request.spec'; +import '@workerTests/page/page-expose-function.spec'; +import '@workerTests/page/page-fill.spec'; +import '@workerTests/page/page-focus.spec'; +import '@workerTests/page/page-goto.spec'; +import '@workerTests/page/page-history.spec'; +import '@workerTests/page/page-keyboard.spec'; +// import '@workerTests/page/page-leaks.spec'; +import '@workerTests/page/page-mouse.spec'; +import '@workerTests/page/page-navigation.spec'; +import '@workerTests/page/page-network-idle.spec'; +import '@workerTests/page/page-network-request.spec'; +import '@workerTests/page/page-network-response.spec'; +import '@workerTests/page/page-network-sizes.spec'; +import '@workerTests/page/page-object-count.spec'; +import '@workerTests/page/page-request-continue.spec'; +import '@workerTests/page/page-request-fallback.spec'; +import '@workerTests/page/page-request-fulfill.spec'; +import '@workerTests/page/page-request-intercept.spec'; +import '@workerTests/page/page-route.spec'; +// import '@workerTests/page/page-screenshot.spec'; +import '@workerTests/page/page-select-option.spec'; +import '@workerTests/page/page-set-content.spec'; +import '@workerTests/page/page-set-extra-http-headers.spec'; +// import '@workerTests/page/page-set-input-files.spec'; +import '@workerTests/page/page-strict.spec'; +import '@workerTests/page/page-wait-for-function.spec'; +import '@workerTests/page/page-wait-for-load-state.spec'; +import '@workerTests/page/page-wait-for-navigation.spec'; +import '@workerTests/page/page-wait-for-request.spec'; +import '@workerTests/page/page-wait-for-response.spec'; +import '@workerTests/page/page-wait-for-selector-1.spec'; +import '@workerTests/page/page-wait-for-selector-2.spec'; +import '@workerTests/page/page-wait-for-url.spec'; +import '@workerTests/page/queryselector.spec'; +import '@workerTests/page/retarget.spec'; +import '@workerTests/page/selectors-css.spec'; +import '@workerTests/page/selectors-frame.spec'; +import '@workerTests/page/selectors-get-by.spec'; +import '@workerTests/page/selectors-misc.spec'; +import '@workerTests/page/selectors-react.spec'; +import '@workerTests/page/selectors-register.spec'; +import '@workerTests/page/selectors-role.spec'; +import '@workerTests/page/selectors-text.spec'; +import '@workerTests/page/selectors-vue.spec'; +import '@workerTests/page/wheel.spec'; +import '@workerTests/page/workers.spec'; -import '../workerTests/library/browsercontext-pages.spec.ts'; +import '@workerTests/library/browsercontext-pages.spec'; export const skipTests: string[][] = [ ["page/elementhandle-screenshot.spec.ts", "element screenshot", "path option should create subdirectories"], // Error: Error: [unenv] fs.readFile is not implemented yet! diff --git a/packages/playwright-cloudflare/tests/src/testsServer.ts b/packages/playwright-cloudflare/tests/src/testsServer.ts index 831b90a10..75f944623 100644 --- a/packages/playwright-cloudflare/tests/src/testsServer.ts +++ b/packages/playwright-cloudflare/tests/src/testsServer.ts @@ -1,7 +1,7 @@ import { connect, sessions, limits, acquire } from '@cloudflare/playwright'; import { testSuites, TestRunner, setUnderTest } from '@cloudflare/playwright/internal'; -import { setAssetsUrl, setCurrentBrowser, setCurrentEnv } from './workerFixtures'; +import { setCurrentContext } from './workerFixtures'; import { skipTests } from './tests'; @@ -21,7 +21,7 @@ const skipTestsFullTitles = new Set(skipTests.map(t => t.join(' > '))); setUnderTest(true); export default { - + async fetch(request: Request, env: Env): Promise { const url = new URL(request.url); const timeout = url.searchParams.has('timeout') ? parseInt(url.searchParams.get('timeout')!, 10) * 1000 : 10_000; @@ -29,24 +29,23 @@ export default { const file = url.pathname.substring(1); const upgradeHeader = request.headers.get('Upgrade'); - + if (upgradeHeader !== 'websocket') { const suites = await testSuites(); const response = file ? suites.find(s => s.file === file) : suites; return response ? Response.json(response) : new Response('Not found', { status: 404 }); } - + const webSocketPair = new WebSocketPair(); const [client, server] = Object.values(webSocketPair); server.accept(); - - setCurrentEnv(env); const browser = await connectBrowser(env, sessionId); - setCurrentBrowser(browser); // we need to run browser rendering in dev remote mode, // so URL will ne a public one which is what we need - setAssetsUrl(url.origin); + const assetsUrl = url.origin; + + setCurrentContext({ env, browser, assetsUrl }); const testRunner = new TestRunner({ timeout }); @@ -60,14 +59,14 @@ export default { } console.log(`🧪 Running ${fullTitle}`); - + testRunner.runTest(file, testId) .then(result => send(server, result)) .catch(e => server.close(1011, e.message)); }); server.addEventListener('close', () => { browser.close().catch(e => console.error(e)); - setCurrentBrowser(undefined); + setCurrentContext(undefined); }); return new Response(null, { diff --git a/packages/playwright-cloudflare/tests/src/workerFixtures.ts b/packages/playwright-cloudflare/tests/src/workerFixtures.ts index 152d15c24..193e68aca 100644 --- a/packages/playwright-cloudflare/tests/src/workerFixtures.ts +++ b/packages/playwright-cloudflare/tests/src/workerFixtures.ts @@ -1,7 +1,7 @@ import type { Browser, BrowserType, BrowserContext, Page, Frame, PageScreenshotOptions, ViewportSize } from "@cloudflare/playwright/test"; import type { BrowserContextOptions, ScreenshotMode, VideoMode } from "../../types/test"; import { expect } from "@cloudflare/playwright/test"; -import { _baseTest, debug } from "@cloudflare/playwright/internal"; +import { _baseTest } from "@cloudflare/playwright/internal"; import playwright from "@cloudflare/playwright"; export { expect } from '@cloudflare/playwright/test'; @@ -86,19 +86,21 @@ export type TestModeTestFixtures = { toImpl: (rpcObject?: any) => any; }; -let env: Env | undefined = undefined; -export function setCurrentEnv(e?: Env) { - env = e; +export type Context = { + env: Env; + browser: Browser; + assetsUrl: string; } -let browser: Browser | undefined = undefined; -export function setCurrentBrowser(b?: Browser) { - browser = b; +export function setCurrentContext(context?: Context) { + (global as any)['__TEST_GLOBALS'] = context; } -let assetsUrl: string | undefined; -export function setAssetsUrl(url: string) { - assetsUrl = url; +export function currentContext() { + const context = (global as any)['__TEST_GLOBALS']; + if (!context) + throw new Error('Context not initialized'); + return context; } export const test = platformTest.extend({ @@ -110,9 +112,7 @@ export const test = platformTest.extend { - if (!env) - throw new Error('Env not initialized'); - await run(env); + await run(currentContext().env); }, { scope: 'worker' }], browserVersion: [async ({ browser }, run) => { @@ -127,7 +127,7 @@ export const test = platformTest.extend { await run(playwright[browserName]); }, { scope: 'worker' }], @@ -135,9 +135,7 @@ export const test = platformTest.extend run(playwright), { scope: 'worker' }], browser: [async ({}, run) => { - if (!browser) - throw new Error('Browser not initialized'); - await run(browser); + await run(currentContext().browser); }, { scope: 'worker' }], context: async ({ contextFactory }, run) => { @@ -151,8 +149,7 @@ export const test = platformTest.extend { - if (!assetsUrl) - throw new Error('Assets URL not set'); + const assetsUrl = currentContext().assetsUrl; await run({ PREFIX: assetsUrl, @@ -196,61 +193,3 @@ export const test = platformTest.extend Number(e)); - const right: number[] = b.split('.').map(e => Number(e)); - for (let i = 0; i < 4; i++) { - if (left[i] > right[i]) - return false; - if (left[i] < right[i]) - return true; - } - return false; -} - -export const kTargetClosedErrorMessage = 'Target page, context or browser has been closed'; - -export async function attachFrame(page: Page, frameId: string, url: string): Promise { - const handle = await page.evaluateHandle(async ({ frameId, url }) => { - const frame = document.createElement('iframe'); - frame.src = url; - frame.id = frameId; - document.body.appendChild(frame); - await new Promise(x => frame.onload = x); - return frame; - }, { frameId, url }); - return handle.asElement().contentFrame() as Promise; -} - -export async function detachFrame(page: Page, frameId: string) { - await page.evaluate(frameId => { - document.getElementById(frameId)!.remove(); - }, frameId); -} - -export async function verifyViewport(page: Page, width: number, height: number) { - expect(page.viewportSize()!.width).toBe(width); - expect(page.viewportSize()!.height).toBe(height); - expect(await page.evaluate('window.innerWidth')).toBe(width); - expect(await page.evaluate('window.innerHeight')).toBe(height); -} - -const ansiRegex = new RegExp('[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', 'g'); -export function stripAnsi(str: string): string { - return str.replace(ansiRegex, ''); -} - -export function expectedSSLError(browserName: string, platform: string): RegExp { - if (browserName === 'chromium') - return /net::(ERR_CERT_AUTHORITY_INVALID|ERR_CERT_INVALID)/; - if (browserName === 'webkit') { - if (platform === 'darwin') - return /The certificate for this server is invalid/; - else if (platform === 'win32') - return /SSL peer certificate or SSH remote key was not OK/; - else - return /Unacceptable TLS certificate/; - } - return /SSL_ERROR_UNKNOWN/; -} diff --git a/packages/playwright-cloudflare/tests/tsconfig.json b/packages/playwright-cloudflare/tests/tsconfig.json index d062d06d2..2f81d7a56 100644 --- a/packages/playwright-cloudflare/tests/tsconfig.json +++ b/packages/playwright-cloudflare/tests/tsconfig.json @@ -10,6 +10,10 @@ "allowSyntheticDefaultImports": true, "allowImportingTsExtensions": true, "resolveJsonModule": true, + "paths": { + "@workerTests/*": ["./workerTests/*"], + "@cloudflareTests/*": ["./workerTests/packages/playwright-cloudflare/tests/src/*"], + }, "types": ["./worker-configuration.d.ts"] }, "include": ["./**/*.ts", "./**/*.d.ts"], diff --git a/packages/playwright-cloudflare/tests/vitest.config.ts b/packages/playwright-cloudflare/tests/vitest.config.ts index a2dcd3ef5..08cb85948 100644 --- a/packages/playwright-cloudflare/tests/vitest.config.ts +++ b/packages/playwright-cloudflare/tests/vitest.config.ts @@ -3,6 +3,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { include: ['./proxyTests/**/*.(spec|test).ts'], + isolate: false, hookTimeout: 30_000, testTimeout: 30_000, maxConcurrency: 1, @@ -10,4 +11,4 @@ export default defineConfig({ maxWorkers: 1, globalSetup: './src/globalSetup.ts', }, -}); \ No newline at end of file +}); diff --git a/packages/playwright-cloudflare/utils/generate_worker_tests.js b/packages/playwright-cloudflare/utils/generate_worker_tests.js index cd01f08c3..d4801ac1f 100644 --- a/packages/playwright-cloudflare/utils/generate_worker_tests.js +++ b/packages/playwright-cloudflare/utils/generate_worker_tests.js @@ -1,45 +1,142 @@ -import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; -import { deleteDir, writeFile } from "./utils.js"; +import { build } from "vite"; const basedir = path.dirname(fileURLToPath(import.meta.url)); const sourceTestsDir = path.join(basedir, '..', '..', '..', 'tests'); +const cloudflareSourceTestsDir = path.join(basedir, '..', 'tests', 'src'); const workerTestsDir = path.join(basedir, '..', 'tests', 'workerTests'); -const testExtendFiles = [ - 'config/browserTest.ts', - 'config/utils.ts', - 'config/errors.ts', - 'page/pageTest.ts', -]; - -const content = fs.readFileSync(path.join(basedir, '../tests/src/tests.ts'), { encoding: 'utf-8' }); -const testPaths = [...content.matchAll(/import\s+'\.\.\/workerTests\/(.+)';/g)].map(([, importFile]) => importFile) || []; - -// ensure workerTests directory is clean -deleteDir(workerTestsDir); - -for (const testPath of testPaths) { - const testFile = path.join(sourceTestsDir, testPath); - const targetTestFile = path.join(workerTestsDir, testPath); - const pathStr = JSON.stringify(testPath); - writeFile(targetTestFile, `import { setCurrentTestFile } from '@cloudflare/playwright/internal'; - -setCurrentTestFile(${pathStr}); +function setTestFilePlugin() { + return { + name: 'transform-file', + transform(src, id) { + let testPath = [sourceTestsDir, cloudflareSourceTestsDir].map(dir => path.relative(dir, id).replace(/\\/g, '/')) + .find(p => !p.startsWith('..')); + if (/\.(spec|test)\.ts$/.test(id)) { + return { + code: [ + `import { setCurrentTestFile } from '@cloudflare/playwright/internal';setCurrentTestFile(${JSON.stringify(testPath)});`, + src, + 'setCurrentTestFile(undefined);', + ].join('\n'), + map: null, // provide source map if available + } + } + }, + } +} -${fs.readFileSync(testFile, 'utf-8')}; +(async () => { + await build({ + plugins: [setTestFilePlugin()], + root: sourceTestsDir, + resolve: { + alias: { + // https://workers-nodejs-compat-matrix.pages.dev/ + 'async_hooks': 'node:async_hooks', + 'assert': 'node:assert', + 'buffer': 'node:buffer', + 'child_process': 'node:child_process', + 'constants': 'node:constants', + 'crypto': 'node:crypto', + 'dns': 'node:dns', + 'events': 'node:events', + 'http': 'node:http', + 'http2': 'node:http2', + 'https': 'node:https', + 'inspector': 'node:inspector', + 'module': 'node:module', + 'net': 'node:net', + 'os': 'node:os', + 'path': 'node:path', + 'process': 'node:process', + 'readline': 'node:readline', + 'stream': 'node:stream', + 'tls': 'node:tls', + 'url': 'node:url', + 'util': 'node:util', + 'vm': 'node:vm', + 'zlib': 'node:zlib', -setCurrentTestFile(undefined); -`); -} + '@workerTests': sourceTestsDir, + '@cloudflareTests': path.resolve(basedir, '../tests/src'), -for (const testExtendFile of testExtendFiles) { - const targetTestExtendFile = path.join(workerTestsDir, testExtendFile); - const fixturesFile = path.join(basedir, '../tests/src/workerFixtures.ts'); - const relativePath = path.relative(path.dirname(targetTestExtendFile), fixturesFile).replace(/\\/g, '/'); - writeFile(targetTestExtendFile, `export * from '${relativePath}';`); -} + '../config/browserTest': path.resolve(basedir, '../tests/src/workerFixtures'), + './pageTest': path.resolve(basedir, '../tests/src/workerFixtures'), + '../zipBundle': '@cloudflare/playwright/lib/zipBundle', + '../../packages/playwright-core/lib': path.resolve(basedir, '../../playwright-core/src'), + 'playwright-core': '@cloudflare/playwright', + '@playwright/test': '@cloudflare/playwright/test', + '@playwright/test': path.resolve(basedir, '../tests/src/workerFixtures'), + 'fs': '@cloudflare/playwright/fs', + }, + }, + build: { + emptyOutDir: true, + minify: false, + // prevents __defProp, __defNormalProp, __publicField in compiled code + target: 'esnext', + lib: { + name: 'tests', + entry: path.join(basedir, '../tests/src/tests.ts'), + formats: ['es'], + }, + terserOptions: { + format: { + // we need to ensure no comments are preserved + comments: false + } + }, + rollupOptions: { + output: { + preserveModules: true, + dir: workerTestsDir, + preserveModulesRoot: sourceTestsDir, + entryFileNames: '[name].js', + chunkFileNames: '[name].js', + }, + external: [ + 'node:async_hooks', + 'node:assert', + 'node:browser', + 'node:buffer', + 'node:child_process', + 'node:constants', + 'node:crypto', + 'node:dns', + 'node:events', + 'node:http', + 'node:http2', + 'node:https', + 'node:inspector', + 'node:module', + 'node:net', + 'node:os', + 'node:path', + 'node:process', + 'node:readline', + 'node:stream', + 'node:timers', + 'node:tls', + 'node:url', + 'node:util', + 'node:vm', + 'node:zlib', + /^@cloudflare\/playwright.*/, + ] + }, + commonjsOptions: { + transformMixedEsModules: true, + extensions: ['.ts', '.js'], + include: [ + path.resolve(basedir, '../../../tests/**/*'), + /node_modules/, + ], + }, + }, + }); +})();