Skip to content

Commit dff028f

Browse files
author
Joel Einbinder
committed
1
1 parent 6528477 commit dff028f

File tree

5 files changed

+139
-31
lines changed

5 files changed

+139
-31
lines changed

docs/api.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ Get the browser context that the page belongs to.
822822

823823
#### page.coverage
824824

825-
- returns: <?[any]>
825+
- returns: <?[ChromiumCoverage]>
826826

827827
Browser-specific Coverage implementation, only available for Chromium atm. See [ChromiumCoverage](#class-chromiumcoverage) for more details.
828828

@@ -3906,7 +3906,6 @@ const { chromium } = require('playwright');
39063906
[ChromiumSession]: #class-chromiumsession "ChromiumSession"
39073907
[ChromiumTarget]: #class-chromiumtarget "ChromiumTarget"
39083908
[ConsoleMessage]: #class-consolemessage "ConsoleMessage"
3909-
[Coverage]: #class-coverage "Coverage"
39103909
[Dialog]: #class-dialog "Dialog"
39113910
[ElementHandle]: #class-elementhandle "ElementHandle"
39123911
[Element]: https://developer.mozilla.org/en-US/docs/Web/API/element "Element"

utils/doclint/check_public_api/MDBuilder.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class MDOutline {
6565
if (text.startsWith(`"`) || text.startsWith(`'`))
6666
continue;
6767
const property = parseProperty(childElement);
68-
property.required = property.comment.includes('***required***');
68+
property.required = property.comment.includes('**required**');
6969
properties.push(property);
7070
}
7171
}
@@ -102,7 +102,7 @@ class MDOutline {
102102
acceptNode(node) {
103103
if (!(node instanceof Comment))
104104
return NodeFilter.FILTER_REJECT;
105-
if (node.data.trim() === 'GEN:toc')
105+
if (node.data.trim().startsWith('GEN:toc'))
106106
return NodeFilter.FILTER_ACCEPT;
107107
return NodeFilter.FILTER_REJECT;
108108
}
@@ -179,7 +179,7 @@ class MDOutline {
179179
errors.push(`${name} has mistyped 'return' type declaration: expected exactly '${expectedText}', found '${actualText}'.`);
180180
}
181181
}
182-
const comment = parseComment(extractSiblingsIntoFragment(ul ? ul.nextSibling : content));
182+
const comment = parseComment(extractSiblingsIntoFragment(ul ? ul.nextSibling : content.querySelector('h4').nextSibling));
183183
return {
184184
name,
185185
args,

utils/generate_types/index.js

+19-6
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,8 @@ let documentation;
4040
return '';
4141
throw new Error(`Unknown override method "${className}.${methodName}"`);
4242
}
43-
return memberJSDOC(method, ' ');
43+
return memberJSDOC(method, ' ').trimLeft();
4444
}, (className) => {
45-
4645
return classBody(docClassForName(className));
4746
});
4847
const classes = documentation.classesArray.filter(cls => !handledClasses.has(cls.name));
@@ -97,6 +96,15 @@ function classToString(classDesc) {
9796
return parts.join('\n');
9897
}
9998

