chore: add type tests (#8588)

This commit is contained in:
jrandolf 2022-06-27 10:57:31 +02:00 committed by GitHub
parent 7001322cd1
commit e499515fd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 269 additions and 636 deletions

View File

@ -3,6 +3,5 @@ build/
coverage/
doclint/
lib/
test-ts-types/
tsconfig.tsbuildinfo
vendor/

View File

@ -55,8 +55,7 @@ jobs:
# See https://github.com/puppeteer/puppeteer/issues/7710 for more info
# npm run generate:docs
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
run: |

2
.gitignore vendored
View File

@ -15,7 +15,5 @@ node_modules/
package-lock.json
puppeteer.api.json
puppeteer*.tgz
test-ts-types/**/dist/
test-ts-types/**/node_modules
tsconfig.tsbuildinfo
yarn.lock

View File

@ -9,7 +9,6 @@ lib/
node_modules/
package-lock.json
package.json
test-ts-types/
test/assets/
tsconfig.tsbuildinfo
vendor/

View File

@ -36,7 +36,7 @@
"test:pinned-deps": "ts-node -s scripts/ensure-pinned-deps",
"test:install": "scripts/test-install.sh",
"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",
"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",
@ -126,6 +126,7 @@
"sinon": "14.0.0",
"source-map-support": "0.5.21",
"text-diff": "1.0.1",
"tsd": "0.21.0",
"typescript": "4.7.2"
}
}

View File

@ -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);
});

View File

@ -167,7 +167,7 @@ export class JSHandle<T = unknown> {
[this, ...Params]
>
>(
pageFunction: Func,
pageFunction: Func | string,
...args: Params
): // @ts-expect-error Circularity here is okay because we only need the return
// type which doesn't use `this`.

View 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
View 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);
}

View 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
View File

@ -0,0 +1,8 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"noEmit": true,
"module": "ESNext"
},
"references": [{"path": "../src/tsconfig.esm.json"}]
}

View File

@ -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();

View File

@ -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();

View File

@ -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"
}
}

View File

@ -1,11 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"checkJs": true,
"allowJs": true,
"strict": true,
"outDir": "dist",
"moduleResolution": "node"
},
"files": ["good.js", "bad.js"]
}

View File

@ -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();

View File

@ -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();

View File

@ -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"
}
}

View File

@ -1,11 +0,0 @@
{
"compilerOptions": {
"module": "esnext",
"checkJs": true,
"allowJs": true,
"strict": true,
"outDir": "dist",
"moduleResolution": "node"
},
"files": ["good.js", "bad.js"]
}

View File

@ -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();

View File

@ -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();

View File

@ -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"
}
}

View File

@ -1,11 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"checkJs": true,
"allowJs": true,
"strict": true,
"outDir": "dist",
"moduleResolution": "node"
},
"files": ["good.js", "bad.js"]
}

View File

@ -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();

View File

@ -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();

View File

@ -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"
}
}

View File

@ -1,11 +0,0 @@
{
"compilerOptions": {
"module": "esnext",
"checkJs": true,
"allowJs": true,
"strict": true,
"outDir": "dist",
"moduleResolution": "node"
},
"files": ["good.js", "bad.js"]
}

View File

@ -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();

View File

@ -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();

View File

@ -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"
}
}

View File

@ -1,9 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"strict": true,
"outDir": "dist",
"moduleResolution": "node"
},
"files": ["good.ts", "bad.ts"]
}

View File

@ -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();

View File

@ -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();

View File

@ -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"
}
}

View File

@ -1,9 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"strict": true,
"outDir": "dist",
"moduleResolution": "node"
},
"files": ["good.ts", "bad.ts"]
}

View File

@ -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();

View File

@ -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();

View File

@ -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"
}
}

View File

@ -1,9 +0,0 @@
{
"compilerOptions": {
"module": "esnext",
"strict": true,
"outDir": "dist",
"moduleResolution": "node"
},
"files": ["good.ts", "bad.ts"]
}