Skip to content

Commit 8a50a9f

Browse files
committed
feat(fixture): add screen fixture that combines Page and Queries
This will likely replace the `queries` fixture when the `Locator` fixture stuff is officially released
1 parent 6d87bc0 commit 8a50a9f

File tree

6 files changed

+67
-6
lines changed

6 files changed

+67
-6
lines changed

lib/fixture/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@ import {Fixtures} from '@playwright/test'
22

33
import type {Queries as ElementHandleQueries} from './element-handle'
44
import {queriesFixture as elementHandleQueriesFixture} from './element-handle'
5-
import type {Queries as LocatorQueries} from './locator'
65
import {
6+
Queries as LocatorQueries,
77
installTestingLibraryFixture,
88
queriesFixture as locatorQueriesFixture,
99
options,
1010
queriesFor,
1111
registerSelectorsFixture,
12+
screenFixture,
1213
withinFixture,
1314
} from './locator'
14-
import type {Config} from './types'
15+
import type {Config, Screen} from './types'
1516
import {Within} from './types'
1617

1718
const elementHandleFixtures: Fixtures = {queries: elementHandleQueriesFixture}
1819
const locatorFixtures: Fixtures = {
1920
queries: locatorQueriesFixture,
21+
screen: screenFixture,
2022
within: withinFixture,
2123
registerSelectors: registerSelectorsFixture,
2224
installTestingLibrary: installTestingLibraryFixture,
@@ -29,6 +31,7 @@ interface ElementHandleFixtures {
2931

3032
interface LocatorFixtures extends Partial<Config> {
3133
queries: LocatorQueries
34+
screen: Screen
3235
within: Within
3336
registerSelectors: void
3437
installTestingLibrary: void

lib/fixture/locator/fixtures.ts

+22-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import {selectors} from '@playwright/test'
44
import type {
55
Config,
66
LocatorQueries as Queries,
7+
Screen,
78
SelectorEngine,
89
SynchronousQuery,
910
Within,
1011
} from '../types'
1112

12-
import {buildTestingLibraryScript, queryToSelector} from './helpers'
13-
import {isAllQuery, queriesFor, synchronousQueryNames} from './queries'
13+
import {buildTestingLibraryScript, includes, queryToSelector} from './helpers'
14+
import {allQueryNames, isAllQuery, queriesFor, synchronousQueryNames} from './queries'
1415

1516
type TestArguments = PlaywrightTestArgs & Config
1617

@@ -29,6 +30,24 @@ const queriesFixture: TestFixture<Queries, TestArguments> = async (
2930
use,
3031
) => use(queriesFor(page, {asyncUtilExpectedState, asyncUtilTimeout}))
3132

33+
const screenFixture: TestFixture<Screen, TestArguments> = async (
34+
{page, asyncUtilExpectedState, asyncUtilTimeout},
35+
use,
36+
) => {
37+
const queries = queriesFor(page, {asyncUtilExpectedState, asyncUtilTimeout})
38+
const revocable = Proxy.revocable(page, {
39+
get(target, property, receiver) {
40+
return includes(allQueryNames, property)
41+
? queries[property]
42+
: Reflect.get(target, property, receiver)
43+
},
44+
})
45+
46+
await use(revocable.proxy as Screen)
47+
48+
revocable.revoke()
49+
}
50+
3251
const withinFixture: TestFixture<Within, TestArguments> = async (
3352
{asyncUtilExpectedState, asyncUtilTimeout},
3453
use,
@@ -117,6 +136,7 @@ export {
117136
options,
118137
queriesFixture,
119138
registerSelectorsFixture,
139+
screenFixture,
120140
withinFixture,
121141
}
122142
export type {Queries}

lib/fixture/locator/helpers.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,29 @@ const buildTestingLibraryScript = async ({config}: {config: Config}) => {
2222
`
2323
}
2424

25-
export {buildTestingLibraryScript, queryToSelector}
25+
/**
26+
* Alternative version of `Array.prototype.includes` that allows testing for
27+
* the existence of an item with a type that is a _superset_ of the type of the
28+
* items in the array.
29+
*
30+
* This allows us to use it to check whether an item of type `string` exists in
31+
* an array of string literals (e.g: `['foo', 'bar'] as const`) without TypeScript
32+
* complaining. It will, however, throw a compiler error if you try to pass an item
33+
* of type `number`.
34+
*
35+
* @example
36+
* const things = ['foo', 'bar'] as const;
37+
*
38+
* // error
39+
* const hasThing = (t: string) => things.includes(t);
40+
*
41+
* // compiles
42+
* const hasThing = (t: string) => includes(things, t);
43+
*
44+
* @param array array to search
45+
* @param item item to search for
46+
*/
47+
const includes = <T extends U, U>(array: ReadonlyArray<T>, item: U): item is T =>
48+
array.includes(item as T)
49+
50+
export {buildTestingLibraryScript, includes, queryToSelector}

lib/fixture/locator/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export {
33
options,
44
queriesFixture,
55
registerSelectorsFixture,
6+
screenFixture,
67
withinFixture,
78
} from './fixtures'
89
export type {Queries} from './fixtures'

lib/fixture/types.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Locator} from '@playwright/test'
1+
import {Locator, Page} from '@playwright/test'
22
import type * as TestingLibraryDom from '@testing-library/dom'
33
import {queries} from '@testing-library/dom'
44

@@ -51,7 +51,9 @@ type KebabCase<S> = S extends `${infer C}${infer T}`
5151
: S
5252

5353
export type LocatorQueries = {[K in keyof Queries]: ConvertQuery<Queries[K]>}
54+
5455
export type Within = (locator: Locator) => LocatorQueries
56+
export type Screen = LocatorQueries & Page
5557

5658
export type Query = keyof Queries
5759

test/fixture/locators.test.ts

+10
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,16 @@ test.describe('lib/fixture.ts (locators)', () => {
170170
})
171171
})
172172
})
173+
174+
test('screen fixture responds to Page and Query methods', async ({screen}) => {
175+
const locator = screen.getByRole('button', {name: /getBy.*Test/})
176+
expect(await locator.textContent()).toEqual('getByRole Test')
177+
178+
await screen.goto(`file://${path.join(__dirname, '../fixtures/late-page.html')}`)
179+
180+
const delayedLocator = await screen.findByText('Loaded!', undefined, {timeout: 3000})
181+
expect(await delayedLocator.textContent()).toEqual('Loaded!')
182+
})
173183
})
174184

175185
test.describe('deferred page', () => {

0 commit comments

Comments
 (0)