99+
/**
100+
* @param {string} type
101+
*/
102+
function argNameForType(type) {
103+
if (type === 'void')
104+
return null;
105+
return type[0].toLowerCase() + type.slice(1);
106+
}
107+
100108
/**
101109
* @param {import('../doclint/check_public_api/Documentation').Class} classDesc
102110
*/
@@ -106,7 +114,10 @@ function classBody(classDesc) {
106114
for (const [eventName, value] of classDesc.events) {
107115
if (value.comment)
108116
parts.push(writeComment(value.comment, ' '));
109-
parts.push(` ${method}(event: '${eventName}', listener: (arg0 : ${typeToString(value && value.type, classDesc.name, eventName, 'payload')}) => void): this;\n`);
117+
const type = typeToString(value && value.type, classDesc.name, eventName, 'payload');
118+
const argName = argNameForType(type);
119+
const params = argName ? `${argName} : ${type}` : '';
120+
parts.push(` ${method}(event: '${eventName}', listener: (${params}) => void): this;\n`);
110121
}
111122
}
112123
const members = classDesc.membersArray.filter(member => member.kind !== 'event');
@@ -171,8 +182,6 @@ function typeToString(type, ...namespace) {
171182
if (!type)
172183
return 'void';
173184
let typeString = stringifyType(parseType(type.name));
174-
for (let i = 0; i < type.properties.length; i++)
175-
typeString = typeString.replace('arg' + i, type.properties[i].name);
176185
if (type.properties.length && typeString.indexOf('Object') !== -1) {
177186
const name = namespace.map(n => n[0].toUpperCase() + n.substring(1)).join('');
178187
typeString = typeString.replace('Object', name);
@@ -242,6 +251,9 @@ function parseType(type) {
242251
};
243252
}
244253

254+
/**
255+
* @return {string}
256+
*/
245257
function stringifyType(parsedType) {
246258
if (!parsedType)
247259
return 'void';
@@ -255,7 +267,7 @@ function stringifyType(parsedType) {
255267
arg.next = null;
256268
stringArgs.push(stringifyType(arg));
257269
}
258-
out = `((${stringArgs.map((type, index) => `arg${index} : ${type}`).join(', ')}, ...args: any[]) => ${stringifyType(parsedType.retType)})`;
270+
out = `((${stringArgs.map((type, index) => `arg${index} : ${type}`).join(', ')}) => ${stringifyType(parsedType.retType)})`;
259271
} else if (parsedType.name === 'function') {
260272
out = 'Function';
261273
}
@@ -292,6 +304,7 @@ function argsFromMember(member, ...namespace) {
292304
}
293305
/**
294306
* @param {import('../doclint/check_public_api/Documentation').Member} member
307+
* @param {string} indent
295308
*/
296309
function memberJSDOC(member, indent) {
297310
const lines = [];

utils/generate_types/overrides.d.ts

+30-17
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,51 @@ type WaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
1111
visibility: 'visible'|'any';
1212
}
1313

14-
export interface Page<C=BrowserContext> {
15-
context(): C;
14+
type HTMLOrSVGElement = SVGElement | HTMLElement;
15+
type HTMLOrSVGElementHandle = ElementHandle<HTMLOrSVGElement>;
1616

17+
export interface Page {
1718
evaluate<Args extends any[], R>(pageFunction: PageFunction<Args, R>, ...args: Boxed<Args>): Promise<R>;
1819
evaluateHandle<Args extends any[], R>(pageFunction: PageFunction<Args, R>, ...args: Boxed<Args>): Promise<Handle<R>>;
1920

2021
$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K> | null>;
21-
$(selector: string): Promise<ElementHandle<Element> | null>;
22+
$(selector: string): Promise<HTMLOrSVGElementHandle | null>;
23+
24+
$$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>;
25+
$$(selector: string): Promise<HTMLOrSVGElementHandle[]>;
2226

2327
$eval<K extends keyof HTMLElementTagNameMap, Args extends any[], R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Args, R>, ...args: Boxed<Args>): Promise<R>;
24-
$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<Element, Args, R>, ...args: Boxed<Args>): Promise<R>;
28+
$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement, Args, R>, ...args: Boxed<Args>): Promise<R>;
2529

2630
$$eval<K extends keyof HTMLElementTagNameMap, Args extends any[], R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Args, R>, ...args: Boxed<Args>): Promise<R>;
27-
$$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<Element[], Args, R>, ...args: Boxed<Args>): Promise<R>;
31+
$$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement[], Args, R>, ...args: Boxed<Args>): Promise<R>;
2832

29-
waitForSelector(selector: string, options?: WaitForSelectorOptionsNotHidden): Promise<ElementHandle>;
30-
waitForSelector(selector: string, options: PageWaitForSelectorOptions): Promise<null|ElementHandle>;
33+
waitForSelector<K extends keyof HTMLElementTagNameMap>(selector: K, options?: WaitForSelectorOptionsNotHidden): Promise<ElementHandleForTag<K>>;
34+
waitForSelector(selector: string, options?: WaitForSelectorOptionsNotHidden): Promise<HTMLOrSVGElementHandle>;
35+
waitForSelector<K extends keyof HTMLElementTagNameMap>(selector: K, options: PageWaitForSelectorOptions): Promise<ElementHandleForTag<K> | null>;
36+
waitForSelector(selector: string, options: PageWaitForSelectorOptions): Promise<null|HTMLOrSVGElementHandle>;
3137
}
3238

