diff --git a/docs/src/auth.md b/docs/src/auth.md index 31f821f88e..1f20edafe3 100644 --- a/docs/src/auth.md +++ b/docs/src/auth.md @@ -193,11 +193,11 @@ async function globalSetup(config: FullConfig) { const { baseURL, storageState } = config.projects[0].use; const browser = await chromium.launch(); const page = await browser.newPage(); - await page.goto(baseURL); + await page.goto(baseURL!); await page.fill('input[name="user"]', 'user'); await page.fill('input[name="password"]', 'password'); await page.click('text=Sign in'); - await page.context().storageState({ path: storageState }); + await page.context().storageState({ path: storageState as string }); await browser.close(); } diff --git a/docs/src/test-advanced-js.md b/docs/src/test-advanced-js.md index d0d25b89c8..5d606d91f4 100644 --- a/docs/src/test-advanced-js.md +++ b/docs/src/test-advanced-js.md @@ -301,11 +301,11 @@ async function globalSetup(config: FullConfig) { const { baseURL, storageState } = config.projects[0].use; const browser = await chromium.launch(); const page = await browser.newPage(); - await page.goto(baseURL); + await page.goto(baseURL!); await page.fill('input[name="user"]', 'user'); await page.fill('input[name="password"]', 'password'); await page.click('text=Sign in'); - await page.context().storageState({ path: storageState }); + await page.context().storageState({ path: storageState as string }); await browser.close(); } diff --git a/src/test/matchers/matchers.ts b/src/test/matchers/matchers.ts index ded545d3e1..009d9d97c8 100644 --- a/src/test/matchers/matchers.ts +++ b/src/test/matchers/matchers.ts @@ -15,7 +15,6 @@ */ import { Locator, Page } from '../../..'; -import { PlaywrightTestOptions} from '../../../types/test'; import { constructURLBasedOnBaseURL } from '../../utils/utils'; import { currentTestInfo } from '../globals'; import type { Expect } from '../types'; @@ -240,7 +239,7 @@ export function toHaveURL( const testInfo = currentTestInfo(); if (!testInfo) throw new Error(`toHaveURL must be called during the test`); - const baseURL = (testInfo.project.use as PlaywrightTestOptions)?.baseURL; + const baseURL = testInfo.project.use.baseURL; return toMatchText.call(this, 'toHaveURL', page, 'Page', async () => { return page.url(); diff --git a/tests/playwright-test/entry/index.d.ts b/tests/playwright-test/entry/index.d.ts index ea977723bc..4b50fb5f5d 100644 --- a/tests/playwright-test/entry/index.d.ts +++ b/tests/playwright-test/entry/index.d.ts @@ -15,3 +15,5 @@ */ export * from '../../../types/test'; +export * from '../../../types/types'; +export { default } from '../../../types/test'; diff --git a/tests/playwright-test/global-setup.spec.ts b/tests/playwright-test/global-setup.spec.ts index 6c35c8a186..8f4cad9f61 100644 --- a/tests/playwright-test/global-setup.spec.ts +++ b/tests/playwright-test/global-setup.spec.ts @@ -238,45 +238,54 @@ test('globalSetup should allow requiring a package from node_modules', async ({ expect(results[0].status).toBe('passed'); }); -test('globalSetup should work for auth', async ({ runInlineTest }) => { - const result = await runInlineTest({ - 'playwright.config.ts': ` - module.exports = { - globalSetup: require.resolve('./auth.js'), - use: { - baseURL: 'https://www.example.com', - storageState: 'state.json', - }, - }; - `, - 'auth.js': ` - module.exports = async config => { - const { baseURL, storageState } = config.projects[0].use; - const browser = await pwt.chromium.launch(); - const page = await browser.newPage(); - await page.route('**/*', route => { - route.fulfill({ body: '' }).catch(() => {}); - }); - await page.goto(baseURL); - await page.evaluate(() => { - localStorage['name'] = 'value'; - }); - await page.context().storageState({ path: storageState }); - await browser.close(); - }; - `, - 'a.test.js': ` - const { test } = pwt; - test('should have storage state', async ({ page }) => { - await page.route('**/*', route => { - route.fulfill({ body: '' }).catch(() => {}); - }); - await page.goto('/'); - const value = await page.evaluate(() => localStorage['name']); - expect(value).toBe('value'); +const authFiles = { + 'playwright.config.ts': ` + const config: pwt.PlaywrightTestConfig = { + globalSetup: require.resolve('./auth'), + use: { + baseURL: 'https://www.example.com', + storageState: 'state.json', + }, + }; + export default config; + `, + 'auth.ts': ` + async function globalSetup(config: pwt.FullConfig) { + const { baseURL, storageState } = config.projects[0].use; + const browser = await pwt.chromium.launch(); + const page = await browser.newPage(); + await page.route('**/*', route => { + route.fulfill({ body: '' }).catch(() => {}); }); - `, - }); + await page.goto(baseURL!); + await page.evaluate(() => { + localStorage['name'] = 'value'; + }); + await page.context().storageState({ path: storageState as string }); + await browser.close(); + }; + export default globalSetup; + `, + 'a.test.ts': ` + const { test } = pwt; + test('should have storage state', async ({ page }) => { + await page.route('**/*', route => { + route.fulfill({ body: '' }).catch(() => {}); + }); + await page.goto('/'); + const value = await page.evaluate(() => localStorage['name']); + expect(value).toBe('value'); + }); + `, +}; + +test('globalSetup should work for auth', async ({ runInlineTest }) => { + const result = await runInlineTest(authFiles); expect(result.exitCode).toBe(0); expect(result.passed).toBe(1); }); + +test('globalSetup auth should compile', async ({runTSC}) => { + const result = await runTSC(authFiles); + expect(result.exitCode).toBe(0); +}); diff --git a/types/test.d.ts b/types/test.d.ts index 8f4a23ebd2..7ffe5c89d1 100644 --- a/types/test.d.ts +++ b/types/test.d.ts @@ -35,6 +35,7 @@ export type PreserveOutput = 'always' | 'never' | 'failures-only'; export type UpdateSnapshots = 'all' | 'none' | 'missing'; type FixtureDefine = { test: TestType, fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs> }; +type UseOptions = { [K in keyof WorkerArgs]?: WorkerArgs[K] } & { [K in keyof TestArgs]?: TestArgs[K] }; type ExpectSettings = { // Default timeout for async expect matchers in milliseconds, defaults to 5000ms. @@ -305,10 +306,10 @@ export interface Project extends TestProject { * ``` * */ - use?: Fixtures<{}, {}, TestArgs, WorkerArgs>; + use?: UseOptions; } -export type FullProject = Required>; +export type FullProject = Required>; export type WebServerConfig = { /** @@ -611,7 +612,7 @@ export interface Config extends TestConfig { * ``` * */ - use?: Fixtures<{}, {}, TestArgs, WorkerArgs>; + use?: UseOptions; } /** @@ -636,7 +637,7 @@ export interface Config extends TestConfig { * ``` * */ -export interface FullConfig { +export interface FullConfig { /** * Whether to exit with an error if any tests or groups are marked as * [test.only(title, testFunction)](https://playwright.dev/docs/api/class-test#test-only) or @@ -706,7 +707,7 @@ export interface FullConfig { /** * Playwright Test supports running multiple test projects at the same time. See [TestProject] for more information. */ - projects: FullProject[]; + projects: FullProject[]; /** * The list of reporters to use. Each reporter can be: * - A builtin reporter name like `'list'` or `'json'`. diff --git a/utils/generate_types/overrides-test.d.ts b/utils/generate_types/overrides-test.d.ts index d165931f6c..815d39e9ce 100644 --- a/utils/generate_types/overrides-test.d.ts +++ b/utils/generate_types/overrides-test.d.ts @@ -34,6 +34,7 @@ export type PreserveOutput = 'always' | 'never' | 'failures-only'; export type UpdateSnapshots = 'all' | 'none' | 'missing'; type FixtureDefine = { test: TestType, fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs> }; +type UseOptions = { [K in keyof WorkerArgs]?: WorkerArgs[K] } & { [K in keyof TestArgs]?: TestArgs[K] }; type ExpectSettings = { // Default timeout for async expect matchers in milliseconds, defaults to 5000ms. @@ -59,10 +60,10 @@ interface TestProject { export interface Project extends TestProject { define?: FixtureDefine | FixtureDefine[]; - use?: Fixtures<{}, {}, TestArgs, WorkerArgs>; + use?: UseOptions; } -export type FullProject = Required>; +export type FullProject = Required>; export type WebServerConfig = { /** @@ -129,10 +130,10 @@ interface TestConfig { export interface Config extends TestConfig { projects?: Project[]; define?: FixtureDefine | FixtureDefine[]; - use?: Fixtures<{}, {}, TestArgs, WorkerArgs>; + use?: UseOptions; } -export interface FullConfig { +export interface FullConfig { forbidOnly: boolean; globalSetup: string | null; globalTeardown: string | null; @@ -141,7 +142,7 @@ export interface FullConfig { grepInvert: RegExp | RegExp[] | null; maxFailures: number; preserveOutput: PreserveOutput; - projects: FullProject[]; + projects: FullProject[]; reporter: ReporterDescription[]; reportSlowTests: ReportSlowTests; rootDir: string;