mirror of
https://github.com/microsoft/playwright.git
synced 2025-01-05 02:02:05 +03:00
feat: support experimental doc entries (#13446)
feat: support experimental doc entries - Params/options/members are marked as experimental in the docs. - `experimental.d.ts` is generated that contains all types and includes experimental features. - `experimental.d.ts` is references in our tests so that we can test experimental features. - `fonts` option is restored as experimental.
This commit is contained in:
parent
166675b9c1
commit
20dcc45afa
@ -960,6 +960,8 @@ An object which specifies clipping of the resulting image. Should have the follo
|
||||
When set to `"css"`, screenshot will have a single pixel per each css pixel on the page. For high-dpi devices, this will keep screenshots small. Using `"device"` option will produce a single pixel per each device pixel, so screenhots of high-dpi devices will be twice as large or even larger. Defaults to `"device"`.
|
||||
|
||||
## screenshot-option-fonts
|
||||
* langs: js
|
||||
* experimental
|
||||
- `fonts` <[ScreenshotFonts]<"ready"|"nowait">>
|
||||
|
||||
When set to `"ready"`, screenshot will wait for [`document.fonts.ready`](https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready) promise to resolve in all frames. Defaults to `"nowait"`.
|
||||
@ -975,6 +977,7 @@ When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`,
|
||||
- %%-screenshot-option-quality-%%
|
||||
- %%-screenshot-option-path-%%
|
||||
- %%-screenshot-option-scale-%%
|
||||
- %%-screenshot-option-fonts-%%
|
||||
- %%-screenshot-option-caret-%%
|
||||
- %%-screenshot-option-type-%%
|
||||
- %%-screenshot-option-mask-%%
|
||||
|
@ -36,7 +36,9 @@
|
||||
"./lib/utils/timeoutRunner": "./lib/utils/timeoutRunner.js",
|
||||
"./lib/remote/playwrightServer": "./lib/remote/playwrightServer.js",
|
||||
"./lib/remote/playwrightClient": "./lib/remote/playwrightClient.js",
|
||||
"./lib/server": "./lib/server/index.js"
|
||||
"./lib/server": "./lib/server/index.js",
|
||||
"./types/protocol": "./types/protocol.d.ts",
|
||||
"./types/structs": "./types/structs.d.ts"
|
||||
},
|
||||
"types": "types/types.d.ts",
|
||||
"bin": {
|
||||
|
@ -201,7 +201,6 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> implements
|
||||
selector: locator._selector,
|
||||
}));
|
||||
}
|
||||
copy.fonts = (options as any)._fonts;
|
||||
const result = await this._elementChannel.screenshot(copy);
|
||||
const buffer = Buffer.from(result.binary, 'base64');
|
||||
if (options.path) {
|
||||
|
@ -492,7 +492,6 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||
selector: locator._selector,
|
||||
}));
|
||||
}
|
||||
copy.fonts = (options as any)._fonts;
|
||||
const result = await this._channel.screenshot(copy);
|
||||
const buffer = Buffer.from(result.binary, 'base64');
|
||||
if (options.path) {
|
||||
|
@ -23,7 +23,7 @@ import type { Frame } from './frames';
|
||||
import type { ParsedSelector } from './isomorphic/selectorParser';
|
||||
import type * as types from './types';
|
||||
import type { Progress } from './progress';
|
||||
import { assert } from '../utils';
|
||||
import { assert, experimentalFeaturesEnabled } from '../utils';
|
||||
import { MultiMap } from '../utils/multimap';
|
||||
|
||||
declare global {
|
||||
@ -322,6 +322,9 @@ function trimClipToSize(clip: types.Rect, size: types.Size): types.Rect {
|
||||
}
|
||||
|
||||
function validateScreenshotOptions(options: ScreenshotOptions): 'png' | 'jpeg' {
|
||||
if (options.fonts && !experimentalFeaturesEnabled())
|
||||
throw new Error(`To use the experimental option "fonts", set PLAYWRIGHT_EXPERIMENTAL_FEATURES=1 enviroment variable.`);
|
||||
|
||||
let format: 'png' | 'jpeg' | null = null;
|
||||
// options.type takes precedence over inferring the type from options.path
|
||||
// because it may be a 0-length file with no extension created beforehand (i.e. as a temp file).
|
||||
|
2
packages/playwright-core/types/structs.d.ts
vendored
2
packages/playwright-core/types/structs.d.ts
vendored
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JSHandle, ElementHandle, Frame, Page, BrowserContext, Locator } from './types';
|
||||
import { JSHandle, ElementHandle, Frame, Page, BrowserContext } from 'playwright-core';
|
||||
|
||||
/**
|
||||
* Can be converted to JSON
|
||||
|
4
packages/playwright-core/types/types.d.ts
vendored
4
packages/playwright-core/types/types.d.ts
vendored
@ -14,12 +14,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Protocol } from './protocol';
|
||||
import { Protocol } from 'playwright-core/types/protocol';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import { EventEmitter } from 'events';
|
||||
import { Readable } from 'stream';
|
||||
import { ReadStream } from 'fs';
|
||||
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from './structs';
|
||||
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from 'playwright-core/types/structs';
|
||||
|
||||
type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
|
||||
state?: 'visible'|'attached';
|
||||
|
1
packages/playwright-test/index.d.ts
vendored
1
packages/playwright-test/index.d.ts
vendored
@ -14,6 +14,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from 'playwright-core';
|
||||
export * from './types/test';
|
||||
export { default } from './types/test';
|
||||
|
@ -308,7 +308,7 @@ export async function toHaveScreenshot(
|
||||
const [page, locator] = pageOrLocator.constructor.name === 'Page' ? [(pageOrLocator as PageEx), undefined] : [(pageOrLocator as Locator).page() as PageEx, pageOrLocator as LocatorEx];
|
||||
const screenshotOptions = {
|
||||
animations: config?.animations ?? 'disabled',
|
||||
_fonts: config?.fonts ?? 'ready',
|
||||
fonts: process.env.PLAYWRIGHT_EXPERIMENTAL_FEATURES ? (config?.fonts ?? 'ready') : undefined,
|
||||
scale: config?.scale ?? 'css',
|
||||
caret: config?.caret ?? 'hide',
|
||||
...helper.allOptions,
|
||||
|
5
packages/playwright-test/types/test.d.ts
vendored
5
packages/playwright-test/types/test.d.ts
vendored
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, Page, LaunchOptions, ViewportSize, Geolocation, HTTPCredentials, Locator, APIResponse } from 'playwright-core';
|
||||
export * from 'playwright-core';
|
||||
|
||||
export type ReporterDescription =
|
||||
['dot'] |
|
||||
@ -2917,7 +2918,7 @@ type MakeMatchers<R, T> = BaseMatchers<R, T> & {
|
||||
ExtraMatchers<T, Locator, LocatorAssertions> &
|
||||
ExtraMatchers<T, APIResponse, APIResponseAssertions>;
|
||||
|
||||
export declare type Expect = {
|
||||
export type Expect = {
|
||||
<T = unknown>(actual: T, messageOrOptions?: string | { message?: string }): MakeMatchers<void, T>;
|
||||
soft: <T = unknown>(actual: T, messageOrOptions?: string | { message?: string }) => MakeMatchers<void, T>;
|
||||
poll: <T = unknown>(actual: () => T | Promise<T>, messageOrOptions?: string | { message?: string, timeout?: number }) => BaseMatchers<Promise<void>, T> & {
|
||||
@ -2996,12 +2997,14 @@ type SupportedExpectProperties =
|
||||
'toThrow' |
|
||||
'toThrowError'
|
||||
|
||||
// --- BEGINGLOBAL ---
|
||||
declare global {
|
||||
export namespace PlaywrightTest {
|
||||
export interface Matchers<R, T = unknown> {
|
||||
}
|
||||
}
|
||||
}
|
||||
// --- ENDGLOBAL ---
|
||||
|
||||
/**
|
||||
* These tests are executed in Playwright environment that launches the browser
|
||||
|
@ -15,8 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { FullConfig, FullProject, TestStatus, TestError } from './test';
|
||||
export type { FullConfig, TestStatus, TestError } from './test';
|
||||
import type { FullConfig, FullProject, TestStatus, TestError } from '@playwright/test';
|
||||
export type { FullConfig, TestStatus, TestError } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* `Suite` is a group of tests. All tests in Playwright Test form the following hierarchy:
|
||||
|
@ -14,6 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line spaced-comment
|
||||
/// <reference path="./experimental.d.ts" />
|
||||
|
||||
import type { Fixtures } from '@playwright/test';
|
||||
import type { ChildProcess } from 'child_process';
|
||||
import { execSync, spawn } from 'child_process';
|
||||
|
20281
tests/config/experimental.d.ts
vendored
Normal file
20281
tests/config/experimental.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,8 @@ export class DriverTestMode implements TestMode {
|
||||
|
||||
async setup() {
|
||||
this._impl = await start({
|
||||
NODE_OPTIONS: undefined // Hide driver process while debugging.
|
||||
NODE_OPTIONS: undefined, // Hide driver process while debugging.
|
||||
PLAYWRIGHT_EXPERIMENTAL_FEATURES: '1',
|
||||
});
|
||||
return this._impl.playwright;
|
||||
}
|
||||
|
@ -72,6 +72,9 @@ if (mode === 'service') {
|
||||
command: 'npx playwright experimental-grid-server',
|
||||
port: 3333,
|
||||
reuseExistingServer: true,
|
||||
env: {
|
||||
PLAYWRIGHT_EXPERIMENTAL_FEATURES: '1',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -80,6 +83,9 @@ if (mode === 'service2') {
|
||||
command: 'npx playwright run-server --port=3333',
|
||||
port: 3333,
|
||||
reuseExistingServer: true,
|
||||
env: {
|
||||
PLAYWRIGHT_EXPERIMENTAL_FEATURES: '1',
|
||||
},
|
||||
};
|
||||
config.use.connectOptions = {
|
||||
wsEndpoint: 'ws://localhost:3333/',
|
||||
|
@ -785,13 +785,13 @@ it.describe('page screenshot animations', () => {
|
||||
const noIconsScreenshot = await page.screenshot();
|
||||
// Make sure screenshot times out while webfont is stalled.
|
||||
const error = await page.screenshot({
|
||||
_fonts: 'ready',
|
||||
fonts: 'ready',
|
||||
timeout: 200,
|
||||
} as any).catch(e => e);
|
||||
}).catch(e => e);
|
||||
expect(error.message).toContain('waiting for fonts to load...');
|
||||
expect(error.message).toContain('Timeout 200ms exceeded');
|
||||
const [iconsScreenshot] = await Promise.all([
|
||||
page.screenshot({ _fonts: 'ready' } as any),
|
||||
page.screenshot({ fonts: 'ready' }),
|
||||
server.serveFile(serverRequest, serverResponse),
|
||||
]);
|
||||
expect(iconsScreenshot).toMatchSnapshot('screenshot-web-font.png', {
|
||||
|
@ -63,6 +63,7 @@ test('should fail to screenshot a page with infinite animation', async ({ runInl
|
||||
test('should disable animations by default', async ({ runInlineTest }, testInfo) => {
|
||||
const cssTransitionURL = pathToFileURL(path.join(__dirname, '../assets/css-transition.html'));
|
||||
const result = await runInlineTest({
|
||||
...playwrightConfig({}),
|
||||
'a.spec.js': `
|
||||
pwt.test('is a test', async ({ page }) => {
|
||||
await page.goto('${cssTransitionURL}');
|
||||
@ -156,11 +157,7 @@ test('should report _toHaveScreenshot step with expectation name in title', asyn
|
||||
}
|
||||
module.exports = Reporter;
|
||||
`,
|
||||
'playwright.config.ts': `
|
||||
module.exports = {
|
||||
reporter: './reporter',
|
||||
};
|
||||
`,
|
||||
...playwrightConfig({ reporter: './reporter' }),
|
||||
'a.spec.js': `
|
||||
pwt.test('is a test', async ({ page }) => {
|
||||
// Named expectation.
|
||||
@ -371,8 +368,7 @@ test('should compile with different option combinations', async ({ runTSC }) =>
|
||||
maxDiffPixelRatio: 0.2,
|
||||
animations: "disabled",
|
||||
omitBackground: true,
|
||||
// TODO: uncomment when enabling "fonts".
|
||||
// fonts: "nowait",
|
||||
fonts: "nowait",
|
||||
caret: "initial",
|
||||
scale: "device",
|
||||
timeout: 1000,
|
||||
@ -401,6 +397,7 @@ test('should fail when screenshot is different size', async ({ runInlineTest })
|
||||
|
||||
test('should fail when given non-png snapshot name', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
...playwrightConfig({}),
|
||||
'a.spec.js': `
|
||||
pwt.test('is a test', async ({ page }) => {
|
||||
await expect(page)._toHaveScreenshot('snapshot.jpeg');
|
||||
@ -413,6 +410,7 @@ test('should fail when given non-png snapshot name', async ({ runInlineTest }) =
|
||||
|
||||
test('should fail when given buffer', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
...playwrightConfig({}),
|
||||
'a.spec.js': `
|
||||
pwt.test('is a test', async ({ page }) => {
|
||||
await expect(Buffer.from([1]))._toHaveScreenshot();
|
||||
@ -798,6 +796,7 @@ test('should respect maxDiffPixelRatio option', async ({ runInlineTest }) => {
|
||||
|
||||
test('should throw for invalid maxDiffPixels values', async ({ runInlineTest }) => {
|
||||
expect((await runInlineTest({
|
||||
...playwrightConfig({}),
|
||||
'a.spec.js': `
|
||||
pwt.test('is a test', async ({ page }) => {
|
||||
await expect(page)._toHaveScreenshot({
|
||||
@ -810,6 +809,7 @@ test('should throw for invalid maxDiffPixels values', async ({ runInlineTest })
|
||||
|
||||
test('should throw for invalid maxDiffPixelRatio values', async ({ runInlineTest }) => {
|
||||
expect((await runInlineTest({
|
||||
...playwrightConfig({}),
|
||||
'a.spec.js': `
|
||||
pwt.test('is a test', async ({ page }) => {
|
||||
await expect(page)._toHaveScreenshot({
|
||||
|
@ -74,7 +74,7 @@ class ApiParser {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const clazz = new Documentation.Class(extractLangs(node), name, [], extendsName, extractComments(node));
|
||||
const clazz = new Documentation.Class(extractLangs(node), extractExperimental(node), name, [], extendsName, extractComments(node));
|
||||
this.classes.set(clazz.name, clazz);
|
||||
}
|
||||
|
||||
@ -102,11 +102,11 @@ class ApiParser {
|
||||
const comments = extractComments(spec);
|
||||
let member;
|
||||
if (match[1] === 'event')
|
||||
member = Documentation.Member.createEvent(extractLangs(spec), name, returnType, comments);
|
||||
member = Documentation.Member.createEvent(extractLangs(spec), extractExperimental(spec), name, returnType, comments);
|
||||
if (match[1] === 'property')
|
||||
member = Documentation.Member.createProperty(extractLangs(spec), name, returnType, comments, !optional);
|
||||
member = Documentation.Member.createProperty(extractLangs(spec), extractExperimental(spec), name, returnType, comments, !optional);
|
||||
if (['method', 'async method', 'optional method', 'optional async method'].includes(match[1])) {
|
||||
member = Documentation.Member.createMethod(extractLangs(spec), name, [], returnType, comments);
|
||||
member = Documentation.Member.createMethod(extractLangs(spec), extractExperimental(spec), name, [], returnType, comments);
|
||||
if (match[1].includes('async'))
|
||||
member.async = true;
|
||||
if (match[1].includes('optional'))
|
||||
@ -167,7 +167,7 @@ class ApiParser {
|
||||
let options = method.argsArray.find(o => o.name === 'options');
|
||||
if (!options) {
|
||||
const type = new Documentation.Type('Object', []);
|
||||
options = Documentation.Member.createProperty({}, 'options', type, undefined, false);
|
||||
options = Documentation.Member.createProperty({}, false /* experimental */, 'options', type, undefined, false);
|
||||
method.argsArray.push(options);
|
||||
}
|
||||
const p = this.parseProperty(spec);
|
||||
@ -188,7 +188,7 @@ class ApiParser {
|
||||
const name = text.substring(0, typeStart).replace(/\`/g, '').trim();
|
||||
const comments = extractComments(spec);
|
||||
const { type, optional } = this.parseType(param);
|
||||
return Documentation.Member.createProperty(extractLangs(spec), name, type, comments, !optional);
|
||||
return Documentation.Member.createProperty(extractLangs(spec), extractExperimental(spec), name, type, comments, !optional);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -202,7 +202,7 @@ class ApiParser {
|
||||
const { name, text } = parseVariable(child.text);
|
||||
const comments = /** @type {MarkdownNode[]} */ ([{ type: 'text', text }]);
|
||||
const childType = this.parseType(child);
|
||||
properties.push(Documentation.Member.createProperty({}, name, childType.type, comments, !childType.optional));
|
||||
properties.push(Documentation.Member.createProperty({}, false /* experimental */, name, childType.type, comments, !childType.optional));
|
||||
}
|
||||
const type = Documentation.Type.parse(arg.type, properties);
|
||||
return { type, optional: arg.optional };
|
||||
@ -300,13 +300,11 @@ function applyTemplates(body, params) {
|
||||
* @returns {MarkdownNode[]}
|
||||
*/
|
||||
function extractComments(item) {
|
||||
return (item.children || []).filter(c => {
|
||||
return childrenWithoutProperties(item).filter(c => {
|
||||
if (c.type.startsWith('h'))
|
||||
return false;
|
||||
if (c.type === 'li' && c.liType === 'default')
|
||||
return false;
|
||||
if (c.type === 'li' && c.text.startsWith('langs:'))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -346,12 +344,27 @@ function extractLangs(spec) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MarkdownNode} spec
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function extractExperimental(spec) {
|
||||
for (const child of spec.children) {
|
||||
if (child.type === 'li' && child.liType === 'bullet' && child.text === 'experimental')
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MarkdownNode} spec
|
||||
* @returns {MarkdownNode[]}
|
||||
*/
|
||||
function childrenWithoutProperties(spec) {
|
||||
return spec.children.filter(c => c.liType !== 'bullet' || !c.text.startsWith('langs'));
|
||||
return (spec.children || []).filter(c => {
|
||||
const isProperty = c.liType === 'bullet' && (c.text.startsWith('langs:') || c.text === 'experimental');
|
||||
return !isProperty;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,7 +66,7 @@ class Documentation {
|
||||
* @return {!Documentation}
|
||||
*/
|
||||
mergeWith(documentation) {
|
||||
return new Documentation([...this.classesArray, ...documentation.classesArray]);
|
||||
return new Documentation([...this.classesArray, ...documentation.classesArray].map(cls => cls.clone()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,6 +108,18 @@ class Documentation {
|
||||
this.index();
|
||||
}
|
||||
|
||||
filterOutExperimental() {
|
||||
const classesArray = [];
|
||||
for (const clazz of this.classesArray) {
|
||||
if (clazz.experimental)
|
||||
continue;
|
||||
clazz.filterOutExperimental();
|
||||
classesArray.push(clazz);
|
||||
}
|
||||
this.classesArray = classesArray;
|
||||
this.index();
|
||||
}
|
||||
|
||||
index() {
|
||||
for (const cls of this.classesArray) {
|
||||
this.classes.set(cls.name, cls);
|
||||
@ -149,23 +161,28 @@ class Documentation {
|
||||
clazz.visit(item => item.comment = generateSourceCodeComment(item.spec));
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new Documentation(this.classesArray.map(cls => cls.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
Documentation.Class = class {
|
||||
/**
|
||||
* @param {Langs} langs
|
||||
* @param {boolean} experimental
|
||||
* @param {string} name
|
||||
* @param {!Array<!Documentation.Member>} membersArray
|
||||
* @param {?string=} extendsName
|
||||
* @param {MarkdownNode[]=} spec
|
||||
*/
|
||||
constructor(langs, name, membersArray, extendsName = null, spec = undefined) {
|
||||
constructor(langs, experimental, name, membersArray, extendsName = null, spec = undefined) {
|
||||
this.langs = langs;
|
||||
this.experimental = experimental;
|
||||
this.name = name;
|
||||
this.membersArray = membersArray;
|
||||
this.spec = spec;
|
||||
this.extends = extendsName;
|
||||
this.comment = '';
|
||||
this.comment = '';
|
||||
this.index();
|
||||
const match = name.match(/(API|JS|CDP|[A-Z])(.*)/);
|
||||
this.varName = match[1].toLowerCase() + match[2];
|
||||
@ -204,6 +221,12 @@ Documentation.Class = class {
|
||||
}
|
||||
}
|
||||
|
||||
clone() {
|
||||
const cls = new Documentation.Class(this.langs, this.experimental, this.name, this.membersArray.map(m => m.clone()), this.extends, this.spec);
|
||||
cls.comment = this.comment;
|
||||
return cls;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} lang
|
||||
*/
|
||||
@ -218,6 +241,17 @@ Documentation.Class = class {
|
||||
this.membersArray = membersArray;
|
||||
}
|
||||
|
||||
filterOutExperimental() {
|
||||
const membersArray = [];
|
||||
for (const member of this.membersArray) {
|
||||
if (member.experimental)
|
||||
continue;
|
||||
member.filterOutExperimental();
|
||||
membersArray.push(member);
|
||||
}
|
||||
this.membersArray = membersArray;
|
||||
}
|
||||
|
||||
validateOrder(errors, cls) {
|
||||
const members = this.membersArray;
|
||||
// Events should go first.
|
||||
@ -280,15 +314,17 @@ Documentation.Member = class {
|
||||
/**
|
||||
* @param {string} kind
|
||||
* @param {Langs} langs
|
||||
* @param {boolean} experimental
|
||||
* @param {string} name
|
||||
* @param {?Documentation.Type} type
|
||||
* @param {!Array<!Documentation.Member>} argsArray
|
||||
* @param {MarkdownNode[]=} spec
|
||||
* @param {boolean=} required
|
||||
*/
|
||||
constructor(kind, langs, name, type, argsArray, spec = undefined, required = true) {
|
||||
constructor(kind, langs, experimental, name, type, argsArray, spec = undefined, required = true) {
|
||||
this.kind = kind;
|
||||
this.langs = langs;
|
||||
this.experimental = experimental;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.spec = spec;
|
||||
@ -355,13 +391,27 @@ Documentation.Member = class {
|
||||
overriddenArg.filterForLanguage(lang);
|
||||
if (overriddenArg.name === 'options' && !overriddenArg.type.properties.length)
|
||||
continue;
|
||||
overriddenArg.type.filterForLanguage(lang);
|
||||
argsArray.push(overriddenArg);
|
||||
}
|
||||
this.argsArray = argsArray;
|
||||
}
|
||||
|
||||
filterOutExperimental() {
|
||||
this.type.filterOutExperimental();
|
||||
const argsArray = [];
|
||||
for (const arg of this.argsArray) {
|
||||
if (arg.experimental)
|
||||
continue;
|
||||
arg.type.filterOutExperimental();
|
||||
argsArray.push(arg);
|
||||
}
|
||||
this.argsArray = argsArray;
|
||||
}
|
||||
|
||||
clone() {
|
||||
const result = new Documentation.Member(this.kind, this.langs, this.name, this.type, this.argsArray, this.spec, this.required);
|
||||
const result = new Documentation.Member(this.kind, this.langs, this.experimental, this.name, this.type.clone(), this.argsArray.map(arg => arg.clone()), this.spec, this.required);
|
||||
result.alias = this.alias;
|
||||
result.async = this.async;
|
||||
result.paramOrOption = this.paramOrOption;
|
||||
return result;
|
||||
@ -369,37 +419,40 @@ Documentation.Member = class {
|
||||
|
||||
/**
|
||||
* @param {Langs} langs
|
||||
* @param {boolean} experimental
|
||||
* @param {string} name
|
||||
* @param {!Array<!Documentation.Member>} argsArray
|
||||
* @param {?Documentation.Type} returnType
|
||||
* @param {MarkdownNode[]=} spec
|
||||
* @return {!Documentation.Member}
|
||||
*/
|
||||
static createMethod(langs, name, argsArray, returnType, spec) {
|
||||
return new Documentation.Member('method', langs, name, returnType, argsArray, spec);
|
||||
static createMethod(langs, experimental, name, argsArray, returnType, spec) {
|
||||
return new Documentation.Member('method', langs, experimental, name, returnType, argsArray, spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Langs} langs
|
||||
* @param {boolean} experimental
|
||||
* @param {!string} name
|
||||
* @param {!Documentation.Type} type
|
||||
* @param {!MarkdownNode[]=} spec
|
||||
* @param {boolean=} required
|
||||
* @return {!Documentation.Member}
|
||||
*/
|
||||
static createProperty(langs, name, type, spec, required) {
|
||||
return new Documentation.Member('property', langs, name, type, [], spec, required);
|
||||
static createProperty(langs, experimental, name, type, spec, required) {
|
||||
return new Documentation.Member('property', langs, experimental, name, type, [], spec, required);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Langs} langs
|
||||
* @param {boolean} experimental
|
||||
* @param {string} name
|
||||
* @param {?Documentation.Type=} type
|
||||
* @param {MarkdownNode[]=} spec
|
||||
* @return {!Documentation.Member}
|
||||
*/
|
||||
static createEvent(langs, name, type = null, spec) {
|
||||
return new Documentation.Member('event', langs, name, type, [], spec);
|
||||
static createEvent(langs, experimental, name, type = null, spec) {
|
||||
return new Documentation.Member('event', langs, experimental, name, type, [], spec);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -488,16 +541,17 @@ Documentation.Type = class {
|
||||
*/
|
||||
constructor(name, properties) {
|
||||
this.name = name.replace(/^\[/, '').replace(/\]$/, '');
|
||||
/** @type {Documentation.Member[] | undefined} */
|
||||
this.properties = this.name === 'Object' ? properties : undefined;
|
||||
/** @type {Documentation.Type[]} | undefined */
|
||||
/** @type {Documentation.Type[] | undefined} */
|
||||
this.union;
|
||||
/** @type {Documentation.Type[]} | undefined */
|
||||
/** @type {Documentation.Type[] | undefined} */
|
||||
this.args;
|
||||
/** @type {Documentation.Type} | undefined */
|
||||
/** @type {Documentation.Type | undefined} */
|
||||
this.returnType;
|
||||
/** @type {Documentation.Type[]} | undefined */
|
||||
/** @type {Documentation.Type[] | undefined} */
|
||||
this.templates;
|
||||
/** @type {string | undefined } */
|
||||
/** @type {string | undefined} */
|
||||
this.expression;
|
||||
}
|
||||
|
||||
@ -510,6 +564,20 @@ Documentation.Type = class {
|
||||
}
|
||||
}
|
||||
|
||||
clone() {
|
||||
const type = new Documentation.Type(this.name, this.properties ? this.properties.map(prop => prop.clone()) : undefined);
|
||||
if (this.union)
|
||||
type.union = this.union.map(type => type.clone());
|
||||
if (this.args)
|
||||
type.args = this.args.map(type => type.clone());
|
||||
if (this.returnType)
|
||||
type.returnType = this.returnType.clone();
|
||||
if (this.templates)
|
||||
type.templates = this.templates.map(type => type.clone());
|
||||
type.expression = this.expression;
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Documentation.Member[]}
|
||||
*/
|
||||
@ -550,6 +618,19 @@ Documentation.Type = class {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
filterOutExperimental() {
|
||||
if (!this.properties)
|
||||
return;
|
||||
const properties = [];
|
||||
for (const prop of this.properties) {
|
||||
if (prop.experimental)
|
||||
continue;
|
||||
prop.filterOutExperimental();
|
||||
properties.push(prop);
|
||||
}
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Documentation.Type[]} result
|
||||
*/
|
||||
|
@ -26,8 +26,6 @@ const { parseOverrides } = require('./parseOverrides');
|
||||
const exported = require('./exported.json');
|
||||
const { parseApi } = require('../doclint/api_parser');
|
||||
|
||||
/** @typedef {import('../doclint/documentation').Member} Member */
|
||||
|
||||
Error.stackTraceLimit = 50;
|
||||
|
||||
class TypesGenerator {
|
||||
@ -38,10 +36,11 @@ class TypesGenerator {
|
||||
* overridesToDocsClassMapping?: Map<string, string>,
|
||||
* ignoreMissing?: Set<string>,
|
||||
* doNotExportClassNames?: Set<string>,
|
||||
* includeExperimental?: boolean,
|
||||
* }} options
|
||||
*/
|
||||
constructor(options) {
|
||||
/** @type {Array<{name: string, properties: Member[]}>} */
|
||||
/** @type {Array<{name: string, properties: Documentation.Member[]}>} */
|
||||
this.objectDefinitions = [];
|
||||
/** @type {Set<string>} */
|
||||
this.handledMethods = new Set();
|
||||
@ -50,6 +49,10 @@ class TypesGenerator {
|
||||
this.overridesToDocsClassMapping = options.overridesToDocsClassMapping || new Map();
|
||||
this.ignoreMissing = options.ignoreMissing || new Set();
|
||||
this.doNotExportClassNames = options.doNotExportClassNames || new Set();
|
||||
this.documentation.filterForLanguage('js');
|
||||
if (!options.includeExperimental)
|
||||
this.documentation.filterOutExperimental();
|
||||
this.documentation.copyDocsFromSuperclasses([]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,9 +60,6 @@ class TypesGenerator {
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async generateTypes(overridesFile) {
|
||||
this.documentation.filterForLanguage('js');
|
||||
this.documentation.copyDocsFromSuperclasses([]);
|
||||
|
||||
const createMarkdownLink = (member, text) => {
|
||||
const className = toKebabCase(member.clazz.name);
|
||||
const memberName = toKebabCase(member.name);
|
||||
@ -238,7 +238,7 @@ class TypesGenerator {
|
||||
type,
|
||||
params,
|
||||
eventName,
|
||||
comment: value.comment
|
||||
comment: value.comment,
|
||||
});
|
||||
}
|
||||
return descriptions;
|
||||
@ -366,10 +366,21 @@ class TypesGenerator {
|
||||
return this.stringifySimpleType(type, indent, ...namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Documentation.Member[]} properties
|
||||
* @param {string} name
|
||||
* @param {string=} indent
|
||||
* @returns {string}
|
||||
*/
|
||||
stringifyObjectType(properties, name, indent = '') {
|
||||
const parts = [];
|
||||
parts.push(`{`);
|
||||
parts.push(properties.map(member => `${this.memberJSDOC(member, indent + ' ')}${this.nameForProperty(member)}${this.argsFromMember(member, indent + ' ', name)}: ${this.stringifyComplexType(member.type, indent + ' ', name, member.name)};`).join('\n\n'));
|
||||
parts.push(properties.map(member => {
|
||||
const comment = this.memberJSDOC(member, indent + ' ');
|
||||
const args = this.argsFromMember(member, indent + ' ', name);
|
||||
const type = this.stringifyComplexType(member.type, indent + ' ', name, member.name);
|
||||
return `${comment}${this.nameForProperty(member)}${args}: ${type};`;
|
||||
}).join('\n\n'));
|
||||
parts.push(indent + '}');
|
||||
return parts.join('\n');
|
||||
}
|
||||
@ -476,15 +487,124 @@ class TypesGenerator {
|
||||
}
|
||||
|
||||
(async function () {
|
||||
let hadChanges = false;
|
||||
const coreDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api'));
|
||||
const testDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-api'), path.join(PROJECT_DIR, 'docs', 'src', 'api', 'params.md'));
|
||||
const reporterDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-reporter-api'));
|
||||
const assertionClasses = new Set(['LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'ScreenshotAssertions']);
|
||||
|
||||
/**
|
||||
* @param {boolean} includeExperimental
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function generateCoreTypes(includeExperimental) {
|
||||
const documentation = coreDocumentation.clone();
|
||||
const generator = new TypesGenerator({
|
||||
documentation,
|
||||
classNamesToGenerate: new Set(coreDocumentation.classesArray.map(cls => cls.name).filter(name => !assertionClasses.has(name) && name !== 'PlaywrightAssertions')),
|
||||
includeExperimental,
|
||||
});
|
||||
let types = await generator.generateTypes(path.join(__dirname, 'overrides.d.ts'));
|
||||
const namedDevices = Object.keys(devices).map(name => ` ${JSON.stringify(name)}: DeviceDescriptor;`).join('\n');
|
||||
types += [
|
||||
`type Devices = {`,
|
||||
namedDevices,
|
||||
` [key: string]: DeviceDescriptor;`,
|
||||
`}`,
|
||||
``,
|
||||
`export interface ChromiumBrowserContext extends BrowserContext { }`,
|
||||
`export interface ChromiumBrowser extends Browser { }`,
|
||||
`export interface FirefoxBrowser extends Browser { }`,
|
||||
`export interface WebKitBrowser extends Browser { }`,
|
||||
`export interface ChromiumCoverage extends Coverage { }`,
|
||||
``,
|
||||
].join('\n');
|
||||
for (const [key, value] of Object.entries(exported))
|
||||
types = types.replace(new RegExp('\\b' + key + '\\b', 'g'), value);
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} includeExperimental
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function generateTestTypes(includeExperimental) {
|
||||
const documentation = coreDocumentation.mergeWith(testDocumentation);
|
||||
const generator = new TypesGenerator({
|
||||
documentation,
|
||||
classNamesToGenerate: new Set(['TestError', 'TestInfo', 'WorkerInfo', ...assertionClasses]),
|
||||
overridesToDocsClassMapping: new Map([
|
||||
['TestType', 'Test'],
|
||||
['Config', 'TestConfig'],
|
||||
['FullConfig', 'TestConfig'],
|
||||
['Project', 'TestProject'],
|
||||
['PlaywrightWorkerOptions', 'TestOptions'],
|
||||
['PlaywrightTestOptions', 'TestOptions'],
|
||||
['PlaywrightWorkerArgs', 'Fixtures'],
|
||||
['PlaywrightTestArgs', 'Fixtures'],
|
||||
]),
|
||||
ignoreMissing: new Set([
|
||||
'FullConfig.version',
|
||||
'FullConfig.rootDir',
|
||||
'SuiteFunction',
|
||||
'TestFunction',
|
||||
'PlaywrightWorkerOptions.defaultBrowserType',
|
||||
'PlaywrightWorkerArgs.playwright',
|
||||
'Matchers',
|
||||
]),
|
||||
doNotExportClassNames: new Set(assertionClasses),
|
||||
includeExperimental,
|
||||
});
|
||||
return await generator.generateTypes(path.join(__dirname, 'overrides-test.d.ts'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} includeExperimental
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function generateReporterTypes(includeExperimental) {
|
||||
const documentation = coreDocumentation.mergeWith(testDocumentation).mergeWith(reporterDocumentation);
|
||||
const generator = new TypesGenerator({
|
||||
documentation,
|
||||
classNamesToGenerate: new Set(reporterDocumentation.classesArray.map(cls => cls.name)),
|
||||
ignoreMissing: new Set(['FullResult']),
|
||||
includeExperimental,
|
||||
});
|
||||
return await generator.generateTypes(path.join(__dirname, 'overrides-testReporter.d.ts'));
|
||||
}
|
||||
|
||||
async function generateExperimentalTypes() {
|
||||
const core = await generateCoreTypes(true);
|
||||
const test = await generateTestTypes(true);
|
||||
const reporter = await generateReporterTypes(true);
|
||||
const lines = [
|
||||
`// This file is generated by ${__filename.substring(path.join(__dirname, '..', '..').length).split(path.sep).join(path.posix.sep)}`,
|
||||
`declare module 'playwright-core' {`,
|
||||
...core.split('\n'),
|
||||
`}`,
|
||||
`declare module '@playwright/test' {`,
|
||||
...test.split('\n'),
|
||||
`}`,
|
||||
`declare module '@playwright/test/reporter' {`,
|
||||
...reporter.split('\n'),
|
||||
`}`,
|
||||
];
|
||||
const cutFrom = lines.findIndex(line => line.includes('BEGINGLOBAL'));
|
||||
const cutTo = lines.findIndex(line => line.includes('ENDGLOBAL'));
|
||||
lines.splice(cutFrom, cutTo - cutFrom + 1);
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} filePath
|
||||
* @param {string} content
|
||||
* @param {boolean} removeTrailingWhiteSpace
|
||||
*/
|
||||
function writeFile(filePath, content) {
|
||||
function writeFile(filePath, content, removeTrailingWhiteSpace) {
|
||||
content = content.replace(/\r\n/g, '\n');
|
||||
if (removeTrailingWhiteSpace)
|
||||
content = content.replace(/( +)\n/g, '\n'); // remove trailing whitespace
|
||||
if (os.platform() === 'win32')
|
||||
content = content.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
|
||||
content = content.replace(/\n/g, '\r\n');
|
||||
const existing = fs.readFileSync(filePath, 'utf8');
|
||||
if (existing === content)
|
||||
return;
|
||||
@ -493,82 +613,18 @@ class TypesGenerator {
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
}
|
||||
|
||||
let hadChanges = false;
|
||||
const coreTypesDir = path.join(PROJECT_DIR, 'packages', 'playwright-core', 'types');
|
||||
if (!fs.existsSync(coreTypesDir))
|
||||
fs.mkdirSync(coreTypesDir)
|
||||
const testTypesDir = path.join(PROJECT_DIR, 'packages', 'playwright-test', 'types');
|
||||
if (!fs.existsSync(testTypesDir))
|
||||
fs.mkdirSync(testTypesDir)
|
||||
writeFile(path.join(coreTypesDir, 'protocol.d.ts'), fs.readFileSync(path.join(PROJECT_DIR, 'packages', 'playwright-core', 'src', 'server', 'chromium', 'protocol.d.ts'), 'utf8'));
|
||||
|
||||
const assertionClasses = new Set(['LocatorAssertions', 'PageAssertions', 'APIResponseAssertions', 'ScreenshotAssertions']);
|
||||
const apiDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api'));
|
||||
apiDocumentation.index();
|
||||
const apiTypesGenerator = new TypesGenerator({
|
||||
documentation: apiDocumentation,
|
||||
classNamesToGenerate: new Set(apiDocumentation.classesArray.map(cls => cls.name).filter(name => !assertionClasses.has(name) && name !== 'PlaywrightAssertions')),
|
||||
});
|
||||
let apiTypes = await apiTypesGenerator.generateTypes(path.join(__dirname, 'overrides.d.ts'));
|
||||
const namedDevices = Object.keys(devices).map(name => ` ${JSON.stringify(name)}: DeviceDescriptor;`).join('\n');
|
||||
apiTypes += [
|
||||
`type Devices = {`,
|
||||
namedDevices,
|
||||
` [key: string]: DeviceDescriptor;`,
|
||||
`}`,
|
||||
``,
|
||||
`export interface ChromiumBrowserContext extends BrowserContext { }`,
|
||||
`export interface ChromiumBrowser extends Browser { }`,
|
||||
`export interface FirefoxBrowser extends Browser { }`,
|
||||
`export interface WebKitBrowser extends Browser { }`,
|
||||
`export interface ChromiumCoverage extends Coverage { }`,
|
||||
``,
|
||||
].join('\n');
|
||||
for (const [key, value] of Object.entries(exported))
|
||||
apiTypes = apiTypes.replace(new RegExp('\\b' + key + '\\b', 'g'), value);
|
||||
apiTypes = apiTypes.replace(/( +)\n/g, '\n'); // remove trailing whitespace
|
||||
writeFile(path.join(coreTypesDir, 'types.d.ts'), apiTypes);
|
||||
|
||||
const testOnlyDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-api'), path.join(PROJECT_DIR, 'docs', 'src', 'api', 'params.md'));
|
||||
const testDocumentation = apiDocumentation.mergeWith(testOnlyDocumentation);
|
||||
const testTypesGenerator = new TypesGenerator({
|
||||
documentation: testDocumentation,
|
||||
classNamesToGenerate: new Set(['TestError', 'TestInfo', 'WorkerInfo', ...assertionClasses]),
|
||||
overridesToDocsClassMapping: new Map([
|
||||
['TestType', 'Test'],
|
||||
['Config', 'TestConfig'],
|
||||
['FullConfig', 'TestConfig'],
|
||||
['Project', 'TestProject'],
|
||||
['PlaywrightWorkerOptions', 'TestOptions'],
|
||||
['PlaywrightTestOptions', 'TestOptions'],
|
||||
['PlaywrightWorkerArgs', 'Fixtures'],
|
||||
['PlaywrightTestArgs', 'Fixtures'],
|
||||
]),
|
||||
ignoreMissing: new Set([
|
||||
'FullConfig.version',
|
||||
'FullConfig.rootDir',
|
||||
'SuiteFunction',
|
||||
'TestFunction',
|
||||
'PlaywrightWorkerOptions.defaultBrowserType',
|
||||
'PlaywrightWorkerArgs.playwright',
|
||||
'Matchers',
|
||||
]),
|
||||
doNotExportClassNames: new Set(assertionClasses),
|
||||
});
|
||||
let testTypes = await testTypesGenerator.generateTypes(path.join(__dirname, 'overrides-test.d.ts'));
|
||||
testTypes = testTypes.replace(/( +)\n/g, '\n'); // remove trailing whitespace
|
||||
writeFile(path.join(testTypesDir, 'test.d.ts'), testTypes);
|
||||
|
||||
const testReporterOnlyDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-reporter-api'));
|
||||
const testReporterDocumentation = testDocumentation.mergeWith(testReporterOnlyDocumentation);
|
||||
const testReporterTypesGenerator = new TypesGenerator({
|
||||
documentation: testReporterDocumentation,
|
||||
classNamesToGenerate: new Set(testReporterOnlyDocumentation.classesArray.map(cls => cls.name)),
|
||||
ignoreMissing: new Set(['FullResult']),
|
||||
});
|
||||
let testReporterTypes = await testReporterTypesGenerator.generateTypes(path.join(__dirname, 'overrides-testReporter.d.ts'));
|
||||
testReporterTypes = testReporterTypes.replace(/( +)\n/g, '\n'); // remove trailing whitespace
|
||||
writeFile(path.join(testTypesDir, 'testReporter.d.ts'), testReporterTypes);
|
||||
|
||||
writeFile(path.join(coreTypesDir, 'protocol.d.ts'), fs.readFileSync(path.join(PROJECT_DIR, 'packages', 'playwright-core', 'src', 'server', 'chromium', 'protocol.d.ts'), 'utf8'), false);
|
||||
writeFile(path.join(coreTypesDir, 'types.d.ts'), await generateCoreTypes(false), true);
|
||||
writeFile(path.join(testTypesDir, 'test.d.ts'), await generateTestTypes(false), true);
|
||||
writeFile(path.join(testTypesDir, 'testReporter.d.ts'), await generateReporterTypes(false), true);
|
||||
writeFile(path.join(PROJECT_DIR, 'tests', 'config', 'experimental.d.ts'), await generateExperimentalTypes(), true);
|
||||
process.exit(hadChanges && process.argv.includes('--check-clean') ? 1 : 0);
|
||||
})().catch(e => {
|
||||
console.error(e);
|
||||
|
5
utils/generate_types/overrides-test.d.ts
vendored
5
utils/generate_types/overrides-test.d.ts
vendored
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import type { APIRequestContext, Browser, BrowserContext, BrowserContextOptions, Page, LaunchOptions, ViewportSize, Geolocation, HTTPCredentials, Locator, APIResponse } from 'playwright-core';
|
||||
export * from 'playwright-core';
|
||||
|
||||
export type ReporterDescription =
|
||||
['dot'] |
|
||||
@ -371,7 +372,7 @@ type MakeMatchers<R, T> = BaseMatchers<R, T> & {
|
||||
ExtraMatchers<T, Locator, LocatorAssertions> &
|
||||
ExtraMatchers<T, APIResponse, APIResponseAssertions>;
|
||||
|
||||
export declare type Expect = {
|
||||
export type Expect = {
|
||||
<T = unknown>(actual: T, messageOrOptions?: string | { message?: string }): MakeMatchers<void, T>;
|
||||
soft: <T = unknown>(actual: T, messageOrOptions?: string | { message?: string }) => MakeMatchers<void, T>;
|
||||
poll: <T = unknown>(actual: () => T | Promise<T>, messageOrOptions?: string | { message?: string, timeout?: number }) => BaseMatchers<Promise<void>, T> & {
|
||||
@ -450,12 +451,14 @@ type SupportedExpectProperties =
|
||||
'toThrow' |
|
||||
'toThrowError'
|
||||
|
||||
// --- BEGINGLOBAL ---
|
||||
declare global {
|
||||
export namespace PlaywrightTest {
|
||||
export interface Matchers<R, T = unknown> {
|
||||
}
|
||||
}
|
||||
}
|
||||
// --- ENDGLOBAL ---
|
||||
|
||||
/**
|
||||
* These tests are executed in Playwright environment that launches the browser
|
||||
|
@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { FullConfig, FullProject, TestStatus, TestError } from './test';
|
||||
export type { FullConfig, TestStatus, TestError } from './test';
|
||||
import type { FullConfig, FullProject, TestStatus, TestError } from '@playwright/test';
|
||||
export type { FullConfig, TestStatus, TestError } from '@playwright/test';
|
||||
|
||||
export interface Suite {
|
||||
project(): FullProject | undefined;
|
||||
|
4
utils/generate_types/overrides.d.ts
vendored
4
utils/generate_types/overrides.d.ts
vendored
@ -13,12 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Protocol } from './protocol';
|
||||
import { Protocol } from 'playwright-core/types/protocol';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import { EventEmitter } from 'events';
|
||||
import { Readable } from 'stream';
|
||||
import { ReadStream } from 'fs';
|
||||
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from './structs';
|
||||
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from 'playwright-core/types/structs';
|
||||
|
||||
type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
|
||||
state?: 'visible'|'attached';
|
||||
|
Loading…
Reference in New Issue
Block a user