fix(test): make use in config accept option values only (#8828)

Also include default options in FullConfig/FullProject.
Also make examples compile and add a test.
This commit is contained in:
Dmitry Gozman 2021-09-13 17:50:31 -07:00 committed by GitHub
parent ed34a67d4a
commit d9d2d809a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 54 deletions

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();

View File

@ -15,3 +15,5 @@
*/
export * from '../../../types/test';
export * from '../../../types/types';
export { default } from '../../../types/test';

View File

@ -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: '<html></html>' }).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: '<html></html>' }).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: '<html></html>' }).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: '<html></html>' }).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);
});

11
types/test.d.ts vendored
View File

@ -35,6 +35,7 @@ export type PreserveOutput = 'always' | 'never' | 'failures-only';
export type UpdateSnapshots = 'all' | 'none' | 'missing';
type FixtureDefine<TestArgs extends KeyValue = {}, WorkerArgs extends KeyValue = {}> = { test: TestType<TestArgs, WorkerArgs>, fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs> };
type UseOptions<TestArgs, WorkerArgs> = { [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<TestArgs = {}, WorkerArgs = {}> extends TestProject {
* ```
*
*/
use?: Fixtures<{}, {}, TestArgs, WorkerArgs>;
use?: UseOptions<TestArgs, WorkerArgs>;
}
export type FullProject<TestArgs = {}, WorkerArgs = {}> = Required<Project<TestArgs, WorkerArgs>>;
export type FullProject<TestArgs = {}, WorkerArgs = {}> = Required<Project<PlaywrightTestOptions & TestArgs, PlaywrightWorkerOptions & WorkerArgs>>;
export type WebServerConfig = {
/**
@ -611,7 +612,7 @@ export interface Config<TestArgs = {}, WorkerArgs = {}> extends TestConfig {
* ```
*
*/
use?: Fixtures<{}, {}, TestArgs, WorkerArgs>;
use?: UseOptions<TestArgs, WorkerArgs>;
}
/**
@ -636,7 +637,7 @@ export interface Config<TestArgs = {}, WorkerArgs = {}> extends TestConfig {
* ```
*
*/
export interface FullConfig {
export interface FullConfig<TestArgs = {}, WorkerArgs = {}> {
/**
* 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<TestArgs, WorkerArgs>[];
/**
* The list of reporters to use. Each reporter can be:
* - A builtin reporter name like `'list'` or `'json'`.

View File

@ -34,6 +34,7 @@ export type PreserveOutput = 'always' | 'never' | 'failures-only';
export type UpdateSnapshots = 'all' | 'none' | 'missing';
type FixtureDefine<TestArgs extends KeyValue = {}, WorkerArgs extends KeyValue = {}> = { test: TestType<TestArgs, WorkerArgs>, fixtures: Fixtures<{}, {}, TestArgs, WorkerArgs> };
type UseOptions<TestArgs, WorkerArgs> = { [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<TestArgs = {}, WorkerArgs = {}> extends TestProject {
define?: FixtureDefine | FixtureDefine[];
use?: Fixtures<{}, {}, TestArgs, WorkerArgs>;
use?: UseOptions<TestArgs, WorkerArgs>;
}
export type FullProject<TestArgs = {}, WorkerArgs = {}> = Required<Project<TestArgs, WorkerArgs>>;
export type FullProject<TestArgs = {}, WorkerArgs = {}> = Required<Project<PlaywrightTestOptions & TestArgs, PlaywrightWorkerOptions & WorkerArgs>>;
export type WebServerConfig = {
/**
@ -129,10 +130,10 @@ interface TestConfig {
export interface Config<TestArgs = {}, WorkerArgs = {}> extends TestConfig {
projects?: Project<TestArgs, WorkerArgs>[];
define?: FixtureDefine | FixtureDefine[];
use?: Fixtures<{}, {}, TestArgs, WorkerArgs>;
use?: UseOptions<TestArgs, WorkerArgs>;
}
export interface FullConfig {
export interface FullConfig<TestArgs = {}, WorkerArgs = {}> {
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<TestArgs, WorkerArgs>[];
reporter: ReporterDescription[];
reportSlowTests: ReportSlowTests;
rootDir: string;