3339
export interface Frame {
3440
evaluate<Args extends any[], R>(pageFunction: PageFunction<Args, R>, ...args: Boxed<Args>): Promise<R>;
3541
evaluateHandle<Args extends any[], R>(pageFunction: PageFunction<Args, R>, ...args: Boxed<Args>): Promise<Handle<R>>;
3642

3743
$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K> | null>;
38-
$(selector: string): Promise<ElementHandle<Element> | null>;
44+
$(selector: string): Promise<HTMLOrSVGElementHandle | null>;
45+
46+
$$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>;
47+
$$(selector: string): Promise<HTMLOrSVGElementHandle[]>;
3948

4049
$eval<K extends keyof HTMLElementTagNameMap, Args extends any[], R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Args, R>, ...args: Boxed<Args>): Promise<R>;
41-
$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<Element, Args, R>, ...args: Boxed<Args>): Promise<R>;
50+
$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement, Args, R>, ...args: Boxed<Args>): Promise<R>;
4251

4352
$$eval<K extends keyof HTMLElementTagNameMap, Args extends any[], R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Args, R>, ...args: Boxed<Args>): Promise<R>;
44-
$$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<Element[], Args, R>, ...args: Boxed<Args>): Promise<R>;
53+
$$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement[], Args, R>, ...args: Boxed<Args>): Promise<R>;
54+
55+
waitForSelector<K extends keyof HTMLElementTagNameMap>(selector: K, options?: WaitForSelectorOptionsNotHidden): Promise<ElementHandleForTag<K>>;
56+
waitForSelector(selector: string, options?: WaitForSelectorOptionsNotHidden): Promise<HTMLOrSVGElementHandle>;
57+
waitForSelector<K extends keyof HTMLElementTagNameMap>(selector: K, options: PageWaitForSelectorOptions): Promise<ElementHandleForTag<K> | null>;
58+
waitForSelector(selector: string, options: PageWaitForSelectorOptions): Promise<null|HTMLOrSVGElementHandle>;
4559
}
4660

4761
export interface Worker {
@@ -58,17 +72,16 @@ export interface JSHandle<T = any> {
5872

5973
export interface ElementHandle<T=Node> extends JSHandle<T> {
6074
$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K> | null>;
61-
$(selector: string): Promise<ElementHandle<Element> | null>;
75+
$(selector: string): Promise<HTMLOrSVGElementHandle | null>;
76+
77+
$$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>;
78+
$$(selector: string): Promise<HTMLOrSVGElementHandle[]>;
6279

6380
$eval<K extends keyof HTMLElementTagNameMap, Args extends any[], R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Args, R>, ...args: Boxed<Args>): Promise<R>;
64-
$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<Element, Args, R>, ...args: Boxed<Args>): Promise<R>;
81+
$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement, Args, R>, ...args: Boxed<Args>): Promise<R>;
6582

6683
$$eval<K extends keyof HTMLElementTagNameMap, Args extends any[], R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Args, R>, ...args: Boxed<Args>): Promise<R>;
67-
$$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<Element[], Args, R>, ...args: Boxed<Args>): Promise<R>;
68-
}
69-
70-
export interface ChromiumBrowser extends Browser {
71-
newPage(options?: BrowserNewPageOptions): Promise<Page<ChromiumBrowserContext>>;
84+
$$eval<Args extends any[], R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement[], Args, R>, ...args: Boxed<Args>): Promise<R>;
7285
}
7386

7487
export interface BrowserType<Browser> {

utils/generate_types/test/test.ts

+86-3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ playwright.chromium.launch().then(async browser => {
5454
});
5555
const assertion : AssertType<number, typeof result> = true;
5656
console.log(await page.evaluate("1 + 2"));
57+
page.$eval('.foo', e => e.style);
5758
}
5859

5960
const bodyHandle = await page.$("body");
@@ -115,8 +116,16 @@ playwright.chromium.launch().then(async browser => {
115116
else interceptedRequest.continue();
116117
});
117118

