mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat(expect): implement toMatchText (#7871)
This commit is contained in:
parent
34b96a5759
commit
b8dc0b9156
@ -65,7 +65,7 @@ element.click()
|
||||
```
|
||||
|
||||
```csharp
|
||||
var element = page.Finder("text=Submit");
|
||||
var element = page.Locator("text=Submit");
|
||||
await element.HoverAsync();
|
||||
await element.ClickAsync();
|
||||
```
|
||||
@ -332,7 +332,7 @@ assert tweets.evaluate("node => node.innerText") == "10 retweets"
|
||||
```
|
||||
|
||||
```csharp
|
||||
var tweets = page.Finder(".tweet .retweets");
|
||||
var tweets = page.Locator(".tweet .retweets");
|
||||
Assert.Equals("10 retweets", await tweets.EvaluateAsync("node => node.innerText"));
|
||||
```
|
||||
|
||||
@ -817,7 +817,7 @@ element.press("Enter")
|
||||
```
|
||||
|
||||
```csharp
|
||||
var element = page.Finder("input");
|
||||
var element = page.Locator("input");
|
||||
await element.TypeAsync("some text");
|
||||
await element.PressAsync("Enter");
|
||||
```
|
||||
@ -856,19 +856,3 @@ When all steps combined have not finished during the specified [`option: timeout
|
||||
### option: Locator.uncheck.noWaitAfter = %%-input-no-wait-after-%%
|
||||
### option: Locator.uncheck.timeout = %%-input-timeout-%%
|
||||
### option: Locator.uncheck.trial = %%-input-trial-%%
|
||||
|
||||
## async method: Locator.waitFor
|
||||
- returns: <[null]|[ElementHandle]<[HTMLElement]|[SVGElement]>>
|
||||
|
||||
Returns when element specified by selector satisfies [`option: state`] option. Returns `null` if waiting for `hidden` or `detached`.
|
||||
|
||||
Wait for the element to satisfy [`option: state`] option (either appear/disappear from dom, or become
|
||||
visible/hidden). If at the moment of calling the method it already satisfies the condition, the method
|
||||
will return immediately. If the selector doesn't satisfy the condition for the [`option: timeout`] milliseconds, the
|
||||
function will throw.
|
||||
|
||||
This method works across navigations.
|
||||
|
||||
### option: Locator.waitFor.state = %%-wait-for-selector-state-%%
|
||||
### option: Locator.waitFor.timeout = %%-input-timeout-%%
|
||||
|
||||
|
||||
@ -22,14 +22,17 @@ import { monotonicTime } from '../utils/utils';
|
||||
import { ElementHandle } from './elementHandle';
|
||||
import { Frame } from './frame';
|
||||
import { FilePayload, Rect, SelectOption, SelectOptionOptions, TimeoutOptions } from './types';
|
||||
import { TimeoutSettings } from '../utils/timeoutSettings';
|
||||
|
||||
export class Locator implements api.Locator {
|
||||
private _frame: Frame;
|
||||
private _selector: string;
|
||||
private _visibleSelector: string;
|
||||
private _timeoutSettings: TimeoutSettings;
|
||||
|
||||
constructor(frame: Frame, selector: string) {
|
||||
this._frame = frame;
|
||||
this._timeoutSettings = this._frame.page()._timeoutSettings;
|
||||
this._selector = selector;
|
||||
this._visibleSelector = selector + ' >> _visible=true';
|
||||
}
|
||||
@ -202,12 +205,6 @@ export class Locator implements api.Locator {
|
||||
return this._frame.uncheck(this._visibleSelector, { strict: true, ...options });
|
||||
}
|
||||
|
||||
waitFor(options: channels.FrameWaitForSelectorOptions & { state: 'attached' | 'visible' }): Promise<ElementHandle<SVGElement | HTMLElement>>;
|
||||
waitFor(options?: channels.FrameWaitForSelectorOptions): Promise<ElementHandle<SVGElement | HTMLElement> | null>;
|
||||
async waitFor(options?: channels.FrameWaitForSelectorOptions): Promise<ElementHandle<SVGElement | HTMLElement> | null> {
|
||||
return this._frame.waitForSelector(this._visibleSelector, { strict: true, ...options });
|
||||
}
|
||||
|
||||
[(util.inspect as any).custom]() {
|
||||
return this.toString();
|
||||
}
|
||||
|
||||
@ -16,46 +16,9 @@
|
||||
|
||||
import type { Expect } from './types';
|
||||
import expectLibrary from 'expect';
|
||||
import { currentTestInfo } from './globals';
|
||||
import { compare } from './golden';
|
||||
import { toMatchSnapshot } from './matchers/toMatchSnapshot';
|
||||
import { toMatchText, toHaveText } from './matchers/toMatchText';
|
||||
|
||||
export const expect: Expect = expectLibrary;
|
||||
|
||||
function toMatchSnapshot(this: ReturnType<Expect['getState']>, received: Buffer | string, nameOrOptions: string | { name: string, threshold?: number }, optOptions: { threshold?: number } = {}) {
|
||||
let options: { name: string, threshold?: number };
|
||||
const testInfo = currentTestInfo();
|
||||
if (!testInfo)
|
||||
throw new Error(`toMatchSnapshot() must be called during the test`);
|
||||
if (typeof nameOrOptions === 'string')
|
||||
options = { name: nameOrOptions, ...optOptions };
|
||||
else
|
||||
options = { ...nameOrOptions };
|
||||
if (!options.name)
|
||||
throw new Error(`toMatchSnapshot() requires a "name" parameter`);
|
||||
|
||||
const projectThreshold = testInfo.project.expect?.toMatchSnapshot?.threshold;
|
||||
if (options.threshold === undefined && projectThreshold !== undefined)
|
||||
options.threshold = projectThreshold;
|
||||
|
||||
const withNegateComparison = this.isNot;
|
||||
const { pass, message, expectedPath, actualPath, diffPath, mimeType } = compare(
|
||||
received,
|
||||
options.name,
|
||||
testInfo.snapshotPath,
|
||||
testInfo.outputPath,
|
||||
testInfo.config.updateSnapshots,
|
||||
withNegateComparison,
|
||||
options
|
||||
);
|
||||
const contentType = mimeType || 'application/octet-stream';
|
||||
if (expectedPath)
|
||||
testInfo.attachments.push({ name: 'expected', contentType, path: expectedPath });
|
||||
if (actualPath)
|
||||
testInfo.attachments.push({ name: 'actual', contentType, path: actualPath });
|
||||
if (diffPath)
|
||||
testInfo.attachments.push({ name: 'diff', contentType, path: diffPath });
|
||||
return { pass, message: () => message };
|
||||
}
|
||||
|
||||
expectLibrary.extend({ toMatchSnapshot });
|
||||
expectLibrary.setState({ expand: false });
|
||||
export const expect: Expect = expectLibrary as any;
|
||||
expectLibrary.setState({ expand: false });
|
||||
expectLibrary.extend({ toMatchSnapshot, toMatchText, toHaveText });
|
||||
|
||||
@ -21,8 +21,8 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import jpeg from 'jpeg-js';
|
||||
import pixelmatch from 'pixelmatch';
|
||||
import { diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL } from '../third_party/diff_match_patch';
|
||||
import { UpdateSnapshots } from './types';
|
||||
import { diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL } from '../../third_party/diff_match_patch';
|
||||
import { UpdateSnapshots } from '../types';
|
||||
|
||||
// Note: we require the pngjs version of pixelmatch to avoid version mismatches.
|
||||
const { PNG } = require(require.resolve('pngjs', { paths: [require.resolve('pixelmatch')] }));
|
||||
56
src/test/matchers/toMatchSnapshot.ts
Normal file
56
src/test/matchers/toMatchSnapshot.ts
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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 type { Expect } from '../types';
|
||||
import { currentTestInfo } from '../globals';
|
||||
import { compare } from './golden';
|
||||
import { SyncExpectationResult } from 'expect/build/types';
|
||||
|
||||
export function toMatchSnapshot(this: ReturnType<Expect['getState']>, received: Buffer | string, nameOrOptions: string | { name: string, threshold?: number }, optOptions: { threshold?: number } = {}): SyncExpectationResult {
|
||||
let options: { name: string, threshold?: number };
|
||||
const testInfo = currentTestInfo();
|
||||
if (!testInfo)
|
||||
throw new Error(`toMatchSnapshot() must be called during the test`);
|
||||
if (typeof nameOrOptions === 'string')
|
||||
options = { name: nameOrOptions, ...optOptions };
|
||||
else
|
||||
options = { ...nameOrOptions };
|
||||
if (!options.name)
|
||||
throw new Error(`toMatchSnapshot() requires a "name" parameter`);
|
||||
|
||||
const projectThreshold = testInfo.project.expect?.toMatchSnapshot?.threshold;
|
||||
if (options.threshold === undefined && projectThreshold !== undefined)
|
||||
options.threshold = projectThreshold;
|
||||
|
||||
const withNegateComparison = this.isNot;
|
||||
const { pass, message, expectedPath, actualPath, diffPath, mimeType } = compare(
|
||||
received,
|
||||
options.name,
|
||||
testInfo.snapshotPath,
|
||||
testInfo.outputPath,
|
||||
testInfo.config.updateSnapshots,
|
||||
withNegateComparison,
|
||||
options
|
||||
);
|
||||
const contentType = mimeType || 'application/octet-stream';
|
||||
if (expectedPath)
|
||||
testInfo.attachments.push({ name: 'expected', contentType, path: expectedPath });
|
||||
if (actualPath)
|
||||
testInfo.attachments.push({ name: 'actual', contentType, path: actualPath });
|
||||
if (diffPath)
|
||||
testInfo.attachments.push({ name: 'diff', contentType, path: diffPath });
|
||||
return { pass, message: () => message || '' };
|
||||
}
|
||||
140
src/test/matchers/toMatchText.ts
Normal file
140
src/test/matchers/toMatchText.ts
Normal file
@ -0,0 +1,140 @@
|
||||
/**
|
||||
* 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 {
|
||||
printReceivedStringContainExpectedResult,
|
||||
printReceivedStringContainExpectedSubstring
|
||||
} from 'expect/build/print';
|
||||
|
||||
import {
|
||||
EXPECTED_COLOR,
|
||||
getLabelPrinter,
|
||||
matcherErrorMessage,
|
||||
matcherHint, MatcherHintOptions,
|
||||
printExpected,
|
||||
printReceived,
|
||||
printWithType,
|
||||
} from 'jest-matcher-utils';
|
||||
import { Locator } from '../../..';
|
||||
import { currentTestInfo } from '../globals';
|
||||
import type { Expect } from '../types';
|
||||
import { monotonicTime, pollUntilDeadline } from '../util';
|
||||
|
||||
async function toMatchTextImpl(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: Locator,
|
||||
expected: string | RegExp,
|
||||
exactMatch: boolean,
|
||||
options: { timeout?: number, useInnerText?: boolean } = {},
|
||||
) {
|
||||
const testInfo = currentTestInfo();
|
||||
if (!testInfo)
|
||||
throw new Error(`toMatchSnapshot() must be called during the test`);
|
||||
|
||||
const matcherName = exactMatch ? 'toHaveText' : 'toMatchText';
|
||||
const matcherOptions: MatcherHintOptions = {
|
||||
isNot: this.isNot,
|
||||
promise: this.promise,
|
||||
};
|
||||
|
||||
if (
|
||||
!(typeof expected === 'string') &&
|
||||
!(expected && typeof expected.test === 'function')
|
||||
) {
|
||||
throw new Error(
|
||||
matcherErrorMessage(
|
||||
matcherHint(matcherName, undefined, undefined, matcherOptions),
|
||||
`${EXPECTED_COLOR(
|
||||
'expected',
|
||||
)} value must be a string or regular expression`,
|
||||
printWithType('Expected', expected, printExpected),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
let received: string;
|
||||
let pass = false;
|
||||
const timeout = options.timeout === 0 ? 0 : options.timeout || testInfo.timeout;
|
||||
const deadline = timeout ? monotonicTime() + timeout : 0;
|
||||
|
||||
try {
|
||||
await pollUntilDeadline(async () => {
|
||||
received = options?.useInnerText ? await locator.innerText() : await locator.textContent() || '';
|
||||
if (exactMatch)
|
||||
pass = expected === received;
|
||||
else
|
||||
pass = typeof expected === 'string' ? received.includes(expected) : new RegExp(expected).test(received);
|
||||
return pass === !matcherOptions.isNot;
|
||||
}, deadline, 100);
|
||||
} catch (e) {
|
||||
pass = false;
|
||||
}
|
||||
|
||||
const stringSubstring = exactMatch ? 'string' : 'substring';
|
||||
const message = pass
|
||||
? () =>
|
||||
typeof expected === 'string'
|
||||
? matcherHint(matcherName, undefined, undefined, matcherOptions) +
|
||||
'\n\n' +
|
||||
`Expected ${stringSubstring}: not ${printExpected(expected)}\n` +
|
||||
`Received string: ${printReceivedStringContainExpectedSubstring(
|
||||
received,
|
||||
received.indexOf(expected),
|
||||
expected.length,
|
||||
)}`
|
||||
: matcherHint(matcherName, undefined, undefined, matcherOptions) +
|
||||
'\n\n' +
|
||||
`Expected pattern: not ${printExpected(expected)}\n` +
|
||||
`Received string: ${printReceivedStringContainExpectedResult(
|
||||
received,
|
||||
typeof expected.exec === 'function'
|
||||
? expected.exec(received)
|
||||
: null,
|
||||
)}`
|
||||
: () => {
|
||||
const labelExpected = `Expected ${typeof expected === 'string' ? stringSubstring : 'pattern'
|
||||
}`;
|
||||
const labelReceived = 'Received string';
|
||||
const printLabel = getLabelPrinter(labelExpected, labelReceived);
|
||||
|
||||
return (
|
||||
matcherHint(matcherName, undefined, undefined, matcherOptions) +
|
||||
'\n\n' +
|
||||
`${printLabel(labelExpected)}${printExpected(expected)}\n` +
|
||||
`${printLabel(labelReceived)}${printReceived(received)}`
|
||||
);
|
||||
};
|
||||
|
||||
return { message, pass };
|
||||
}
|
||||
|
||||
export async function toMatchText(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: Locator,
|
||||
expected: string | RegExp,
|
||||
options?: { timeout?: number, useInnerText?: boolean },
|
||||
) {
|
||||
return toMatchTextImpl.call(this, locator, expected, false, options);
|
||||
}
|
||||
|
||||
export async function toHaveText(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: Locator,
|
||||
expected: string,
|
||||
options?: { timeout?: number, useInnerText?: boolean },
|
||||
) {
|
||||
return toMatchTextImpl.call(this, locator, expected, true, options);
|
||||
}
|
||||
@ -18,6 +18,7 @@ import util from 'util';
|
||||
import path from 'path';
|
||||
import type { TestError, Location } from './types';
|
||||
import { default as minimatch } from 'minimatch';
|
||||
import { TimeoutError } from '../utils/errors';
|
||||
|
||||
export class DeadlineRunner<T> {
|
||||
private _timer: NodeJS.Timer | undefined;
|
||||
@ -69,6 +70,20 @@ export async function raceAgainstDeadline<T>(promise: Promise<T>, deadline: numb
|
||||
return (new DeadlineRunner(promise, deadline)).result;
|
||||
}
|
||||
|
||||
export async function pollUntilDeadline(func: () => Promise<boolean>, deadline: number, delay: number): Promise<void> {
|
||||
while (true) {
|
||||
if (await func())
|
||||
return;
|
||||
|
||||
const timeUntilDeadline = deadline ? deadline - monotonicTime() : Number.MAX_VALUE;
|
||||
if (timeUntilDeadline > 0)
|
||||
await new Promise(f => setTimeout(f, Math.min(timeUntilDeadline, delay)));
|
||||
else
|
||||
throw new TimeoutError('Timed out while waiting for condition to be met');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function serializeError(error: Error | any): TestError {
|
||||
if (error instanceof Error) {
|
||||
return {
|
||||
|
||||
@ -61,28 +61,6 @@ it('should type', async ({ page }) => {
|
||||
expect(await page.$eval('input', input => input.value)).toBe('hello');
|
||||
});
|
||||
|
||||
it('should wait for visible', async ({ page }) => {
|
||||
async function giveItAChanceToResolve() {
|
||||
for (let i = 0; i < 5; i++)
|
||||
await page.evaluate(() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f))));
|
||||
}
|
||||
|
||||
await page.setContent(`<div id='div' style='display:none'>content</div>`);
|
||||
const div = page.locator('div');
|
||||
let done = false;
|
||||
const promise = div.waitFor({ state: 'visible' }).then(() => done = true);
|
||||
await giveItAChanceToResolve();
|
||||
expect(done).toBe(false);
|
||||
await page.evaluate(() => (window as any).div.style.display = 'block');
|
||||
await promise;
|
||||
});
|
||||
|
||||
it('should wait for already visible', async ({ page }) => {
|
||||
await page.setContent(`<div>content</div>`);
|
||||
const div = page.locator('div');
|
||||
await div.waitFor({ state: 'visible' });
|
||||
});
|
||||
|
||||
it('should take screenshot', async ({ page, server, browserName, headless, isAndroid }) => {
|
||||
it.skip(browserName === 'firefox' && !headless);
|
||||
it.skip(isAndroid, 'Different dpr. Remove after using 1x scale for screenshots.');
|
||||
|
||||
110
tests/playwright-test/playwright.expect.text.spec.ts
Normal file
110
tests/playwright-test/playwright.expect.text.spec.ts
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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, stripAscii } from './playwright-test-fixtures';
|
||||
|
||||
test('should support toMatchText', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
|
||||
test('pass', async ({ page }) => {
|
||||
await page.setContent('<div id=node>Text content</div>');
|
||||
const handle = page.locator('#node');
|
||||
await expect(handle).toMatchText(/Text/);
|
||||
});
|
||||
|
||||
test('fail', async ({ page }) => {
|
||||
await page.setContent('<div id=node>Text content</div>');
|
||||
const handle = page.locator('#node');
|
||||
await expect(handle).toMatchText(/Text 2/, { timeout: 100 });
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
const output = stripAscii(result.output);
|
||||
expect(output).toContain('Error: expect(received).toMatchText(expected)');
|
||||
expect(output).toContain('Expected pattern: /Text 2/');
|
||||
expect(output).toContain('Received string: "Text content"');
|
||||
expect(output).toContain('expect(handle).toMatchText');
|
||||
expect(result.passed).toBe(1);
|
||||
expect(result.failed).toBe(1);
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
test('should support toHaveText', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
|
||||
test('pass', async ({ page }) => {
|
||||
await page.setContent('<div id=node>Text content</div>');
|
||||
const handle = page.locator('#node');
|
||||
await expect(handle).toHaveText('Text content');
|
||||
});
|
||||
|
||||
test('fail', async ({ page }) => {
|
||||
await page.setContent('<div id=node>Text content</div>');
|
||||
const handle = page.locator('#node');
|
||||
await expect(handle).toHaveText('Text', { timeout: 100 });
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
const output = stripAscii(result.output);
|
||||
expect(output).toContain('Error: expect(received).toHaveText(expected)');
|
||||
expect(output).toContain('Expected string: "Text"');
|
||||
expect(output).toContain('Received string: "Text content"');
|
||||
expect(output).toContain('expect(handle).toHaveText');
|
||||
expect(result.passed).toBe(1);
|
||||
expect(result.failed).toBe(1);
|
||||
expect(result.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
test('should support toMatchText eventually', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
|
||||
test('pass eventually', async ({ page }) => {
|
||||
await page.setContent('<div id=node>Text content</div>');
|
||||
const handle = page.locator('#node');
|
||||
await Promise.all([
|
||||
expect(handle).toMatchText(/Text 2/),
|
||||
page.waitForTimeout(1000).then(() => handle.evaluate(element => element.textContent = 'Text 2 content')),
|
||||
]);
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
expect(result.passed).toBe(1);
|
||||
expect(result.failed).toBe(0);
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test('should support toMatchText with innerText', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
|
||||
test('pass', async ({ page }) => {
|
||||
await page.setContent('<div id=node>Text content</div>');
|
||||
const handle = page.locator('#node');
|
||||
await expect(handle).toHaveText('Text content', { useInnerText: true });
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
expect(result.passed).toBe(1);
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
12
types/testExpect.d.ts
vendored
12
types/testExpect.d.ts
vendored
@ -35,7 +35,7 @@ type OverriddenExpectProperties =
|
||||
'rejects' |
|
||||
'toMatchInlineSnapshot' |
|
||||
'toThrowErrorMatchingInlineSnapshot' |
|
||||
'toMatchSnapshot' |
|
||||
'toMatchSnapshot' |
|
||||
'toThrowErrorMatchingSnapshot';
|
||||
|
||||
declare global {
|
||||
@ -68,6 +68,16 @@ declare global {
|
||||
toMatchSnapshot(name: string, options?: {
|
||||
threshold?: number
|
||||
}): R;
|
||||
|
||||
/**
|
||||
* Asserts element's exact text content.
|
||||
*/
|
||||
toHaveText(expected: string, options?: { timeout?: number, useInnerText?: boolean }): Promise<R>;
|
||||
|
||||
/**
|
||||
* Asserts element's text content matches given pattern or contains given substring.
|
||||
*/
|
||||
toMatchText(expected: string | RegExp, options?: { timeout?: number, useInnerText?: boolean }): Promise<R>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
types/types.d.ts
vendored
34
types/types.d.ts
vendored
@ -8036,39 +8036,7 @@ export interface Locator {
|
||||
* `false`. Useful to wait until the element is ready for the action without performing it.
|
||||
*/
|
||||
trial?: boolean;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns when element specified by selector satisfies `state` option. Returns `null` if waiting for `hidden` or
|
||||
* `detached`.
|
||||
*
|
||||
* Wait for the element to satisfy `state` option (either appear/disappear from dom, or become visible/hidden). If at the
|
||||
* moment of calling the method it already satisfies the condition, the method will return immediately. If the selector
|
||||
* doesn't satisfy the condition for the `timeout` milliseconds, the function will throw.
|
||||
*
|
||||
* This method works across navigations.
|
||||
* @param options
|
||||
*/
|
||||
waitFor(options?: {
|
||||
/**
|
||||
* Defaults to `'visible'`. Can be either:
|
||||
* - `'attached'` - wait for element to be present in DOM.
|
||||
* - `'detached'` - wait for element to not be present in DOM.
|
||||
* - `'visible'` - wait for element to have non-empty bounding box and no `visibility:hidden`. Note that element without
|
||||
* any content or with `display:none` has an empty bounding box and is not considered visible.
|
||||
* - `'hidden'` - wait for element to be either detached from DOM, or have an empty bounding box or `visibility:hidden`.
|
||||
* This is opposite to the `'visible'` option.
|
||||
*/
|
||||
state?: "attached"|"detached"|"visible"|"hidden";
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by
|
||||
* using the
|
||||
* [browserContext.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-timeout)
|
||||
* or [page.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-timeout) methods.
|
||||
*/
|
||||
timeout?: number;
|
||||
}): Promise<null|ElementHandle<HTMLElement|SVGElement>>;}
|
||||
}): Promise<void>;}
|
||||
|
||||
/**
|
||||
* BrowserType provides methods to launch a specific browser instance or connect to an existing one. The following is a
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user