mirror of
https://github.com/microsoft/playwright.git
synced 2024-10-27 13:50:25 +03:00
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
|
||||
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!
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -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!
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -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).
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
8
types/test.d.ts
vendored
@ -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).
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user