docs: update global setup docs (#8637)
Changing example to "authenticate once", and also updating the auth doc. Adding a test with the same setup.
This commit is contained in:
parent
6b371f83f2
commit
b1260602ac
|
|
@ -166,65 +166,91 @@ When using [Playwright Test](./intro.md), you can log in once in the global setu
|
||||||
and then reuse authentication state in tests. That way all your tests are completely
|
and then reuse authentication state in tests. That way all your tests are completely
|
||||||
isolated, yet you only waste time logging in once for the entire test suite run.
|
isolated, yet you only waste time logging in once for the entire test suite run.
|
||||||
|
|
||||||
First, introduce the global setup that would log in once.
|
First, introduce the global setup that would sign in once. In this example we use the `baseURL` and `storageState` options from the configuration file.
|
||||||
|
|
||||||
```js js-flavor=js
|
```js js-flavor=js
|
||||||
// global-setup.js
|
// global-setup.js
|
||||||
const { chromium } = require('@playwright/test');
|
const { chromium } = require('@playwright/test');
|
||||||
|
|
||||||
module.exports = async () => {
|
module.exports = async config => {
|
||||||
|
const { baseURL, storageState } = config.projects[0].use;
|
||||||
const browser = await chromium.launch();
|
const browser = await chromium.launch();
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
await page.goto('http://localhost:5000/');
|
await page.goto(baseURL);
|
||||||
await page.click('text=login');
|
|
||||||
await page.fill('input[name="user"]', 'user');
|
await page.fill('input[name="user"]', 'user');
|
||||||
await page.fill('input[name="password"]', 'password');
|
await page.fill('input[name="password"]', 'password');
|
||||||
await page.click('input:has-text("login")');
|
await page.click('text=Sign in');
|
||||||
await page.context().storageState({ path: 'state.json' });
|
await page.context().storageState({ path: storageState });
|
||||||
await browser.close();
|
await browser.close();
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
```js js-flavor=ts
|
```js js-flavor=ts
|
||||||
// global-setup.ts
|
// global-setup.ts
|
||||||
import { chromium } from '@playwright/test';
|
import { chromium, FullConfig } from '@playwright/test';
|
||||||
|
|
||||||
async function globalSetup() {
|
async function globalSetup(config: FullConfig) {
|
||||||
|
const { baseURL, storageState } = config.projects[0].use;
|
||||||
const browser = await chromium.launch();
|
const browser = await chromium.launch();
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
await page.goto('http://localhost:5000/');
|
await page.goto(baseURL);
|
||||||
await page.click('text=login');
|
|
||||||
await page.fill('input[name="user"]', 'user');
|
await page.fill('input[name="user"]', 'user');
|
||||||
await page.fill('input[name="password"]', 'password');
|
await page.fill('input[name="password"]', 'password');
|
||||||
await page.click('input:has-text("login")');
|
await page.click('text=Sign in');
|
||||||
await page.context().storageState({ path: 'state.json' });
|
await page.context().storageState({ path: storageState });
|
||||||
await browser.close();
|
await browser.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default globalSetup;
|
export default globalSetup;
|
||||||
```
|
```
|
||||||
|
|
||||||
Then reuse saved authentication state in your tests.
|
Next specify `globalSetup`, `baseURL` and `storageState` in the configuration file.
|
||||||
|
|
||||||
|
```js js-flavor=js
|
||||||
|
// playwright.config.js
|
||||||
|
// @ts-check
|
||||||
|
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
||||||
|
const config = {
|
||||||
|
globalSetup: require.resolve('./global-setup'),
|
||||||
|
use: {
|
||||||
|
baseURL: 'http://localhost:3000/',
|
||||||
|
storageState: 'state.json',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module.exports = config;
|
||||||
|
```
|
||||||
|
|
||||||
|
```js js-flavor=ts
|
||||||
|
// playwright.config.ts
|
||||||
|
import { PlaywrightTestConfig } from '@playwright/test';
|
||||||
|
|
||||||
|
const config: PlaywrightTestConfig = {
|
||||||
|
globalSetup: require.resolve('./global-setup'),
|
||||||
|
use: {
|
||||||
|
baseURL: 'http://localhost:3000/',
|
||||||
|
storageState: 'state.json',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
|
```
|
||||||
|
|
||||||
|
Tests start already authenticated because we specify `storageState` that was populated by global setup.
|
||||||
|
|
||||||
```js js-flavor=ts
|
```js js-flavor=ts
|
||||||
import { test } from '@playwright/test';
|
import { test } from '@playwright/test';
|
||||||
|
|
||||||
test.use({ storageState: 'state.json' });
|
|
||||||
|
|
||||||
test('test', async ({ page }) => {
|
test('test', async ({ page }) => {
|
||||||
await page.goto('http://localhost:5000/');
|
await page.goto('/');
|
||||||
// You are logged in!
|
// You are signed in!
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
```js js-flavor=js
|
```js js-flavor=js
|
||||||
const { test } = require('@playwright/test');
|
const { test } = require('@playwright/test');
|
||||||
|
|
||||||
test.use({ storageState: 'state.json' });
|
|
||||||
|
|
||||||
test('test', async ({ page }) => {
|
test('test', async ({ page }) => {
|
||||||
await page.goto('http://localhost:5000/');
|
await page.goto('/');
|
||||||
// You are logged in!
|
// You are signed in!
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -270,50 +270,49 @@ test('test', async ({ page, baseURL }) => {
|
||||||
|
|
||||||
## Global setup and teardown
|
## Global setup and teardown
|
||||||
|
|
||||||
To set something up once before running all tests, use `globalSetup` option in the [configuration file](#configuration-object).
|
To set something up once before running all tests, use `globalSetup` option in the [configuration file](#configuration-object). Global setup file must export a single function that takes a config object. This function will be run once before all the tests.
|
||||||
|
|
||||||
Similarly, use `globalTeardown` to run something once after all the tests. Alternatively, let `globalSetup` return a function that will be used as a global teardown. You can pass data such as port number, authentication tokens, etc. from your global setup to your tests using environment.
|
Similarly, use `globalTeardown` to run something once after all the tests. Alternatively, let `globalSetup` return a function that will be used as a global teardown. You can pass data such as port number, authentication tokens, etc. from your global setup to your tests using environment.
|
||||||
|
|
||||||
Here is a global setup example that runs an app.
|
Here is a global setup example that authenticates once and reuses authentication state in tests. It uses `baseURL` and `storageState` options from the configuration file.
|
||||||
|
|
||||||
```js js-flavor=js
|
```js js-flavor=js
|
||||||
// global-setup.js
|
// global-setup.js
|
||||||
const app = require('./my-app');
|
const { chromium } = require('@playwright/test');
|
||||||
|
|
||||||
module.exports = async () => {
|
module.exports = async config => {
|
||||||
const server = require('http').createServer(app);
|
const { baseURL, storageState } = config.projects[0].use;
|
||||||
await new Promise(done => server.listen(done));
|
const browser = await chromium.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
// Expose port to the tests.
|
await page.goto(baseURL);
|
||||||
process.env.SERVER_PORT = String(server.address().port);
|
await page.fill('input[name="user"]', 'user');
|
||||||
|
await page.fill('input[name="password"]', 'password');
|
||||||
// Return the teardown function.
|
await page.click('text=Sign in');
|
||||||
return async () => {
|
await page.context().storageState({ path: storageState });
|
||||||
await new Promise(done => server.close(done));
|
await browser.close();
|
||||||
};
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
```js js-flavor=ts
|
```js js-flavor=ts
|
||||||
// global-setup.ts
|
// global-setup.ts
|
||||||
import app from './my-app';
|
import { chromium, FullConfig } from '@playwright/test';
|
||||||
import * as http from 'http';
|
|
||||||
|
|
||||||
async function globalSetup() {
|
async function globalSetup(config: FullConfig) {
|
||||||
const server = http.createServer(app);
|
const { baseURL, storageState } = config.projects[0].use;
|
||||||
await new Promise(done => server.listen(done));
|
const browser = await chromium.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
// Expose port to the tests.
|
await page.goto(baseURL);
|
||||||
process.env.SERVER_PORT = String(server.address().port);
|
await page.fill('input[name="user"]', 'user');
|
||||||
|
await page.fill('input[name="password"]', 'password');
|
||||||
// Return the teardown function.
|
await page.click('text=Sign in');
|
||||||
return async () => {
|
await page.context().storageState({ path: storageState });
|
||||||
await new Promise(done => server.close(done));
|
await browser.close();
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default globalSetup;
|
export default globalSetup;
|
||||||
```
|
```
|
||||||
|
|
||||||
Now add `globalSetup` option to the configuration file.
|
Specify `globalSetup`, `baseURL` and `storageState` in the configuration file.
|
||||||
|
|
||||||
```js js-flavor=js
|
```js js-flavor=js
|
||||||
// playwright.config.js
|
// playwright.config.js
|
||||||
|
|
@ -321,6 +320,10 @@ Now add `globalSetup` option to the configuration file.
|
||||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
||||||
const config = {
|
const config = {
|
||||||
globalSetup: require.resolve('./global-setup'),
|
globalSetup: require.resolve('./global-setup'),
|
||||||
|
use: {
|
||||||
|
baseURL: 'http://localhost:3000/',
|
||||||
|
storageState: 'state.json',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
```
|
```
|
||||||
|
|
@ -331,27 +334,31 @@ import { PlaywrightTestConfig } from '@playwright/test';
|
||||||
|
|
||||||
const config: PlaywrightTestConfig = {
|
const config: PlaywrightTestConfig = {
|
||||||
globalSetup: require.resolve('./global-setup'),
|
globalSetup: require.resolve('./global-setup'),
|
||||||
|
use: {
|
||||||
|
baseURL: 'http://localhost:3000/',
|
||||||
|
storageState: 'state.json',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
export default config;
|
export default config;
|
||||||
```
|
```
|
||||||
|
|
||||||
Tests will now run after the global setup is done and will have access to the data created in the global setup:
|
Tests start already authenticated because we specify `storageState` that was populated by global setup.
|
||||||
|
|
||||||
```js js-flavor=js
|
```js js-flavor=ts
|
||||||
// test.spec.js
|
import { test } from '@playwright/test';
|
||||||
const { test } = require('@playwright/test');
|
|
||||||
|
|
||||||
test('test', async ({ }) => {
|
test('test', async ({ page }) => {
|
||||||
console.log(process.env.SERVER_PORT);
|
await page.goto('/');
|
||||||
|
// You are signed in!
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
```js js-flavor=ts
|
```js js-flavor=js
|
||||||
// test.spec.ts
|
const { test } = require('@playwright/test');
|
||||||
import { test } = from '@playwright/test';
|
|
||||||
|
|
||||||
test('test', async ({ }) => {
|
test('test', async ({ page }) => {
|
||||||
console.log(process.env.SERVER_PORT);
|
await page.goto('/');
|
||||||
|
// You are signed in!
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ Whether to exit with an error if any tests or groups are marked as [`method: Tes
|
||||||
## property: TestConfig.globalSetup
|
## property: TestConfig.globalSetup
|
||||||
- type: <[string]>
|
- type: <[string]>
|
||||||
|
|
||||||
Path to the global setup file. This file will be required and run before all the tests. It must export a single function.
|
Path to the global setup file. This file will be required and run before all the tests. It must export a single function that takes a [`TestConfig`] argument.
|
||||||
|
|
||||||
Learn more about [global setup and teardown](./test-advanced.md#global-setup-and-teardown).
|
Learn more about [global setup and teardown](./test-advanced.md#global-setup-and-teardown).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,11 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = require('../../../lib/test/index');
|
const pwt = require('../../../lib/test/index');
|
||||||
|
const playwright = require('../../../lib/inprocess');
|
||||||
|
const combinedExports = {
|
||||||
|
...playwright,
|
||||||
|
...pwt,
|
||||||
|
};
|
||||||
|
Object.defineProperty(combinedExports, '__esModule', { value: true });
|
||||||
|
module.exports = combinedExports;
|
||||||
|
|
|
||||||
|
|
@ -236,4 +236,47 @@ test('globalSetup should allow requiring a package from node_modules', async ({
|
||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
expect(results[0].status).toBe('passed');
|
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');
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(1);
|
||||||
|
});
|
||||||
|
|
|
||||||
8
types/test.d.ts
vendored
8
types/test.d.ts
vendored
|
|
@ -558,8 +558,8 @@ interface TestConfig {
|
||||||
*/
|
*/
|
||||||
forbidOnly?: boolean;
|
forbidOnly?: boolean;
|
||||||
/**
|
/**
|
||||||
* Path to the global setup file. This file will be required and run before all the tests. It must export a single
|
* Path to the global setup file. This file will be required and run before all the tests. It must export a single function
|
||||||
* function.
|
* that takes a [`TestConfig`] argument.
|
||||||
*
|
*
|
||||||
* Learn more about [global setup and teardown](https://playwright.dev/docs/test-advanced#global-setup-and-teardown).
|
* Learn more about [global setup and teardown](https://playwright.dev/docs/test-advanced#global-setup-and-teardown).
|
||||||
*
|
*
|
||||||
|
|
@ -908,8 +908,8 @@ export interface FullConfig {
|
||||||
*/
|
*/
|
||||||
forbidOnly: boolean;
|
forbidOnly: boolean;
|
||||||
/**
|
/**
|
||||||
* Path to the global setup file. This file will be required and run before all the tests. It must export a single
|
* Path to the global setup file. This file will be required and run before all the tests. It must export a single function
|
||||||
* function.
|
* that takes a [`TestConfig`] argument.
|
||||||
*
|
*
|
||||||
* Learn more about [global setup and teardown](https://playwright.dev/docs/test-advanced#global-setup-and-teardown).
|
* Learn more about [global setup and teardown](https://playwright.dev/docs/test-advanced#global-setup-and-teardown).
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue