2021-06-06 17:09:53 -07:00
/ * *
* Copyright Microsoft Corporation . All rights reserved .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
import { test , expect } from './playwright-test-fixtures' ;
2021-09-27 18:58:08 +02:00
test ( 'basics should work' , async ( { runTSC } ) = > {
2021-06-06 17:09:53 -07:00
const result = await runTSC ( {
'a.spec.ts' : `
2023-02-14 19:20:56 -08:00
import { test , expect } from '@playwright/test' ;
2021-06-06 17:09:53 -07:00
test . describe ( 'suite' , ( ) = > {
test . beforeEach ( async ( ) = > { } ) ;
2022-03-18 16:07:11 -07:00
test . afterEach ( async ( ) = > { } ) ;
test . beforeAll ( async ( ) = > { } ) ;
test . afterAll ( async ( ) = > { } ) ;
2021-06-06 17:09:53 -07:00
test ( 'my test' , async ( { } , testInfo ) = > {
expect ( testInfo . title ) . toBe ( 'my test' ) ;
testInfo . annotations [ 0 ] . type ;
2022-10-27 15:53:27 -07:00
test . setTimeout ( 123 ) ;
2021-06-06 17:09:53 -07:00
} ) ;
2022-03-18 16:07:11 -07:00
test . skip ( 'my test' , async ( ) = > { } ) ;
test . fixme ( 'my test' , async ( ) = > { } ) ;
2024-01-22 19:47:27 -08:00
test . fail ( 'my test' , async ( ) = > { } ) ;
2024-10-16 22:47:23 +09:00
test . fail . only ( 'my test' , async ( ) = > { } ) ;
2021-06-06 17:09:53 -07:00
} ) ;
2022-07-06 13:54:11 -07:00
test . describe ( ( ) = > {
test ( 'my test' , ( ) = > { } ) ;
} ) ;
2022-03-18 16:07:11 -07:00
test . describe . parallel ( 'suite' , ( ) = > { } ) ;
test . describe . parallel . only ( 'suite' , ( ) = > { } ) ;
test . describe . serial ( 'suite' , ( ) = > { } ) ;
test . describe . serial . only ( 'suite' , ( ) = > { } ) ;
test . describe . skip ( 'suite' , ( ) = > { } ) ;
2022-07-29 12:44:22 -07:00
test . describe . fixme ( 'suite' , ( ) = > { } ) ;
2021-08-09 13:26:33 -07:00
// @ts-expect-error
test . foo ( ) ;
2022-10-27 15:53:27 -07:00
test . describe . configure ( { mode : 'parallel' } ) ;
test . describe . configure ( { retries : 3 , timeout : 123 } ) ;
feat(test runner): tags/annotations (#29248)
API changes:
- `test(title, details, body)` where details contain `tag` and
`annotation`.
- similar `details` property added to `test.skip`, `test.fail`,
`test.fixme`, `test.only`, `test.describe` and other `test.describe.*`
variations.
- `TestProject.tagFilter`/`TestConfig.tagFilter` that supports logical
tag expressions with `(`, `)`, `and`, `or` and `not`.
- `--tag` CLI option to filter by tags.
- New annotations are available in `TestInfo.annotations` and
`TestCase.annotations`.
- New tags are available in `TestCase.tags`.
Reporter changes:
- `json` reporter includes new tags in addition to old `@smoke`-style
tags. **Breaking**: tags are now listed with the leading `@` symbol.
- `html` reporter filters by old and new tags with the same `@smoke`
token.
Fixes #29229, fixes #23180.
2024-02-07 16:31:25 -08:00
test ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
test ( 'title' , { tag : [ '@foo' , '@bar' ] } , ( ) = > { } ) ;
test ( 'title' , { annotation : { type : 'issue' } } , ( ) = > { } ) ;
test ( 'title' , { annotation : [ { type : 'issue' } , { type : 'foo' , description : 'bar' } ] } , ( ) = > { } ) ;
test ( 'title' , {
tag : '@foo' ,
annotation : { type : 'issue' } ,
} , ( ) = > { } ) ;
test . skip ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
test . fixme ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
test . only ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
test . fail ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
2024-10-16 22:47:23 +09:00
test . fail . only ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
feat(test runner): tags/annotations (#29248)
API changes:
- `test(title, details, body)` where details contain `tag` and
`annotation`.
- similar `details` property added to `test.skip`, `test.fail`,
`test.fixme`, `test.only`, `test.describe` and other `test.describe.*`
variations.
- `TestProject.tagFilter`/`TestConfig.tagFilter` that supports logical
tag expressions with `(`, `)`, `and`, `or` and `not`.
- `--tag` CLI option to filter by tags.
- New annotations are available in `TestInfo.annotations` and
`TestCase.annotations`.
- New tags are available in `TestCase.tags`.
Reporter changes:
- `json` reporter includes new tags in addition to old `@smoke`-style
tags. **Breaking**: tags are now listed with the leading `@` symbol.
- `html` reporter filters by old and new tags with the same `@smoke`
token.
Fixes #29229, fixes #23180.
2024-02-07 16:31:25 -08:00
test . describe ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
test . describe ( 'title' , { annotation : { type : 'issue' } } , ( ) = > { } ) ;
// @ts-expect-error
test . describe ( { tag : '@foo' } , ( ) = > { } ) ;
test . describe . skip ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
test . describe . fixme ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
test . describe . only ( 'title' , { tag : '@foo' } , ( ) = > { } ) ;
2021-06-06 17:09:53 -07:00
`
} ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
} ) ;
2021-09-27 18:58:08 +02:00
test ( 'can pass sync functions everywhere' , async ( { runTSC } ) = > {
2021-06-06 17:09:53 -07:00
const result = await runTSC ( {
'a.spec.ts' : `
2023-02-14 19:20:56 -08:00
import { test as base , expect } from '@playwright/test' ;
const test = base . extend < { foo : string } > ( {
2021-06-06 17:09:53 -07:00
foo : ( { } , use ) = > use ( 'bar' ) ,
} ) ;
test . beforeEach ( ( { foo } ) = > { } ) ;
test . afterEach ( ( { foo } ) = > { } ) ;
test . beforeAll ( ( ) = > { } ) ;
test . afterAll ( ( ) = > { } ) ;
test ( 'my test' , ( { foo } ) = > { } ) ;
`
} ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
} ) ;
2021-09-27 18:58:08 +02:00
test ( 'can return anything from hooks' , async ( { runTSC } ) = > {
2021-06-06 17:09:53 -07:00
const result = await runTSC ( {
'a.spec.ts' : `
2023-02-14 19:20:56 -08:00
import { test , expect } from '@playwright/test' ;
2021-06-06 17:09:53 -07:00
test . beforeEach ( ( ) = > '123' ) ;
test . afterEach ( ( ) = > 123 ) ;
test . beforeAll ( ( ) = > [ 123 ] ) ;
test . afterAll ( ( ) = > ( { a : 123 } ) ) ;
`
} ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
} ) ;
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
test ( 'test.extend options should check types' , async ( { runTSC } ) = > {
2021-06-06 17:09:53 -07:00
const result = await runTSC ( {
'helper.ts' : `
2023-10-11 13:56:27 -07:00
import { test as base , expect , mergeTests } from '@playwright/test' ;
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
export type Params = { foo : string } ;
2023-02-14 19:20:56 -08:00
export const test = base ;
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
export const test1 = test . extend < Params > ( { foo : [ 'foo' , { option : true } ] } ) ;
2023-10-03 13:26:30 -07:00
export const testW = test . extend < { } , { bar : string } > ( { bar : [ 'bar' , { scope : 'worker' } ] } ) ;
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
export const testerror = test . extend < { foo : string } > ( {
// @ts-expect-error
foo : 123
} ) ;
2021-06-06 17:09:53 -07:00
export const test2 = test1 . extend < { bar : number } > ( {
bar : async ( { foo } , run ) = > { await run ( parseInt ( foo ) ) ; }
} ) ;
export const test3 = test1 . extend < { bar : number } > ( {
// @ts-expect-error
bar : async ( { baz } , run ) = > { await run ( 42 ) ; }
} ) ;
2023-10-11 13:56:27 -07:00
export const test4 = mergeTests ( test1 , testW ) ;
2023-10-03 13:26:30 -07:00
const test5 = test4 . extend < { } , { hey : string , hey2 : string } > ( {
// @ts-expect-error
hey : [ async ( { foo } , use ) = > {
await use ( foo ) ;
} , { scope : 'worker' } ] ,
hey2 : [ async ( { bar } , use ) = > {
await use ( bar ) ;
} , { scope : 'worker' } ] ,
} ) ;
export const test6 = test4 . extend < { hey : string } > ( {
hey : async ( { foo } , use ) = > {
await use ( foo ) ;
} ,
} ) ;
2021-06-06 17:09:53 -07:00
` ,
'playwright.config.ts' : `
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
import { Params } from './helper' ;
2023-02-14 19:20:56 -08:00
import { Config } from '@playwright/test' ;
const configs : Config < Params > [ ] = [ ] ;
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
2021-06-06 17:09:53 -07:00
configs . push ( { } ) ;
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
2021-06-06 17:09:53 -07:00
configs . push ( {
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
use : { foo : 'bar' } ,
} ) ;
configs . push ( {
// @ts-expect-error
use : { foo : true } ,
2021-06-06 17:09:53 -07:00
} ) ;
configs . push ( {
// @ts-expect-error
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
use : { unknown : true } ,
2021-06-06 17:09:53 -07:00
} ) ;
module . exports = configs ;
` ,
'a.spec.ts' : `
2023-10-03 13:26:30 -07:00
import { test , test1 , test2 , test3 , test4 , test6 } from './helper' ;
2021-06-06 17:09:53 -07:00
// @ts-expect-error
test ( 'my test' , async ( { foo } ) = > { } ) ;
test1 ( 'my test' , async ( { foo } ) = > { } ) ;
// @ts-expect-error
test1 ( 'my test' , async ( { foo , bar } ) = > { } ) ;
test2 ( 'my test' , async ( { foo , bar } ) = > { } ) ;
// @ts-expect-error
test2 ( 'my test' , async ( { foo , baz } ) = > { } ) ;
2023-10-03 13:26:30 -07:00
test4 ( 'my test' , async ( { foo , bar } ) = > { } ) ;
// @ts-expect-error
test4 ( 'my test' , async ( { foo , qux } ) = > { } ) ;
test6 ( 'my test' , async ( { bar , hey } ) = > { } ) ;
// @ts-expect-error
test6 ( 'my test' , async ( { qux } ) = > { } ) ;
2021-06-06 17:09:53 -07:00
`
} ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
} ) ;
2022-07-29 15:16:07 -07:00
test ( 'step should inherit return type from its callback ' , async ( { runTSC } ) = > {
const result = await runTSC ( {
'a.spec.ts' : `
2023-02-14 19:20:56 -08:00
import { test , expect } from '@playwright/test' ;
2022-07-29 15:16:07 -07:00
test ( 'my test' , async ( { } ) = > {
// @ts-expect-error
const bad1 : string = await test . step ( 'my step' , ( ) = > {
return 10 ;
} ) ;
// @ts-expect-error
const bad2 : string = await test . step ( 'my step' , async ( ) = > {
return 10 ;
} ) ;
const good : string = await test . step ( 'my step' , async ( ) = > {
return 'foo' ;
} ) ;
await test . step ( 'my step' , async ( ) = > { } ) ;
2023-02-17 14:26:40 -08:00
const good2 : string = await test . step ( 'my step' , ( ) = > 'foo' ) ;
2022-07-29 15:16:07 -07:00
} ) ;
`
} ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
} ) ;
2024-12-17 11:17:22 -08:00
2025-01-14 17:43:47 -08:00
test ( 'step.skip returns void ' , async ( { runTSC } ) = > {
2024-12-17 11:17:22 -08:00
const result = await runTSC ( {
'a.spec.ts' : `
import { test , expect } from '@playwright/test' ;
2025-01-14 17:43:47 -08:00
test ( 'test step.skip' , async ( { } ) = > {
2024-12-17 11:17:22 -08:00
// @ts-expect-error
2025-01-14 17:43:47 -08:00
const bad1 : string = await test . step . skip ( 'my step' , ( ) = > { return '' ; } ) ;
const good : void = await test . step . skip ( 'my step' , async ( ) = > {
2024-12-17 11:17:22 -08:00
return 2024 ;
} ) ;
} ) ;
`
} ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
} ) ;
2025-04-17 16:11:06 +02:00
test ( 'calling custom matcher on expect.poll should return Promise' , { annotation : { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/35635' } } , async ( { runTSC } ) = > {
const result = await runTSC ( {
'a.spec.ts' : `
import { test , expect as baseExpect } from '@playwright/test' ;
const expect = baseExpect . extend ( {
toBeFoo ( actual ) {
return {
pass : actual === 'foo' ,
message : ( ) = > 'not foo!' ,
} ;
}
} ) ;
test ( 'test' , async ( ) = > {
const pollingPromise : Promise < any > = expect . poll ( ( ) = > 'foo' ) . toBeFoo ( ) ;
await pollingPromise ;
} ) ;
`
} ) ;
expect ( result . exitCode ) . toBe ( 0 ) ;
} ) ;