2021-10-05 20:22:16 +02:00
---
id: test-parameterize
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
title: "Parametrize tests"
2021-10-05 20:22:16 +02:00
---
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
You can either parametrize tests on a test level or on a project level.
2021-10-05 20:22:16 +02:00
<!-- TOC -->
2021-11-23 05:38:48 +10:00
## Parameterized Tests
2021-10-05 20:22:16 +02:00
```js js-flavor=js
// example.spec.js
const people = ['Alice', 'Bob'];
2021-11-12 14:50:45 +01:00
for (const name of people) {
2021-10-05 20:22:16 +02:00
test(`testing with ${name}` , async () => {
// ...
});
// You can also do it with test.describe() or with multiple tests as long the test name is unique.
}
```
```js js-flavor=ts
// example.spec.ts
const people = ['Alice', 'Bob'];
2021-11-12 14:50:45 +01:00
for (const name of people) {
2021-10-05 20:22:16 +02:00
test(`testing with ${name}` , async () => {
// ...
});
// You can also do it with test.describe() or with multiple tests as long the test name is unique.
}
```
2021-11-23 05:38:48 +10:00
## Parameterized Projects
2021-10-05 20:22:16 +02:00
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
Playwright Test supports running multiple test projects at the same time. In the following example, we'll run two projects with different options.
We declare the option `person` and set the value in the config. The first project runs with the value `Alice` and the second with the value `Bob` .
2021-10-05 20:22:16 +02:00
```js js-flavor=js
// my-test.js
const base = require('@playwright/test ');
exports.test = base.test.extend({
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
// Define an option and provide a default value.
// We can later override it in the config.
person: ['John', { option: true }],
2021-10-05 20:22:16 +02:00
});
```
```js js-flavor=ts
// my-test.ts
import { test as base } from '@playwright/test ';
export type TestOptions = {
person: string;
};
export const test = base.extend< TestOptions > ({
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
// Define an option and provide a default value.
// We can later override it in the config.
person: ['John', { option: true }],
2021-10-05 20:22:16 +02:00
});
```
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
We can use this option in the test, similarly to [fixtures ](./test-fixtures.md ).
2021-10-05 20:22:16 +02:00
```js js-flavor=js
// example.spec.js
const { test } = require('./my-test');
test('test 1', async ({ page, person }) => {
await page.goto(`/index.html` );
await expect(page.locator('#node ')).toContainText(person);
// ...
});
```
```js js-flavor=ts
// example.spec.ts
import { test } from './my-test';
test('test 1', async ({ page, person }) => {
await page.goto(`/index.html` );
await expect(page.locator('#node ')).toContainText(person);
// ...
});
```
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
Now, we can run tests in multiple configurations by using projects.
2021-10-05 20:22:16 +02:00
```js js-flavor=js
// playwright.config.js
// @ts -check
2021-11-12 17:00:41 +02:00
/** @type {import('@playwright/test ').PlaywrightTestConfig< { person: string }>} */
2021-10-05 20:22:16 +02:00
const config = {
projects: [
{
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
name: 'alice',
2021-10-05 20:22:16 +02:00
use: { person: 'Alice' },
},
{
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
name: 'bob',
2021-10-05 20:22:16 +02:00
use: { person: 'Bob' },
},
]
};
module.exports = config;
```
```js js-flavor=ts
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test ';
import { TestOptions } from './my-test';
const config: PlaywrightTestConfig< TestOptions > = {
projects: [
{
name: 'alice',
use: { person: 'Alice' },
},
{
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
name: 'bob',
2021-10-05 20:22:16 +02:00
use: { person: 'Bob' },
},
]
};
export default config;
```
feat(test runner): replace declare/define with "options" (#10293)
1. Fixtures defined in test.extend() can now have `{ option: true }` configuration that makes them overridable in the config. Options support all other properties of fixtures - value/function, scope, auto.
```
const test = base.extend<MyOptions>({
foo: ['default', { option: true }],
});
```
2. test.declare() and project.define are removed.
3. project.use applies overrides to default option values and nothing else. Any test.extend() and test.use() calls take priority over config options.
Required user changes: if someone used to define fixture options with test.extend(), overriding them in config will stop working. The solution is to add `{ option: true }`.
```
// Old code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: 123,
myFixture: ({ myOption }, use) => use(2 * myOption),
});
// New code
export const test = base.extend<{ myOption: number, myFixture: number }>({
myOption: [123, { option: true }],
myFixture: ({ myOption }, use) => use(2 * myOption),
});
```
2021-11-18 15:45:52 -08:00
We can also use the option in a fixture. Learn more about [fixtures ](./test-fixtures.md ).
```js js-flavor=js
// my-test.js
const base = require('@playwright/test ');
exports.test = base.test.extend({
// Define an option and provide a default value.
// We can later override it in the config.
person: ['John', { option: true }],
// Override default "page" fixture.
page: async ({ page, person }, use) => {
await page.goto('/chat');
// We use "person" parameter as a "name" for the chat room.
await page.locator('#name ').fill(person);
await page.click('text=Enter chat room');
// Each test will get a "page" that already has the person name.
await use(page);
},
});
```
```js js-flavor=ts
// my-test.ts
import { test as base } from '@playwright/test ';
export type TestOptions = {
person: string;
};
export const test = base.test.extend< TestOptions > ({
// Define an option and provide a default value.
// We can later override it in the config.
person: ['John', { option: true }],
// Override default "page" fixture.
page: async ({ page, person }, use) => {
await page.goto('/chat');
// We use "person" parameter as a "name" for the chat room.
await page.locator('#name ').fill(person);
await page.click('text=Enter chat room');
// Each test will get a "page" that already has the person name.
await use(page);
},
});
```
2022-02-01 14:34:47 -08:00
:::note
Parametrized projects behavior has changed in version 1.18. [Learn more ](./release-notes#breaking-change-custom-config-options ).
:::
2022-02-22 15:24:35 -08:00
## Passing Environment Variables
You can use environment variables to configure tests from the command line.
For example, consider the following test file that needs a username and a password. It is usually a good idea not to store your secrets in the source code, so we'll need a way to pass secrets from outside.
```js js-flavor=js
// example.spec.js
test(`example test` , async ({ page }) => {
// ...
await page.locator('#username ').fill(process.env.USERNAME);
await page.locator('#password ').fill(process.env.PASSWORD);
});
```
```js js-flavor=ts
// example.spec.ts
test(`example test` , async ({ page }) => {
// ...
await page.locator('#username ').fill(process.env.USERNAME);
await page.locator('#password ').fill(process.env.PASSWORD);
});
```
You can run this test with your secrect username and password set in the command line.
```bash bash-flavor=bash
USERNAME=me PASSWORD=secret npx playwright test
```
```bash bash-flavor=batch
set USERNAME=me
set PASSWORD=secret
npx playwright test
```
```bash bash-flavor=powershell
$env:USERNAME=me
$env:PASSWORD=secret
npx playwright test
```
Similarly, configuration file can also read environment variables passed throught the command line.
```js js-flavor=js
// playwright.config.js
// @ts -check
/** @type {import('@playwright/test ').PlaywrightTestConfig} */
const config = {
use: {
baseURL: process.env.STAGING === '1' ? 'http://staging.example.test/' : 'http://example.test/',
}
};
module.exports = config;
```
```js js-flavor=ts
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test ';
const config: PlaywrightTestConfig = {
use: {
baseURL: process.env.STAGING === '1' ? 'http://staging.example.test/' : 'http://example.test/',
}
};
export default config;
```
Now, you can run tests against a staging or a production environment:
```bash bash-flavor=bash
STAGING=1 npx playwright test
```
```bash bash-flavor=batch
set STAGING=1
npx playwright test
```
```bash bash-flavor=powershell
$env:STAGING=1
npx playwright test
```
### .env files
To make environment variables easier to manage, consider something like `.env` files. Here is an example that uses [`dotenv` ](https://www.npmjs.com/package/dotenv ) package to read environment variables directly in the configuration file.
```js js-flavor=js
// playwright.config.js
// @ts -check
// Read from default ".env" file.
require('dotenv').config();
// Alternatively, read from "../my.env" file.
require('dotenv').config({ path: path.resolve(__dirname, '..', 'my.env') });
/** @type {import('@playwright/test ').PlaywrightTestConfig} */
const config = {
use: {
baseURL: process.env.STAGING === '1' ? 'http://staging.example.test/' : 'http://example.test/',
}
};
module.exports = config;
```
```js js-flavor=ts
// playwright.config.ts
import { PlaywrightTestConfig } from '@playwright/test ';
import dotenv from 'dotenv';
import path from 'path';
// Read from default ".env" file.
dotenv.config();
// Alternatively, read from "../my.env" file.
dotenv.config({ path: path.resolve(__dirname, '..', 'my.env') });
const config: PlaywrightTestConfig = {
use: {
baseURL: process.env.STAGING === '1' ? 'http://staging.example.test/' : 'http://example.test/',
}
};
export default config;
```
Now, you can just edit `.env` file to set any variables you'd like.
```bash
# .env file
STAGING=0
USERNAME=me
PASSWORD=secret
```
Run tests as usual, your environment variables should be picked up.
```bash
npx playwright test
```