diff --git a/README.md b/README.md index fd43d85..ce9df8f 100644 --- a/README.md +++ b/README.md @@ -73,30 +73,47 @@ Unique methods, not part of `@testing-library/dom` - `queryAllByPlaceholderText` - `getByPlaceholderText` - `getAllByPlaceholderText` + - `findByPlaceholderText` + - `findAllByPlaceholderText` - `queryByText` - `queryAllByText` - `getByText` - `getAllByText` + - `findByText` + - `findAllByText` - `queryByLabelText` - `queryAllByLabelText` - `getByLabelText` - `getAllByLabelText` + - `findByLabelText` + - `findAllByLabelText` - `queryByAltText` - `queryAllByAltText` - `getByAltText` - `getAllByAltText` + - `findByAltText` + - `findAllByAltText` - `queryByTestId` - `queryAllByTestId` - `getByTestId` - `getAllByTestId` + - `findByTestId` + - `findAllByTestId` - `queryByTitle` - `queryAllByTitle` - `getByTitle` - `getAllByTitle` + - `findByTitle` + - `findAllByTitle` + - `queryByDisplayValue`, + - `queryAllByDisplayValue`, + - `getByDisplayValue`, + - `getAllByDisplayValue`, + - `findByDisplayValue`, + - `findAllByDisplayValue`, ## Known Limitations - -- `waitForElement` method is not exposed. Puppeteer has its own set of wait utilities that somewhat conflict with the style used in `@testing-library/dom`. See [#3](https://github.com/testing-library/pptr-testing-library/issues/3). +- Async utilities `waitForElement`, `waitForElementToBeRemoved` and `waitForDomChange` are not exposed. Consider using a `find*` query. - `fireEvent` method is not exposed, use puppeteer's built-ins instead. - `expect` assertion extensions are not available. diff --git a/lib/index.ts b/lib/index.ts index 510189f..7a85442 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -161,41 +161,57 @@ export function getQueriesForElement( 'queryAllByPlaceholderText', 'getByPlaceholderText', 'getAllByPlaceholderText', + 'findByPlaceholderText', + 'findAllByPlaceholderText', 'queryByText', 'queryAllByText', 'getByText', 'getAllByText', + 'findByText', + 'findAllByText', 'queryByLabelText', 'queryAllByLabelText', 'getByLabelText', 'getAllByLabelText', + 'findByLabelText', + 'findAllByLabelText', 'queryByAltText', 'queryAllByAltText', 'getByAltText', 'getAllByAltText', + 'findByAltText', + 'findAllByAltText', 'queryByTestId', 'queryAllByTestId', 'getByTestId', 'getAllByTestId', + 'findByTestId', + 'findAllByTestId', 'queryByTitle', 'queryAllByTitle', 'getByTitle', 'getAllByTitle', + 'findByTitle', + 'findAllByTitle', 'queryByRole', 'queryAllByRole', 'getByRole', 'getAllByRole', + 'findByRole', + 'findAllByRole', 'queryByDisplayValue', 'queryAllByDisplayValue', 'getByDisplayValue', 'getAllByDisplayValue', + 'findByDisplayValue', + 'findAllByDisplayValue', ] functionNames.forEach(functionName => { o[functionName] = createDelegateFor(functionName, contextFn) diff --git a/lib/typedefs.ts b/lib/typedefs.ts index c163154..c87810c 100644 --- a/lib/typedefs.ts +++ b/lib/typedefs.ts @@ -1,4 +1,4 @@ -import {Matcher, MatcherOptions, SelectorMatcherOptions} from '@testing-library/dom' +import {Matcher, MatcherOptions, SelectorMatcherOptions, WaitForElementOptions} from '@testing-library/dom' import {ElementHandle} from 'puppeteer' type Element = ElementHandle @@ -8,54 +8,144 @@ interface IQueryMethods { queryAllByPlaceholderText(el: Element, m: Matcher, opts?: MatcherOptions): Promise getByPlaceholderText(el: Element, m: Matcher, opts?: MatcherOptions): Promise getAllByPlaceholderText(el: Element, m: Matcher, opts?: MatcherOptions): Promise + findByPlaceholderText( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise + findAllByPlaceholderText( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise queryByText(el: Element, m: Matcher, opts?: SelectorMatcherOptions): Promise queryAllByText(el: Element, m: Matcher, opts?: SelectorMatcherOptions): Promise getByText(el: Element, m: Matcher, opts?: SelectorMatcherOptions): Promise getAllByText(el: Element, m: Matcher, opts?: SelectorMatcherOptions): Promise + findByText( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise + findAllByText( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise queryByLabelText(el: Element, m: Matcher, opts?: SelectorMatcherOptions): Promise queryAllByLabelText(el: Element, m: Matcher, opts?: SelectorMatcherOptions): Promise getByLabelText(el: Element, m: Matcher, opts?: SelectorMatcherOptions): Promise getAllByLabelText(el: Element, m: Matcher, opts?: SelectorMatcherOptions): Promise + findByLabelText( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise + findAllByLabelText( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise queryByAltText(el: Element, m: Matcher, opts?: MatcherOptions): Promise queryAllByAltText(el: Element, m: Matcher, opts?: MatcherOptions): Promise getByAltText(el: Element, m: Matcher, opts?: MatcherOptions): Promise getAllByAltText(el: Element, m: Matcher, opts?: MatcherOptions): Promise + findByAltText( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise + findAllByAltText( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise queryByTestId(el: Element, m: Matcher, opts?: MatcherOptions): Promise queryAllByTestId(el: Element, m: Matcher, opts?: MatcherOptions): Promise getByTestId(el: Element, m: Matcher, opts?: MatcherOptions): Promise getAllByTestId(el: Element, m: Matcher, opts?: MatcherOptions): Promise + findByTestId( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise + findAllByTestId( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise queryByTitle(el: Element, m: Matcher, opts?: MatcherOptions): Promise queryAllByTitle(el: Element, m: Matcher, opts?: MatcherOptions): Promise getByTitle(el: Element, m: Matcher, opts?: MatcherOptions): Promise getAllByTitle(el: Element, m: Matcher, opts?: MatcherOptions): Promise + findByTitle( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise + findAllByTitle( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise queryByRole(el: Element, m: Matcher, opts?: MatcherOptions): Promise queryAllByRole(el: Element, m: Matcher, opts?: MatcherOptions): Promise getByRole(el: Element, m: Matcher, opts?: MatcherOptions): Promise getAllByRole(el: Element, m: Matcher, opts?: MatcherOptions): Promise + findByRole( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise + findAllByRole( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise queryByDisplayValue(el: Element, m: Matcher, opts?: MatcherOptions): Promise queryAllByDisplayValue(el: Element, m: Matcher, opts?: MatcherOptions): Promise getByDisplayValue(el: Element, m: Matcher, opts?: MatcherOptions): Promise getAllByDisplayValue(el: Element, m: Matcher, opts?: MatcherOptions): Promise + findByDisplayValue( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise + findAllByDisplayValue( + el: Element, + m: Matcher, + opts?: SelectorMatcherOptions, + waitForOpts?: WaitForElementOptions): Promise } -type IScopedQueryMethods = { - [K in keyof IQueryMethods]: (m: Matcher, opts?: MatcherOptions) => ReturnType -} +export type BoundFunction = T extends ( + attribute: string, + element: Element, + text: infer P, + options: infer Q, +) => infer R + ? (text: P, options?: Q) => R + : T extends (a1: any, text: infer P, options: infer Q, waitForElementOptions: infer W) => infer R + ? (text: P, options?: Q, waitForElementOptions?: W) => R + : T extends (a1: any, text: infer P, options: infer Q) => infer R + ? (text: P, options?: Q) => R + : never +export type BoundFunctions = { [P in keyof T]: BoundFunction } -export interface IScopedQueryUtils extends IScopedQueryMethods { - getQueriesForElement(): IQueryUtils & IScopedQueryUtils +export interface IScopedQueryUtils extends BoundFunctions { + getQueriesForElement(): IScopedQueryUtils getNodeText(): Promise } export interface IQueryUtils extends IQueryMethods { - getQueriesForElement(): IQueryUtils & IScopedQueryUtils + getQueriesForElement(): IScopedQueryUtils getNodeText(el: Element): Promise } diff --git a/test/extend.test.ts b/test/extend.test.ts index 26ef087..63d6337 100644 --- a/test/extend.test.ts +++ b/test/extend.test.ts @@ -100,6 +100,29 @@ describe('lib/extend.ts', () => { expect(await queryByText('Hello h3')).toBeTruthy() }) + describe('deferred page', () => { + beforeEach(async () => { + await page.goto(`file://${path.join(__dirname, 'fixtures/late-page.html')}`) + document = await page.getDocument() + }) + + it('should handle the findBy* methods', async () => { + expect(await document.findByText('Loaded!', {}, { timeout: 7000 })).toBeTruthy() + }, 9000) + + it('should handle the findByAll* methods', async () => { + const elements = await document.findAllByText(/Hello/, {}, { timeout: 7000 }) + expect(elements).toHaveLength(2) + + const text = await Promise.all([ + page.evaluate(el => el.textContent, elements[0]), + page.evaluate(el => el.textContent, elements[1]), + ]) + + expect(text).toEqual(['Hello h1', 'Hello h2']) + }, 9000) + }) + afterAll(async () => { await browser.close() }) diff --git a/test/fixtures/late-page.html b/test/fixtures/late-page.html index e536f9c..87f5474 100644 --- a/test/fixtures/late-page.html +++ b/test/fixtures/late-page.html @@ -7,6 +7,14 @@ const loaded = document.createElement('span') loaded.textContent = 'Loaded!' document.body.appendChild(loaded) + + const heading1 = document.createElement('h1') + heading1.textContent = 'Hello h1' + document.body.appendChild(heading1) + + const heading2 = document.createElement('h2') + heading2.textContent = 'Hello h2' + document.body.appendChild(heading2) }, 5000)