Skip to content

Commit

Permalink
a lot of fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Joel Einbinder authored and JoelEinbinder committed Mar 10, 2020
1 parent cbbaab7 commit 9879817
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 56 deletions.
6 changes: 3 additions & 3 deletions utils/doclint/check_public_api/MDBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class MDOutline {
if (text.startsWith(`"`) || text.startsWith(`'`))
continue;
const property = parseProperty(childElement);
property.required = property.comment.includes('***required***');
property.required = property.comment.includes('**required**');
properties.push(property);
}
}
Expand Down Expand Up @@ -102,7 +102,7 @@ class MDOutline {
acceptNode(node) {
if (!(node instanceof Comment))
return NodeFilter.FILTER_REJECT;
if (node.data.trim() === 'GEN:toc')
if (node.data.trim().startsWith('GEN:toc'))
return NodeFilter.FILTER_ACCEPT;
return NodeFilter.FILTER_REJECT;
}
Expand Down Expand Up @@ -179,7 +179,7 @@ class MDOutline {
errors.push(`${name} has mistyped 'return' type declaration: expected exactly '${expectedText}', found '${actualText}'.`);
}
}
const comment = parseComment(extractSiblingsIntoFragment(ul ? ul.nextSibling : content));
const comment = parseComment(extractSiblingsIntoFragment(ul ? ul.nextSibling : content.querySelector('h4').nextSibling));
return {
name,
args,
Expand Down
32 changes: 24 additions & 8 deletions utils/generate_types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ const handledMethods = new Set();
/** @type {import('../doclint/check_public_api/Documentation')} */
let documentation;
(async function() {
fs.writeFileSync(path.join(PROJECT_DIR, 'types', 'protocol.d.ts'), fs.readFileSync(path.join(PROJECT_DIR, 'src', 'chromium', 'protocol.ts')), 'utf8');
const typesDir = path.join(PROJECT_DIR, 'types');
if (!fs.existsSync(typesDir))
fs.mkdirSync(typesDir)
fs.writeFileSync(path.join(typesDir, 'protocol.d.ts'), fs.readFileSync(path.join(PROJECT_DIR, 'src', 'chromium', 'protocol.ts')), 'utf8');
const browser = await chromium.launch();
const page = await browser.newPage();
const api = await Source.readFile(path.join(PROJECT_DIR, 'docs', 'api.md'));
Expand Down Expand Up @@ -40,9 +43,8 @@ let documentation;
return '';
throw new Error(`Unknown override method "${className}.${methodName}"`);
}
return memberJSDOC(method, ' ');
return memberJSDOC(method, ' ').trimLeft();
}, (className) => {

return classBody(docClassForName(className));
});
const classes = documentation.classesArray.filter(cls => !handledClasses.has(cls.name));
Expand All @@ -59,7 +61,7 @@ ${overrides}
${classes.map(classDesc => classToString(classDesc)).join('\n')}
${objectDefinitionsToString()}
`;
fs.writeFileSync(path.join(PROJECT_DIR, 'types', 'types.d.ts'), output, 'utf8');
fs.writeFileSync(path.join(typesDir, 'types.d.ts'), output, 'utf8');
})().catch(e => {
console.error(e);
process.exit(1);
Expand Down Expand Up @@ -97,6 +99,15 @@ function classToString(classDesc) {
return parts.join('\n');
}

/**
* @param {string} type
*/
function argNameForType(type) {
if (type === 'void')
return null;
return type[0].toLowerCase() + type.slice(1);
}

/**
* @param {import('../doclint/check_public_api/Documentation').Class} classDesc
*/
Expand All @@ -106,7 +117,10 @@ function classBody(classDesc) {
for (const [eventName, value] of classDesc.events) {
if (value.comment)
parts.push(writeComment(value.comment, ' '));
parts.push(` ${method}(event: '${eventName}', listener: (arg0 : ${typeToString(value && value.type, classDesc.name, eventName, 'payload')}) => void): this;\n`);
const type = typeToString(value && value.type, classDesc.name, eventName, 'payload');
const argName = argNameForType(type);
const params = argName ? `${argName} : ${type}` : '';
parts.push(` ${method}(event: '${eventName}', listener: (${params}) => void): this;\n`);
}
}
const members = classDesc.membersArray.filter(member => member.kind !== 'event');
Expand Down Expand Up @@ -171,8 +185,6 @@ function typeToString(type, ...namespace) {
if (!type)
return 'void';
let typeString = stringifyType(parseType(type.name));
for (let i = 0; i < type.properties.length; i++)
typeString = typeString.replace('arg' + i, type.properties[i].name);
if (type.properties.length && typeString.indexOf('Object') !== -1) {
const name = namespace.map(n => n[0].toUpperCase() + n.substring(1)).join('');
typeString = typeString.replace('Object', name);
Expand Down Expand Up @@ -242,6 +254,9 @@ function parseType(type) {
};
}

/**
* @return {string}
*/
function stringifyType(parsedType) {
if (!parsedType)
return 'void';
Expand All @@ -255,7 +270,7 @@ function stringifyType(parsedType) {
arg.next = null;
stringArgs.push(stringifyType(arg));
}
out = `((${stringArgs.map((type, index) => `arg${index} : ${type}`).join(', ')}, ...args: any[]) => ${stringifyType(parsedType.retType)})`;
out = `((${stringArgs.map((type, index) => `arg${index} : ${type}`).join(', ')}) => ${stringifyType(parsedType.retType)})`;
} else if (parsedType.name === 'function') {
out = 'Function';
}
Expand Down Expand Up @@ -292,6 +307,7 @@ function argsFromMember(member, ...namespace) {
}
/**
* @param {import('../doclint/check_public_api/Documentation').Member} member
* @param {string} indent
*/
function memberJSDOC(member, indent) {
const lines = [];
Expand Down
54 changes: 36 additions & 18 deletions utils/generate_types/overrides.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,51 @@ type WaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
visibility: 'visible'|'any';
}

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

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

$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K> | null>;
$(selector: string): Promise<ElementHandle<Element> | null>;
$(selector: string): Promise<HTMLOrSVGElementHandle | null>;

$$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>;
$$(selector: string): Promise<HTMLOrSVGElementHandle[]>;

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

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

waitForSelector(selector: string, options?: WaitForSelectorOptionsNotHidden): Promise<ElementHandle>;
waitForSelector(selector: string, options: PageWaitForSelectorOptions): Promise<null|ElementHandle>;
waitForSelector<K extends keyof HTMLElementTagNameMap>(selector: K, options?: WaitForSelectorOptionsNotHidden): Promise<ElementHandleForTag<K>>;
waitForSelector(selector: string, options?: WaitForSelectorOptionsNotHidden): Promise<HTMLOrSVGElementHandle>;
waitForSelector<K extends keyof HTMLElementTagNameMap>(selector: K, options: PageWaitForSelectorOptions): Promise<ElementHandleForTag<K> | null>;
waitForSelector(selector: string, options: PageWaitForSelectorOptions): Promise<null|HTMLOrSVGElementHandle>;
}

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

$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K> | null>;
$(selector: string): Promise<ElementHandle<Element> | null>;
$(selector: string): Promise<HTMLOrSVGElementHandle | null>;

$$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>;
$$(selector: string): Promise<HTMLOrSVGElementHandle[]>;

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

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

waitForSelector<K extends keyof HTMLElementTagNameMap>(selector: K, options?: WaitForSelectorOptionsNotHidden): Promise<ElementHandleForTag<K>>;
waitForSelector(selector: string, options?: WaitForSelectorOptionsNotHidden): Promise<HTMLOrSVGElementHandle>;
waitForSelector<K extends keyof HTMLElementTagNameMap>(selector: K, options: PageWaitForSelectorOptions): Promise<ElementHandleForTag<K> | null>;
waitForSelector(selector: string, options: PageWaitForSelectorOptions): Promise<null|HTMLOrSVGElementHandle>;
}

export interface Worker {
Expand All @@ -58,24 +72,28 @@ export interface JSHandle<T = any> {

export interface ElementHandle<T=Node> extends JSHandle<T> {
$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K> | null>;
$(selector: string): Promise<ElementHandle<Element> | null>;
$(selector: string): Promise<HTMLOrSVGElementHandle | null>;

$$<K extends keyof HTMLElementTagNameMap>(selector: K): Promise<ElementHandleForTag<K>[]>;
$$(selector: string): Promise<HTMLOrSVGElementHandle[]>;

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

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

export interface ChromiumBrowser extends Browser {
newPage(options?: BrowserNewPageOptions): Promise<Page<ChromiumBrowserContext>>;
export interface BrowserType<Browser> {

}

export interface BrowserType<Browser> {

export interface ChromiumBrowser extends Browser {
contexts(): Array<ChromiumBrowserContext>;
newContext(options?: BrowserNewContextOptions): Promise<ChromiumBrowserContext>;
}

export interface ChromiumSession {
export interface ChromiumSession {
on: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
addListener: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
off: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
Expand Down
125 changes: 98 additions & 27 deletions utils/generate_types/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ playwright.chromium.launch().then(async browser => {
});
const assertion : AssertType<number, typeof result> = true;
console.log(await page.evaluate("1 + 2"));
page.$eval('.foo', e => e.style);
}

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

page.keyboard.type("Hello"); // Types instantly
page.keyboard.type("World", { delay: 100 }); // Types slower, like a user
await page.route(str => {
const assertion : AssertType<string, typeof str> = true;
return true;
}, interceptedRequest => {
interceptedRequest.continue();
return 'something random for no reason';
});

await page.keyboard.type("Hello"); // Types instantly
await page.keyboard.type("World", { delay: 100 }); // Types slower, like a user

const watchDog = page.waitForFunction("window.innerWidth < 100");
page.setViewportSize({ width: 50, height: 50 });
Expand Down Expand Up @@ -320,36 +329,24 @@ playwright.chromium.launch().then(async browser => {
await browser.close();
})();

// targets/protocol
// protocol
(async () => {
const browser = await playwright.chromium.launch();
const page = await browser.newPage();
const context = page.context();
const target = context.pageTarget(page);

{
const url = target.url();
const assertion : AssertType<string, typeof url> = true;
}

{
const session = await target.createCDPSession();
const context = await browser.newContext();
const session = await context.createSession(await context.newPage());

session.on('Runtime.executionContextCreated', payload => {
const id = payload.context.id;
const assertion : AssertType<number, typeof id> = true;
})

const obj = await session.send('Runtime.evaluate', {
expression: '1 + 1'
});
const type = obj.result.type;
const assertion : AssertType<string, typeof type> = true;
await session.detach()
}

session.on('Runtime.executionContextCreated', payload => {
const id = payload.context.id;
const assertion : AssertType<number, typeof id> = true;
})

// TODO popups need to be chromium pages :O
const obj = await session.send('Runtime.evaluate', {
expression: '1 + 1'
});
const type = obj.result.type;
const assertion : AssertType<string, typeof type> = true;
await session.detach()


await browser.close();
Expand Down Expand Up @@ -426,3 +423,77 @@ playwright.chromium.launch().then(async browser => {
}, 5);
await browser.close();
})();

// query selectors

(async () => {
const browser = await playwright.chromium.launch();
const page = await browser.newPage();
const frame = page.mainFrame();
const element = await page.waitForSelector('some-fake-element');
const elementLikes = [page, frame, element];
for (const elementLike of elementLikes) {
{
const handle = await elementLike.$('body');
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>, typeof handle> = true;
}
{
const handle = await elementLike.$('something-strange');
const top = await handle!.evaluate(element => element.style.top);
const assertion : AssertType<string, typeof top> = true;
}

{
const handles = await elementLike.$$('body');
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>[], typeof handles> = true;
}

{
const handles = await elementLike.$$('something-strange');
const top = await handles[0].evaluate(element => element.style.top);
const assertion : AssertType<string, typeof top> = true;
}
}

const frameLikes = [page, frame];
for (const frameLike of frameLikes) {
{
const handle = await frameLike.waitForSelector('body');
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>, typeof handle> = true;
const canBeNull : AssertType<null, typeof handle> = false;
}
{
const visibility = Math.random() > .5 ? 'any': 'visible';
const handle = await frameLike.waitForSelector('body', {visibility});
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>, typeof handle> = true;
const canBeNull : AssertType<null, typeof handle> = false;
}
{
const visibility = Math.random() > .5 ? 'hidden': 'visible';
const handle = await frameLike.waitForSelector('body', {visibility});
const bodyAssertion : AssertType<playwright.ElementHandle<HTMLBodyElement>, typeof handle> = true;
const canBeNull : AssertType<null, typeof handle> = true;
}

{
const handle = await frameLike.waitForSelector('something-strange');
const elementAssertion : AssertType<playwright.ElementHandle<HTMLElement|SVGElement>, typeof handle> = true;
const canBeNull : AssertType<null, typeof handle> = false;
}
{
const visibility = Math.random() > .5 ? 'any': 'visible';
const handle = await frameLike.waitForSelector('something-strange', {visibility});
const elementAssertion : AssertType<playwright.ElementHandle<HTMLElement|SVGElement>, typeof handle> = true;
const canBeNull : AssertType<null, typeof handle> = false;
}
{
const visibility = Math.random() > .5 ? 'hidden': 'visible';
const handle = await frameLike.waitForSelector('something-strange', {visibility});
const elementAssertion : AssertType<playwright.ElementHandle<HTMLElement|SVGElement>, typeof handle> = true;
const canBeNull : AssertType<null, typeof handle> = true;
}
}


await browser.close();
})();

0 comments on commit 9879817

Please sign in to comment.