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:
Dmitry Gozman 2021-09-01 15:35:46 -07:00 committed by GitHub
parent 6b371f83f2
commit b1260602ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 150 additions and 67 deletions

View File

@ -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
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
// global-setup.js
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 page = await browser.newPage();
await page.goto('http://localhost:5000/');
await page.click('text=login');
await page.goto(baseURL);
await page.fill('input[name="user"]', 'user');
await page.fill('input[name="password"]', 'password');
await page.click('input:has-text("login")');
await page.context().storageState({ path: 'state.json' });
await page.click('text=Sign in');
await page.context().storageState({ path: storageState });
await browser.close();
};
```
```js js-flavor=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 page = await browser.newPage();
await page.goto('http://localhost:5000/');
await page.click('text=login');
await page.goto(baseURL);
await page.fill('input[name="user"]', 'user');
await page.fill('input[name="password"]', 'password');
await page.click('input:has-text("login")');
await page.context().storageState({ path: 'state.json' });
await page.click('text=Sign in');
await page.context().storageState({ path: storageState });
await browser.close();
}
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
import { test } from '@playwright/test';
test.use({ storageState: 'state.json' });
test('test', async ({ page }) => {
await page.goto('http://localhost:5000/');
// You are logged in!
await page.goto('/');
// You are signed in!
});
```
```js js-flavor=js
const { test } = require('@playwright/test');
test.use({ storageState: 'state.json' });
test('test', async ({ page }) => {
await page.goto('http://localhost:5000/');
// You are logged in!
await page.goto('/');
// You are signed in!
});
```

View File

@ -270,50 +270,49 @@ test('test', async ({ page, baseURL }) => {
## 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.
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
// global-setup.js
const app = require('./my-app');
const { chromium } = require('@playwright/test');
module.exports = async () => {
const server = require('http').createServer(app);
await new Promise(done => server.listen(done));
// Expose port to the tests.
process.env.SERVER_PORT = String(server.address().port);
// Return the teardown function.
return async () => {
await new Promise(done => server.close(done));
};
module.exports = async config => {
const { baseURL, storageState } = config.projects[0].use;
const browser = await chromium.launch();
const page = await browser.newPage();
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 browser.close();
};
```
```js js-flavor=ts
// global-setup.ts
import app from './my-app';
import * as http from 'http';
import { chromium, FullConfig } from '@playwright/test';
async function globalSetup() {
const server = http.createServer(app);
await new Promise(done => server.listen(done));
// Expose port to the tests.
process.env.SERVER_PORT = String(server.address().port);
// Return the teardown function.
return async () => {
await new Promise(done => server.close(done));
};
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.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 browser.close();
}
export default globalSetup;
```
Now add `globalSetup` option to the configuration file.
Specify `globalSetup`, `baseURL` and `storageState` in the configuration file.
```js js-flavor=js
// playwright.config.js
@ -321,6 +320,10 @@ Now add `globalSetup` option to the configuration file.
/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
globalSetup: require.resolve('./global-setup'),
use: {
baseURL: 'http://localhost:3000/',
storageState: 'state.json',
},
};
module.exports = config;
```
@ -331,27 +334,31 @@ 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 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
// test.spec.js
const { test } = require('@playwright/test');
```js js-flavor=ts
import { test } from '@playwright/test';
test('test', async ({ }) => {
console.log(process.env.SERVER_PORT);
test('test', async ({ page }) => {
await page.goto('/');
// You are signed in!
});
```
```js js-flavor=ts
// test.spec.ts
import { test } = from '@playwright/test';
```js js-flavor=js
const { test } = require('@playwright/test');
test('test', async ({ }) => {
console.log(process.env.SERVER_PORT);
test('test', async ({ page }) => {
await page.goto('/');
// You are signed in!
});
```

View File

@ -48,7 +48,7 @@ Whether to exit with an error if any tests or groups are marked as [`method: Tes
## property: TestConfig.globalSetup
- 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).

View File

@ -14,4 +14,11 @@
* 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;

View File

@ -237,3 +237,46 @@ 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');
});
`,
});
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
});

8
types/test.d.ts vendored
View File

@ -558,8 +558,8 @@ interface TestConfig {
*/
forbidOnly?: boolean;
/**
* 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](https://playwright.dev/docs/test-advanced#global-setup-and-teardown).
*
@ -908,8 +908,8 @@ export interface FullConfig {
*/
forbidOnly: boolean;
/**
* 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](https://playwright.dev/docs/test-advanced#global-setup-and-teardown).
*