chore: add type tests (#8588)
This commit is contained in:
parent
7001322cd1
commit
e499515fd6
@ -3,6 +3,5 @@ build/
|
|||||||
coverage/
|
coverage/
|
||||||
doclint/
|
doclint/
|
||||||
lib/
|
lib/
|
||||||
test-ts-types/
|
|
||||||
tsconfig.tsbuildinfo
|
tsconfig.tsbuildinfo
|
||||||
vendor/
|
vendor/
|
||||||
|
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@ -55,8 +55,7 @@ jobs:
|
|||||||
# See https://github.com/puppeteer/puppeteer/issues/7710 for more info
|
# See https://github.com/puppeteer/puppeteer/issues/7710 for more info
|
||||||
# npm run generate:docs
|
# npm run generate:docs
|
||||||
npm run test:protocol-revision
|
npm run test:protocol-revision
|
||||||
# TODO(jrandolf): Find a better way to test TypeScript source files.
|
npm run test:types
|
||||||
# npm run test:types
|
|
||||||
|
|
||||||
- name: Run commit lint
|
- name: Run commit lint
|
||||||
run: |
|
run: |
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -15,7 +15,5 @@ node_modules/
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
puppeteer.api.json
|
puppeteer.api.json
|
||||||
puppeteer*.tgz
|
puppeteer*.tgz
|
||||||
test-ts-types/**/dist/
|
|
||||||
test-ts-types/**/node_modules
|
|
||||||
tsconfig.tsbuildinfo
|
tsconfig.tsbuildinfo
|
||||||
yarn.lock
|
yarn.lock
|
@ -9,7 +9,6 @@ lib/
|
|||||||
node_modules/
|
node_modules/
|
||||||
package-lock.json
|
package-lock.json
|
||||||
package.json
|
package.json
|
||||||
test-ts-types/
|
|
||||||
test/assets/
|
test/assets/
|
||||||
tsconfig.tsbuildinfo
|
tsconfig.tsbuildinfo
|
||||||
vendor/
|
vendor/
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
"test:pinned-deps": "ts-node -s scripts/ensure-pinned-deps",
|
"test:pinned-deps": "ts-node -s scripts/ensure-pinned-deps",
|
||||||
"test:install": "scripts/test-install.sh",
|
"test:install": "scripts/test-install.sh",
|
||||||
"test:debug": "npm run build:test && mocha --inspect-brk",
|
"test:debug": "npm run build:test && mocha --inspect-brk",
|
||||||
"test:types": "ts-node -s scripts/test-ts-definition-files.ts",
|
"test:types": "tsc -b test-d",
|
||||||
"prepublishOnly": "npm run build",
|
"prepublishOnly": "npm run build",
|
||||||
"prepare": "node typescript-if-required.js && ([[ $HUSKY = 0 ]] || husky install)",
|
"prepare": "node typescript-if-required.js && ([[ $HUSKY = 0 ]] || husky install)",
|
||||||
"lint": "npm run build && npm run lint:eslint && npm run doc && npm run lint:prettier",
|
"lint": "npm run build && npm run lint:eslint && npm run doc && npm run lint:prettier",
|
||||||
@ -126,6 +126,7 @@
|
|||||||
"sinon": "14.0.0",
|
"sinon": "14.0.0",
|
||||||
"source-map-support": "0.5.21",
|
"source-map-support": "0.5.21",
|
||||||
"text-diff": "1.0.1",
|
"text-diff": "1.0.1",
|
||||||
|
"tsd": "0.21.0",
|
||||||
"typescript": "4.7.2"
|
"typescript": "4.7.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,217 +0,0 @@
|
|||||||
import {spawnSync} from 'child_process';
|
|
||||||
import {version} from '../package.json';
|
|
||||||
import path from 'path';
|
|
||||||
import fs from 'fs';
|
|
||||||
const PROJECT_FOLDERS_ROOT = 'test-ts-types';
|
|
||||||
const EXPECTED_ERRORS = new Map<string, string[]>([
|
|
||||||
[
|
|
||||||
'ts-esm-import-esm-output',
|
|
||||||
[
|
|
||||||
"bad.ts(6,35): error TS2551: Property 'launh' does not exist on type",
|
|
||||||
"bad.ts(8,29): error TS2551: Property 'devics' does not exist on type",
|
|
||||||
'bad.ts(12,39): error TS2554: Expected 0 arguments, but got 1.',
|
|
||||||
"bad.ts(20,5): error TS2345: Argument of type '(divElem: number) => any' is not assignable to parameter of type 'EvaluateFn<HTMLAnchorElement, any, any>'.",
|
|
||||||
"bad.ts(20,34): error TS2339: Property 'innerText' does not exist on type 'number'.",
|
|
||||||
"bad.ts(24,45): error TS2344: Type '(x: number) => string' does not satisfy the constraint 'EvaluateFn<HTMLAnchorElement, any, any>'.",
|
|
||||||
"bad.ts(27,34): error TS2339: Property 'innerText' does not exist on type 'number'.",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'ts-esm-import-cjs-output',
|
|
||||||
[
|
|
||||||
"bad.ts(6,35): error TS2551: Property 'launh' does not exist on type",
|
|
||||||
"bad.ts(8,29): error TS2551: Property 'devics' does not exist on type",
|
|
||||||
'bad.ts(12,39): error TS2554: Expected 0 arguments, but got 1.',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'ts-cjs-import-cjs-output',
|
|
||||||
[
|
|
||||||
"bad.ts(5,35): error TS2551: Property 'launh' does not exist on type",
|
|
||||||
"bad.ts(7,29): error TS2551: Property 'devics' does not exist on type",
|
|
||||||
'bad.ts(11,39): error TS2554: Expected 0 arguments, but got 1.',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'js-esm-import-cjs-output',
|
|
||||||
[
|
|
||||||
"bad.js(5,35): error TS2551: Property 'launh' does not exist on type",
|
|
||||||
"bad.js(7,29): error TS2551: Property 'devics' does not exist on type",
|
|
||||||
'bad.js(11,39): error TS2554: Expected 0 arguments, but got 1.',
|
|
||||||
"bad.js(15,9): error TS2322: Type 'ElementHandle<HTMLElement> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
|
|
||||||
"bad.js(22,5): error TS2345: Argument of type '(divElem: number) => any' is not assignable to parameter of type 'EvaluateFn<HTMLElement, any, any>'.",
|
|
||||||
"bad.js(22,26): error TS2339: Property 'innerText' does not exist on type 'number'.",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'js-cjs-import-esm-output',
|
|
||||||
[
|
|
||||||
"bad.js(5,35): error TS2551: Property 'launh' does not exist on type",
|
|
||||||
"bad.js(7,29): error TS2551: Property 'devics' does not exist on type",
|
|
||||||
'bad.js(11,39): error TS2554: Expected 0 arguments, but got 1.',
|
|
||||||
"bad.js(15,9): error TS2322: Type 'ElementHandle<HTMLElement> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'js-esm-import-esm-output',
|
|
||||||
[
|
|
||||||
"bad.js(5,35): error TS2551: Property 'launh' does not exist on type",
|
|
||||||
"bad.js(7,29): error TS2551: Property 'devics' does not exist on type",
|
|
||||||
'bad.js(11,39): error TS2554: Expected 0 arguments, but got 1.',
|
|
||||||
"bad.js(15,9): error TS2322: Type 'ElementHandle<HTMLElement> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'js-cjs-import-cjs-output',
|
|
||||||
[
|
|
||||||
"bad.js(5,35): error TS2551: Property 'launh' does not exist on type",
|
|
||||||
"bad.js(7,29): error TS2551: Property 'devics' does not exist on type",
|
|
||||||
'bad.js(11,39): error TS2554: Expected 0 arguments, but got 1.',
|
|
||||||
"bad.js(15,9): error TS2322: Type 'ElementHandle<HTMLElement> | null' is not assignable to type 'ElementHandle<HTMLElement>'",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
const PROJECT_FOLDERS = [...EXPECTED_ERRORS.keys()];
|
|
||||||
|
|
||||||
if (!process.env['CI']) {
|
|
||||||
console.log(`IMPORTANT: this script assumes you have compiled Puppeteer
|
|
||||||
and its types file before running. Make sure you have run:
|
|
||||||
=> npm run build:tsc && npm run generate:types
|
|
||||||
before executing this script locally.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
function packPuppeteer() {
|
|
||||||
console.log('Packing Puppeteer');
|
|
||||||
const result = spawnSync('npm', ['pack'], {
|
|
||||||
encoding: 'utf-8',
|
|
||||||
});
|
|
||||||
if (result.status !== 0) {
|
|
||||||
console.log('Failed to pack Puppeteer', result.stderr);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move from puppeteer-X.Y.Z.tgz to puppeteer.tgz so we don't have to update
|
|
||||||
// it when versions change.
|
|
||||||
const moveResult = spawnSync('mv', [
|
|
||||||
`puppeteer-${version}.tgz`,
|
|
||||||
'puppeteer.tgz',
|
|
||||||
]);
|
|
||||||
if (moveResult.status !== 0) {
|
|
||||||
console.log('Failed to rename Puppeteer tar', moveResult.stderr);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return `puppeteer.tgz`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tar = packPuppeteer();
|
|
||||||
const tarPath = path.join(process.cwd(), tar);
|
|
||||||
|
|
||||||
function compileAndCatchErrors(projectLocation: string) {
|
|
||||||
const {status, stdout, stderr} = spawnSync('npm', ['run', 'compile'], {
|
|
||||||
cwd: projectLocation,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
});
|
|
||||||
const tsErrorMesssage = stdout.split('\n');
|
|
||||||
|
|
||||||
if (status === 0) {
|
|
||||||
console.error(
|
|
||||||
`Running tsc on ${projectLocation} succeeded without triggering the expected errors.`
|
|
||||||
);
|
|
||||||
console.log(stdout, stderr);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
tsErrorMesssage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function testProject(folder: string) {
|
|
||||||
console.log('\nTesting:', folder);
|
|
||||||
const projectLocation = path.join(
|
|
||||||
process.cwd(),
|
|
||||||
PROJECT_FOLDERS_ROOT,
|
|
||||||
folder
|
|
||||||
);
|
|
||||||
|
|
||||||
const tarLocation = path.relative(projectLocation, tarPath);
|
|
||||||
console.log('===> Clearing left over node_modules to ensure clean slate');
|
|
||||||
try {
|
|
||||||
fs.rmdirSync(path.join(projectLocation, 'node_modules'), {
|
|
||||||
recursive: true,
|
|
||||||
});
|
|
||||||
} catch (_error) {
|
|
||||||
// We don't care if this errors because if it did it's most likely because
|
|
||||||
// there was no node_modules folder, which is fine.
|
|
||||||
}
|
|
||||||
console.log('===> Installing Puppeteer from tar file', tarLocation);
|
|
||||||
const {status, stderr, stdout} = spawnSync('npm', ['install', tarLocation], {
|
|
||||||
env: {
|
|
||||||
...process.env,
|
|
||||||
PUPPETEER_SKIP_DOWNLOAD: '1',
|
|
||||||
},
|
|
||||||
cwd: projectLocation,
|
|
||||||
encoding: 'utf-8',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
console.error(
|
|
||||||
'Installing the tar file unexpectedly failed',
|
|
||||||
stdout,
|
|
||||||
stderr
|
|
||||||
);
|
|
||||||
process.exit(status);
|
|
||||||
}
|
|
||||||
console.log('===> Running compile to ensure expected errors only.');
|
|
||||||
const result = compileAndCatchErrors(projectLocation);
|
|
||||||
const expectedErrors = EXPECTED_ERRORS.get(folder) || [];
|
|
||||||
if (
|
|
||||||
result.tsErrorMesssage.find(line => {
|
|
||||||
return line.includes('good.ts') || line.includes('good.js');
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
console.error(
|
|
||||||
`Error for ${projectLocation} contained unexpected failures in good.ts/good.js:\n${result.tsErrorMesssage.join(
|
|
||||||
'\n'
|
|
||||||
)}`
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
const errorsInTsMessage = result.tsErrorMesssage.filter(line => {
|
|
||||||
return line.includes('bad.ts') || line.includes('bad.js');
|
|
||||||
});
|
|
||||||
const expectedErrorsThatHaveOccurred = new Set<string>();
|
|
||||||
const unexpectedErrors = errorsInTsMessage.filter(message => {
|
|
||||||
const isExpected = expectedErrors.some(expectedError => {
|
|
||||||
const isExpected = message.startsWith(expectedError);
|
|
||||||
if (isExpected) {
|
|
||||||
expectedErrorsThatHaveOccurred.add(expectedError);
|
|
||||||
}
|
|
||||||
return isExpected;
|
|
||||||
});
|
|
||||||
return !isExpected;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (unexpectedErrors.length) {
|
|
||||||
console.error(
|
|
||||||
`${projectLocation} had unexpected TS errors: ${unexpectedErrors.join(
|
|
||||||
'\n'
|
|
||||||
)}`
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
expectedErrors.forEach(expected => {
|
|
||||||
if (!expectedErrorsThatHaveOccurred.has(expected)) {
|
|
||||||
console.error(
|
|
||||||
`${projectLocation} expected error that was not thrown: ${expected}`
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log('===> ✅ Type-checked correctly.');
|
|
||||||
}
|
|
||||||
|
|
||||||
PROJECT_FOLDERS.forEach(folder => {
|
|
||||||
testProject(folder);
|
|
||||||
});
|
|
@ -167,7 +167,7 @@ export class JSHandle<T = unknown> {
|
|||||||
[this, ...Params]
|
[this, ...Params]
|
||||||
>
|
>
|
||||||
>(
|
>(
|
||||||
pageFunction: Func,
|
pageFunction: Func | string,
|
||||||
...args: Params
|
...args: Params
|
||||||
): // @ts-expect-error Circularity here is okay because we only need the return
|
): // @ts-expect-error Circularity here is okay because we only need the return
|
||||||
// type which doesn't use `this`.
|
// type which doesn't use `this`.
|
||||||
|
158
test-d/ElementHandle.test-d.ts
Normal file
158
test-d/ElementHandle.test-d.ts
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
import {expectNotType, expectType} from 'tsd';
|
||||||
|
import {ElementHandle} from '../lib/esm/puppeteer/common/ElementHandle.js';
|
||||||
|
|
||||||
|
declare const handle: ElementHandle;
|
||||||
|
|
||||||
|
{
|
||||||
|
{
|
||||||
|
expectType<ElementHandle<HTMLAnchorElement> | null>(await handle.$('a'));
|
||||||
|
expectNotType<ElementHandle<Element> | null>(await handle.$('a'));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
expectType<ElementHandle<HTMLDivElement> | null>(await handle.$('div'));
|
||||||
|
expectNotType<ElementHandle<Element> | null>(await handle.$('div'));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
expectType<ElementHandle<Element> | null>(await handle.$('some-custom'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
{
|
||||||
|
expectType<ElementHandle<HTMLAnchorElement>[]>(await handle.$$('a'));
|
||||||
|
expectNotType<ElementHandle<Element>[]>(await handle.$$('a'));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
expectType<ElementHandle<HTMLDivElement>[]>(await handle.$$('div'));
|
||||||
|
expectNotType<ElementHandle<Element>[]>(await handle.$$('div'));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
expectType<ElementHandle<Element>[]>(await handle.$$('some-custom'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
expectType<void>(
|
||||||
|
await handle.$eval(
|
||||||
|
'a',
|
||||||
|
(element, int) => {
|
||||||
|
expectType<HTMLAnchorElement>(element);
|
||||||
|
expectType<number>(int);
|
||||||
|
},
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expectType<void>(
|
||||||
|
await handle.$eval(
|
||||||
|
'div',
|
||||||
|
(element, int, str) => {
|
||||||
|
expectType<HTMLDivElement>(element);
|
||||||
|
expectType<number>(int);
|
||||||
|
expectType<string>(str);
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
''
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expectType<number>(
|
||||||
|
await handle.$eval(
|
||||||
|
'a',
|
||||||
|
(element, value) => {
|
||||||
|
expectType<HTMLAnchorElement>(element);
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expectType<number>(
|
||||||
|
await handle.$eval(
|
||||||
|
'some-element',
|
||||||
|
(element, value) => {
|
||||||
|
expectType<Element>(element);
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expectType<HTMLAnchorElement>(
|
||||||
|
await handle.$eval('a', element => {
|
||||||
|
return element;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expectType<unknown>(await handle.$eval('a', 'document'));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
expectType<void>(
|
||||||
|
await handle.$$eval(
|
||||||
|
'a',
|
||||||
|
(elements, int) => {
|
||||||
|
expectType<HTMLAnchorElement[]>(elements);
|
||||||
|
expectType<number>(int);
|
||||||
|
},
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expectType<void>(
|
||||||
|
await handle.$$eval(
|
||||||
|
'div',
|
||||||
|
(elements, int, str) => {
|
||||||
|
expectType<HTMLDivElement[]>(elements);
|
||||||
|
expectType<number>(int);
|
||||||
|
expectType<string>(str);
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
''
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expectType<number>(
|
||||||
|
await handle.$$eval(
|
||||||
|
'a',
|
||||||
|
(elements, value) => {
|
||||||
|
expectType<HTMLAnchorElement[]>(elements);
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expectType<number>(
|
||||||
|
await handle.$$eval(
|
||||||
|
'some-element',
|
||||||
|
(elements, value) => {
|
||||||
|
expectType<Element[]>(elements);
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
expectType<HTMLAnchorElement[]>(
|
||||||
|
await handle.$$eval('a', elements => {
|
||||||
|
return elements;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expectType<unknown>(await handle.$$eval('a', 'document'));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
{
|
||||||
|
expectType<ElementHandle<HTMLAnchorElement> | null>(
|
||||||
|
await handle.waitForSelector('a')
|
||||||
|
);
|
||||||
|
expectNotType<ElementHandle<Element> | null>(
|
||||||
|
await handle.waitForSelector('a')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
expectType<ElementHandle<HTMLDivElement> | null>(
|
||||||
|
await handle.waitForSelector('div')
|
||||||
|
);
|
||||||
|
expectNotType<ElementHandle<Element> | null>(
|
||||||
|
await handle.waitForSelector('div')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
expectType<ElementHandle<Element> | null>(
|
||||||
|
await handle.waitForSelector('some-custom')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
84
test-d/JSHandle.test-d.ts
Normal file
84
test-d/JSHandle.test-d.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import {expectAssignable, expectNotAssignable, expectType} from 'tsd';
|
||||||
|
import {ElementHandle} from '../lib/esm/puppeteer/common/ElementHandle.js';
|
||||||
|
import {JSHandle} from '../lib/esm/puppeteer/common/JSHandle.js';
|
||||||
|
|
||||||
|
declare const handle: JSHandle;
|
||||||
|
|
||||||
|
{
|
||||||
|
expectType<unknown>(await handle.evaluate('document'));
|
||||||
|
expectType<number>(
|
||||||
|
await handle.evaluate(() => {
|
||||||
|
return 1;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expectType<HTMLElement>(
|
||||||
|
await handle.evaluate(() => {
|
||||||
|
return document.body;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expectType<string>(
|
||||||
|
await handle.evaluate(() => {
|
||||||
|
return '';
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expectType<string>(
|
||||||
|
await handle.evaluate((value, str) => {
|
||||||
|
expectNotAssignable<never>(value);
|
||||||
|
expectType<string>(str);
|
||||||
|
return '';
|
||||||
|
}, '')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
expectType<JSHandle>(await handle.evaluateHandle('document'));
|
||||||
|
expectType<JSHandle<number>>(
|
||||||
|
await handle.evaluateHandle(() => {
|
||||||
|
return 1;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expectType<JSHandle<string>>(
|
||||||
|
await handle.evaluateHandle(() => {
|
||||||
|
return '';
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expectType<JSHandle<string>>(
|
||||||
|
await handle.evaluateHandle((value, str) => {
|
||||||
|
expectNotAssignable<never>(value);
|
||||||
|
expectType<string>(str);
|
||||||
|
return '';
|
||||||
|
}, '')
|
||||||
|
);
|
||||||
|
expectType<ElementHandle<HTMLElement>>(
|
||||||
|
await handle.evaluateHandle(() => {
|
||||||
|
return document.body;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const handle2: JSHandle<{test: number}>;
|
||||||
|
|
||||||
|
{
|
||||||
|
{
|
||||||
|
expectType<JSHandle<number>>(await handle2.getProperty('test'));
|
||||||
|
expectNotAssignable<JSHandle<string>>(await handle2.getProperty('test'));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
expectType<JSHandle<unknown>>(
|
||||||
|
await handle2.getProperty('key-doesnt-exist')
|
||||||
|
);
|
||||||
|
expectAssignable<JSHandle<string>>(
|
||||||
|
await handle2.getProperty('key-doesnt-exist')
|
||||||
|
);
|
||||||
|
expectAssignable<JSHandle<number>>(
|
||||||
|
await handle2.getProperty('key-doesnt-exist')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
handle.evaluate((value, other) => {
|
||||||
|
expectType<unknown>(value);
|
||||||
|
expectType<{test: number}>(other);
|
||||||
|
}, handle2);
|
||||||
|
}
|
15
test-d/puppeteer.test-d.ts
Normal file
15
test-d/puppeteer.test-d.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import {expectType} from 'tsd';
|
||||||
|
import {
|
||||||
|
connect,
|
||||||
|
createBrowserFetcher,
|
||||||
|
defaultArgs,
|
||||||
|
executablePath,
|
||||||
|
launch,
|
||||||
|
default as puppeteer,
|
||||||
|
} from '../lib/esm/puppeteer/puppeteer.js';
|
||||||
|
|
||||||
|
expectType<typeof launch>(puppeteer.launch);
|
||||||
|
expectType<typeof connect>(puppeteer.connect);
|
||||||
|
expectType<typeof createBrowserFetcher>(puppeteer.createBrowserFetcher);
|
||||||
|
expectType<typeof defaultArgs>(puppeteer.defaultArgs);
|
||||||
|
expectType<typeof executablePath>(puppeteer.executablePath);
|
8
test-d/tsconfig.json
Normal file
8
test-d/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": true,
|
||||||
|
"module": "ESNext"
|
||||||
|
},
|
||||||
|
"references": [{"path": "../src/tsconfig.esm.json"}]
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
const puppeteer = require('puppeteer');
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
// Typo in "launch"
|
|
||||||
const browser = await puppeteer.launh();
|
|
||||||
// Typo: "devices"
|
|
||||||
const devices = puppeteer.devics;
|
|
||||||
console.log(devices);
|
|
||||||
const browser2 = await puppeteer.launch();
|
|
||||||
// 'foo' is invalid argument
|
|
||||||
const page = await browser2.newPage('foo');
|
|
||||||
/**
|
|
||||||
* @type {puppeteer.ElementHandle<HTMLElement>}
|
|
||||||
*/
|
|
||||||
const div = await page.$('div');
|
|
||||||
console.log('got a div!', div);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,17 +0,0 @@
|
|||||||
const puppeteer = require('puppeteer');
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const browser = await puppeteer.launch();
|
|
||||||
const devices = puppeteer.devices;
|
|
||||||
console.log(devices);
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const div = await page.$('div');
|
|
||||||
if (div) {
|
|
||||||
/**
|
|
||||||
* @type {puppeteer.ElementHandle<HTMLAnchorElement>}
|
|
||||||
*/
|
|
||||||
const newDiv = div;
|
|
||||||
console.log('got a div!', newDiv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "test-ts-types-ts-esm",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
|
||||||
"description": "Test project with TypeScript, ESM output",
|
|
||||||
"scripts": {
|
|
||||||
"compile": "../../node_modules/.bin/tsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"puppeteer": "file:../../puppeteer.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"checkJs": true,
|
|
||||||
"allowJs": true,
|
|
||||||
"strict": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
"moduleResolution": "node"
|
|
||||||
},
|
|
||||||
"files": ["good.js", "bad.js"]
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
const puppeteer = require('puppeteer');
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
// Typo in "launch"
|
|
||||||
const browser = await puppeteer.launh();
|
|
||||||
// Typo: "devices"
|
|
||||||
const devices = puppeteer.devics;
|
|
||||||
console.log(devices);
|
|
||||||
const browser2 = await puppeteer.launch();
|
|
||||||
// 'foo' is invalid argument
|
|
||||||
const page = await browser2.newPage('foo');
|
|
||||||
/**
|
|
||||||
* @type {puppeteer.ElementHandle<HTMLElement>}
|
|
||||||
*/
|
|
||||||
const div = await page.$('div');
|
|
||||||
console.log('got a div!', div);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,17 +0,0 @@
|
|||||||
const puppeteer = require('puppeteer');
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const browser = await puppeteer.launch();
|
|
||||||
const devices = puppeteer.devices;
|
|
||||||
console.log(devices);
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const div = await page.$('div');
|
|
||||||
if (div) {
|
|
||||||
/**
|
|
||||||
* @type {puppeteer.ElementHandle<HTMLAnchorElement>}
|
|
||||||
*/
|
|
||||||
const newDiv = div;
|
|
||||||
console.log('got a div!', newDiv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "test-ts-types-ts-esm",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
|
||||||
"description": "Test project with TypeScript, ESM output",
|
|
||||||
"scripts": {
|
|
||||||
"compile": "../../node_modules/.bin/tsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"puppeteer": "file:../../puppeteer.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "esnext",
|
|
||||||
"checkJs": true,
|
|
||||||
"allowJs": true,
|
|
||||||
"strict": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
"moduleResolution": "node"
|
|
||||||
},
|
|
||||||
"files": ["good.js", "bad.js"]
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
// Typo in "launch"
|
|
||||||
const browser = await puppeteer.launh();
|
|
||||||
// Typo: "devices"
|
|
||||||
const devices = puppeteer.devics;
|
|
||||||
console.log(devices);
|
|
||||||
const browser2 = await puppeteer.launch();
|
|
||||||
// 'foo' is invalid argument
|
|
||||||
const page = await browser2.newPage('foo');
|
|
||||||
/**
|
|
||||||
* @type {puppeteer.ElementHandle<HTMLElement>}
|
|
||||||
*/
|
|
||||||
const div = await page.$('div');
|
|
||||||
console.log('got a div!', div);
|
|
||||||
const contentsOfDiv = await div.evaluate(
|
|
||||||
/**
|
|
||||||
* @param {number} divElem
|
|
||||||
* @returns number
|
|
||||||
*/
|
|
||||||
(divElem) => divElem.innerText
|
|
||||||
);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,17 +0,0 @@
|
|||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const browser = await puppeteer.launch();
|
|
||||||
const devices = puppeteer.devices;
|
|
||||||
console.log(devices);
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const div = await page.$('div');
|
|
||||||
if (div) {
|
|
||||||
/**
|
|
||||||
* @type {puppeteer.ElementHandle<HTMLAnchorElement>}
|
|
||||||
*/
|
|
||||||
const newDiv = div;
|
|
||||||
console.log('got a div!', newDiv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "test-ts-types-ts-esm",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
|
||||||
"description": "Test project with TypeScript, ESM output",
|
|
||||||
"scripts": {
|
|
||||||
"compile": "../../node_modules/.bin/tsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"puppeteer": "file:../../puppeteer.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"checkJs": true,
|
|
||||||
"allowJs": true,
|
|
||||||
"strict": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
"moduleResolution": "node"
|
|
||||||
},
|
|
||||||
"files": ["good.js", "bad.js"]
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
// Typo in "launch"
|
|
||||||
const browser = await puppeteer.launh();
|
|
||||||
// Typo: "devices"
|
|
||||||
const devices = puppeteer.devics;
|
|
||||||
console.log(devices);
|
|
||||||
const browser2 = await puppeteer.launch();
|
|
||||||
// 'foo' is invalid argument
|
|
||||||
const page = await browser2.newPage('foo');
|
|
||||||
/**
|
|
||||||
* @type {puppeteer.ElementHandle<HTMLElement>}
|
|
||||||
*/
|
|
||||||
const div = await page.$('div');
|
|
||||||
console.log('got a div!', div);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,17 +0,0 @@
|
|||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const browser = await puppeteer.launch();
|
|
||||||
const devices = puppeteer.devices;
|
|
||||||
console.log(devices);
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const div = await page.$('div');
|
|
||||||
if (div) {
|
|
||||||
/**
|
|
||||||
* @type {puppeteer.ElementHandle<HTMLAnchorElement>}
|
|
||||||
*/
|
|
||||||
const newDiv = div;
|
|
||||||
console.log('got a div!', newDiv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "test-ts-types-ts-esm",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
|
||||||
"description": "Test project with TypeScript, ESM output",
|
|
||||||
"scripts": {
|
|
||||||
"compile": "../../node_modules/.bin/tsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"puppeteer": "file:../../puppeteer.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "esnext",
|
|
||||||
"checkJs": true,
|
|
||||||
"allowJs": true,
|
|
||||||
"strict": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
"moduleResolution": "node"
|
|
||||||
},
|
|
||||||
"files": ["good.js", "bad.js"]
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import puppeteer = require('puppeteer');
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
// Typo in "launch"
|
|
||||||
const browser = await puppeteer.launh();
|
|
||||||
// Typo: "devices"
|
|
||||||
const devices = puppeteer.devics;
|
|
||||||
console.log(devices);
|
|
||||||
const browser2 = await puppeteer.launch();
|
|
||||||
// 'foo' is invalid argument
|
|
||||||
const page = await browser2.newPage('foo');
|
|
||||||
const div = (await page.$(
|
|
||||||
'div'
|
|
||||||
)) as puppeteer.ElementHandle<HTMLAnchorElement>;
|
|
||||||
console.log('got a div!', div);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,16 +0,0 @@
|
|||||||
import puppeteer = require('puppeteer');
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const browser = await puppeteer.launch();
|
|
||||||
const devices = puppeteer.devices;
|
|
||||||
console.log(devices);
|
|
||||||
const page = await browser.newPage();
|
|
||||||
page.on('request', (request) => {
|
|
||||||
const resourceType = request.resourceType();
|
|
||||||
});
|
|
||||||
const div = (await page.$(
|
|
||||||
'div'
|
|
||||||
)) as puppeteer.ElementHandle<HTMLAnchorElement>;
|
|
||||||
console.log('got a div!', div);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "test-ts-types-ts-esm",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
|
||||||
"description": "Test project with TypeScript, ESM output",
|
|
||||||
"scripts": {
|
|
||||||
"compile": "../../node_modules/.bin/tsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"puppeteer": "file:../../puppeteer.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"strict": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
"moduleResolution": "node"
|
|
||||||
},
|
|
||||||
"files": ["good.ts", "bad.ts"]
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
// eslint-disable-next-line import/extensions
|
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
// Typo in "launch"
|
|
||||||
const browser = await puppeteer.launh();
|
|
||||||
// Typo: "devices"
|
|
||||||
const devices = puppeteer.devics;
|
|
||||||
console.log(devices);
|
|
||||||
const browser2 = await puppeteer.launch();
|
|
||||||
// 'foo' is invalid argument
|
|
||||||
const page = await browser2.newPage('foo');
|
|
||||||
const div = (await page.$(
|
|
||||||
'div'
|
|
||||||
)) as puppeteer.ElementHandle<HTMLAnchorElement>;
|
|
||||||
console.log('got a div!', div);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,13 +0,0 @@
|
|||||||
// eslint-disable-next-line import/extensions
|
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import type { ElementHandle } from 'puppeteer';
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const browser = await puppeteer.launch();
|
|
||||||
const devices = puppeteer.devices;
|
|
||||||
console.log(devices);
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const div = (await page.$('div')) as ElementHandle<HTMLAnchorElement>;
|
|
||||||
console.log('got a div!', div);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "test-ts-types-ts-esm",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
|
||||||
"description": "Test project with TypeScript, ESM output",
|
|
||||||
"scripts": {
|
|
||||||
"compile": "../../node_modules/.bin/tsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"puppeteer": "file:../../puppeteer.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "commonjs",
|
|
||||||
"strict": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
"moduleResolution": "node"
|
|
||||||
},
|
|
||||||
"files": ["good.ts", "bad.ts"]
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
// eslint-disable-next-line import/extensions
|
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
// Typo in "launch"
|
|
||||||
const browser = await puppeteer.launh();
|
|
||||||
// Typo: "devices"
|
|
||||||
const devices = puppeteer.devics;
|
|
||||||
console.log(devices);
|
|
||||||
const browser2 = await puppeteer.launch();
|
|
||||||
// 'foo' is invalid argument
|
|
||||||
const page = await browser2.newPage('foo');
|
|
||||||
const div = (await page.$(
|
|
||||||
'div'
|
|
||||||
)) as puppeteer.ElementHandle<HTMLAnchorElement>;
|
|
||||||
console.log('got a div!', div);
|
|
||||||
const contentsOfDiv = await div.evaluate(
|
|
||||||
// Bad: the type system will know here that divElem is an HTMLAnchorElement
|
|
||||||
// and won't let me tell it it's a number
|
|
||||||
(divElem: number) => divElem.innerText
|
|
||||||
);
|
|
||||||
// Bad: the type system will know here that divElem is an HTMLAnchorElement
|
|
||||||
// and won't let me tell it it's a number via the generic
|
|
||||||
const contentsOfDiv2 = await div.evaluate<(x: number) => string>(
|
|
||||||
// Bad: now I've forced it to be a number (which is an error also)
|
|
||||||
// I can't call `innerText` on it.
|
|
||||||
(divElem: number) => divElem.innerText
|
|
||||||
);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,15 +0,0 @@
|
|||||||
// eslint-disable-next-line import/extensions
|
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import type { ElementHandle } from 'puppeteer';
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
const browser = await puppeteer.launch();
|
|
||||||
const devices = puppeteer.devices;
|
|
||||||
console.log(devices);
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const div = (await page.$('div')) as ElementHandle<HTMLAnchorElement>;
|
|
||||||
console.log('got a div!', div);
|
|
||||||
|
|
||||||
const contentsOfDiv = await div.evaluate((divElem) => divElem.innerText);
|
|
||||||
}
|
|
||||||
run();
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "test-ts-types-ts-esm",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
|
||||||
"description": "Test project with TypeScript, ESM output",
|
|
||||||
"scripts": {
|
|
||||||
"compile": "../../node_modules/.bin/tsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"puppeteer": "file:../../puppeteer.tgz"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "esnext",
|
|
||||||
"strict": true,
|
|
||||||
"outDir": "dist",
|
|
||||||
"moduleResolution": "node"
|
|
||||||
},
|
|
||||||
"files": ["good.ts", "bad.ts"]
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user