118-
page.keyboard.type("Hello"); // Types instantly
119-
page.keyboard.type("World", { delay: 100 }); // Types slower, like a user
119+
await page.route(str => {
120+
const assertion : AssertType<string, typeof str> = true;
121+
return true;
122+
}, interceptedRequest => {
123+
interceptedRequest.continue();
124+
return 'something random for no reason';
125+
});
126+
127+
await page.keyboard.type("Hello"); // Types instantly
128+
await page.keyboard.type("World", { delay: 100 }); // Types slower, like a user
120129

121130
const watchDog = page.waitForFunction("window.innerWidth < 100");
122131
page.setViewportSize({ width: 50, height: 50 });
@@ -324,7 +333,7 @@ playwright.chromium.launch().then(async browser => {
324333
(async () => {
325334
const browser = await playwright.chromium.launch();
326335
const page = await browser.newPage();
327-
const context = page.context();
336+
const context = page.context() as playwright.ChromiumBrowserContext;
328337
const target = context.pageTarget(page);
329338

330339
{
@@ -426,3 +435,77 @@ playwright.chromium.launch().then(async browser => {
426435
}, 5);
427436
await browser.close();
428437
})();
438+
439+
// query selectors
440+
441+
(async () => {
442+
const browser = await playwright.chromium.launch();
443+
const page = await browser.newPage();
444+
const frame = page.mainFrame();
445+
const element = await page.waitForSelector('some-fake-element');
446+
const elementLikes = [page, frame, element];
447+
for (const elementLike of elementLikes) {
448+
{
449+
const handle = await elementLike.$('body');
450+
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>, typeof handle> = true;
451+
}
452+
{
453+
const handle = await elementLike.$('something-strange');
454+
const top = await handle!.evaluate(element => element.style.top);
455+
const assertion : AssertType<string, typeof top> = true;
456+
}
457+
458+
{
459+
const handles = await elementLike.$$('body');
460+
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>[], typeof handles> = true;
461+
}
462+
463+
{
464+
const handles = await elementLike.$$('something-strange');
465+
const top = await handles[0].evaluate(element => element.style.top);
466+
const assertion : AssertType<string, typeof top> = true;
467+
}
468+
}
469+
470+
const frameLikes = [page, frame];
471+
for (const frameLike of frameLikes) {
472+
{
473+
const handle = await frameLike.waitForSelector('body');
474+
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>, typeof handle> = true;
475+
const canBeNull : AssertType<null, typeof handle> = false;
476+
}
477+
{
478+
const visibility = Math.random() > .5 ? 'any': 'visible';
479+
const handle = await frameLike.waitForSelector('body', {visibility});
480+
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>, typeof handle> = true;
481+
const canBeNull : AssertType<null, typeof handle> = false;
482+
}
483+
{
484+
const visibility = Math.random() > .5 ? 'hidden': 'visible';
485+
const handle = await frameLike.waitForSelector('body', {visibility});
486+
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>, typeof handle> = true;
487+
const canBeNull : AssertType<null, typeof handle> = true;
488+
}
489+
490+
{
491+
const handle = await frameLike.waitForSelector('something-strange');
492+
const elementAssertion : AssertType<playwright.ElementHandle<HTMLElement|SVGElement>, typeof handle> = true;
493+
const canBeNull : AssertType<null, typeof handle> = false;
494+
}
495+
{
496+
const visibility = Math.random() > .5 ? 'any': 'visible';
497+
const handle = await frameLike.waitForSelector('something-strange', {visibility});
498+
const elementAssertion : AssertType<playwright.ElementHandle<HTMLElement|SVGElement>, typeof handle> = true;
499+
const canBeNull : AssertType<null, typeof handle> = false;
500+
}
501+
{
502+
const visibility = Math.random() > .5 ? 'hidden': 'visible';
503+
const handle = await frameLike.waitForSelector('something-strange', {visibility});
504+
const elementAssertion : AssertType<playwright.ElementHandle<HTMLElement|SVGElement>, typeof handle> = true;
505+
const canBeNull : AssertType<null, typeof handle> = true;
506+
}
507+
}
508+
509+
510+
await browser.close();
511+
})();

0 commit comments

Comments
 (0)