diff --git a/.eslintignore b/.eslintignore index f4c17fcc0f25e..112136a23142f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -12,3 +12,4 @@ lib/ utils/doclint/generate_types/test/test.ts vendor/ web-test-runner.config.mjs +test-ts-types/ diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8121a54d05760..cb916f6ab8207 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -45,6 +45,7 @@ jobs: npm run lint npm run generate-docs npm run ensure-correct-devtools-protocol-revision + npm run test-types-file - name: Run unit tests env: diff --git a/.github/workflows/publish-on-tag.yml b/.github/workflows/publish-on-tag.yml index b16c1be3fb57b..dc2140ab2aff4 100644 --- a/.github/workflows/publish-on-tag.yml +++ b/.github/workflows/publish-on-tag.yml @@ -3,7 +3,7 @@ name: publish-on-tag on: push: tags: - - '*' + - '*' jobs: publish: diff --git a/.gitignore b/.gitignore index f37bd118bfcd6..f0dc23c33077a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /node_modules/ +test-ts-types/**/node_modules +test-ts-types/**/dist/ /test/output-chromium /test/output-firefox /test/test-user-data-dir* @@ -18,3 +20,4 @@ test/coverage.json temp/ puppeteer-core-*.tgz new-docs/ +puppeteer-*.tgz diff --git a/package.json b/package.json index ee41af3939ffc..c8ec001dd5c80 100644 --- a/package.json +++ b/package.json @@ -33,9 +33,10 @@ "tsc-esm": "tsc -b src/tsconfig.esm.json", "apply-next-version": "node utils/apply_next_version.js", "test-install": "scripts/test-install.sh", - "generate-d-ts": "npm run tsc && api-extractor run --local --verbose && ts-node -s scripts/add-default-export-to-types.ts", + "generate-d-ts": "api-extractor run --local --verbose", "generate-docs": "npm run generate-d-ts && api-documenter markdown -i temp -o new-docs", "ensure-correct-devtools-protocol-revision": "ts-node -s scripts/ensure-correct-devtools-protocol-package", + "test-types-file": "ts-node -s scripts/test-ts-definition-files.ts", "release": "node utils/remove_version_suffix.js && standard-version --commit-all" }, "files": [ diff --git a/scripts/add-default-export-to-types.ts b/scripts/add-default-export-to-types.ts deleted file mode 100644 index 13dc57832a2df..0000000000000 --- a/scripts/add-default-export-to-types.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2021 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import fs from 'fs'; -import path from 'path'; -import packageJson from '../package.json'; - -const typingsLocation = path.resolve(process.cwd(), packageJson.types); - -const fileContents = fs.readFileSync(typingsLocation, { encoding: 'utf-8' }); - -// Default to exposing the Node package as this is the majority of our use case. -// May need reworking in the future when we ship an officially supported browser -// bundle also. -const defaultExportCode = `declare const puppeteer: PuppeteerNode; -export = puppeteer;`; - -const newFileContents = fileContents + `\n${defaultExportCode}`; - -fs.writeFileSync(typingsLocation, newFileContents); diff --git a/scripts/test-ts-definition-files.ts b/scripts/test-ts-definition-files.ts new file mode 100644 index 0000000000000..d9f15133a681e --- /dev/null +++ b/scripts/test-ts-definition-files.ts @@ -0,0 +1,187 @@ +import { spawnSync } from 'child_process'; +import { version } from '../package.json'; +import path from 'path'; +const PROJECT_FOLDERS_ROOT = 'test-ts-types'; +const EXPECTED_ERRORS = new Map([ + [ + '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.', + ], + ], + [ + '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 | null' is not assignable to type 'ElementHandle'", + ], + ], + [ + '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 | null' is not assignable to type 'ElementHandle'", + ], + ], + [ + '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 | null' is not assignable to type 'ElementHandle'", + ], + ], + [ + '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 | null' is not assignable to type 'ElementHandle'", + ], + ], +]); +const PROJECT_FOLDERS = [...EXPECTED_ERRORS.keys()]; + +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); + } + + return `puppeteer-${version}.tgz`; +} + +const tar = packPuppeteer(); +const tarPath = path.join(process.cwd(), tar); + +function compileAndCatchErrors(projectLocation) { + 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('===> Installing Puppeteer from tar file'); + const { status, stderr, stdout } = spawnSync( + 'npm', + ['install', '--no-package-lock', tarLocation], + { + env: { + PUPPETEER_SKIP_DOWNLOAD: '1', + }, + cwd: projectLocation, + encoding: 'utf-8', + } + ); + + if (status > 0) { + 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) => 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) => line.includes('bad.ts') || line.includes('bad.js') + ); + const expectedErrorsThatHaveOccurred = new Set(); + 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); +}); diff --git a/src/api-docs-entry.ts b/src/api-docs-entry.ts index d033a3ed7c36a..63d87aff081dc 100644 --- a/src/api-docs-entry.ts +++ b/src/api-docs-entry.ts @@ -14,6 +14,16 @@ * limitations under the License. */ +import { LaunchOptions, ChromeArgOptions } from './node/LaunchOptions.js'; +import { BrowserOptions } from './common/BrowserConnector.js'; +import { Product } from './common/Product.js'; +import { Browser } from './common/Browser.js'; +import { ConnectOptions } from './common/Puppeteer.js'; +import { DevicesMap } from './common/DeviceDescriptors.js'; +import { PuppeteerErrors } from './common/Errors.js'; +import { PredefinedNetworkConditions } from './common/NetworkConditions.js'; +import { CustomQueryHandler } from './common/QueryHandler.js'; + /* * This file re-exports any APIs that we want to have documentation generated * for. It is used by API Extractor to determine what parts of the system to @@ -62,4 +72,75 @@ export * from './common/PDFOptions.js'; export * from './common/TimeoutSettings.js'; export * from './common/LifecycleWatcher.js'; export * from './common/QueryHandler.js'; +export * from './common/NetworkConditions.js'; export * from 'devtools-protocol/types/protocol'; + +/* + * We maintain a namespace that emulates the API of the Puppeteer instance you + * get when you `import puppeteer from 'puppeteer'. + * + * We do this as a namespace because export = PuppeteerDefault where + * PuppeteerDefault is a namespace seems to make sure that the types work in + * both ESM and CJS contexts. + * + * This namespace must be kept in sync with the public API offered by the + * PuppeteerNode class. + */ + +/** + * @public + * {@inheritDoc PuppeteerNode.launch} + */ +export declare function launch( + options?: LaunchOptions & + ChromeArgOptions & + BrowserOptions & { + product?: Product; + extraPrefsFirefox?: Record; + } +): Promise; + +/** + * @public + * {@inheritDoc PuppeteerNode.connect} + */ +export declare function connect(options: ConnectOptions): Promise; + +/** + * @public + * {@inheritDoc Puppeteer.devices} + */ +export let devices: DevicesMap; +/** + * @public + */ +export let errors: PuppeteerErrors; +/** + * @public + */ +export let networkConditions: PredefinedNetworkConditions; + +/** + * @public + * {@inheritDoc Puppeteer.registerCustomQueryHandler} + */ +export declare function registerCustomQueryHandler( + name: string, + queryHandler: CustomQueryHandler +): void; + +/** + * @public + * {@inheritDoc Puppeteer.unregisterCustomQueryHandler} + */ +export declare function unregisterCustomQueryHandler(name: string): void; +/** + * @public + * {@inheritDoc Puppeteer.customQueryHandlerNames} + */ +export declare function customQueryHandlerNames(): string[]; +/** + * @public + * {@inheritDoc Puppeteer.clearCustomQueryHandlers} + */ +export declare function clearCustomQueryHandlers(): void; diff --git a/src/common/NetworkConditions.ts b/src/common/NetworkConditions.ts index c1a89f280bd01..9d03673c25ac4 100644 --- a/src/common/NetworkConditions.ts +++ b/src/common/NetworkConditions.ts @@ -16,8 +16,14 @@ import { NetworkConditions } from './NetworkManager.js'; +/** + * @public + */ export type PredefinedNetworkConditions = { [name: string]: NetworkConditions }; +/** + * @public + */ export const networkConditions: PredefinedNetworkConditions = { 'Slow 3G': { download: ((500 * 1000) / 8) * 0.8, diff --git a/test-ts-types/js-cjs-import-cjs-output/bad.js b/test-ts-types/js-cjs-import-cjs-output/bad.js new file mode 100644 index 0000000000000..be5127947cdb2 --- /dev/null +++ b/test-ts-types/js-cjs-import-cjs-output/bad.js @@ -0,0 +1,18 @@ +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} + */ + const div = await page.$('div'); + console.log('got a div!', div); +} +run(); diff --git a/test-ts-types/js-cjs-import-cjs-output/good.js b/test-ts-types/js-cjs-import-cjs-output/good.js new file mode 100644 index 0000000000000..f4663006078c8 --- /dev/null +++ b/test-ts-types/js-cjs-import-cjs-output/good.js @@ -0,0 +1,17 @@ +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} + */ + const newDiv = div; + console.log('got a div!', newDiv); + } +} +run(); diff --git a/test-ts-types/js-cjs-import-cjs-output/package.json b/test-ts-types/js-cjs-import-cjs-output/package.json new file mode 100644 index 0000000000000..3c0d055e27700 --- /dev/null +++ b/test-ts-types/js-cjs-import-cjs-output/package.json @@ -0,0 +1,12 @@ +{ + "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-7.0.4-post.tgz" + } +} diff --git a/test-ts-types/js-cjs-import-cjs-output/tsconfig.json b/test-ts-types/js-cjs-import-cjs-output/tsconfig.json new file mode 100644 index 0000000000000..2889972c4b81b --- /dev/null +++ b/test-ts-types/js-cjs-import-cjs-output/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "commonjs", + "checkJs": true, + "allowJs": true, + "strict": true, + "outDir": "dist", + "moduleResolution": "node" + }, + "files": ["good.js", "bad.js"] +} diff --git a/test-ts-types/js-cjs-import-esm-output/bad.js b/test-ts-types/js-cjs-import-esm-output/bad.js new file mode 100644 index 0000000000000..be5127947cdb2 --- /dev/null +++ b/test-ts-types/js-cjs-import-esm-output/bad.js @@ -0,0 +1,18 @@ +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} + */ + const div = await page.$('div'); + console.log('got a div!', div); +} +run(); diff --git a/test-ts-types/js-cjs-import-esm-output/good.js b/test-ts-types/js-cjs-import-esm-output/good.js new file mode 100644 index 0000000000000..f4663006078c8 --- /dev/null +++ b/test-ts-types/js-cjs-import-esm-output/good.js @@ -0,0 +1,17 @@ +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} + */ + const newDiv = div; + console.log('got a div!', newDiv); + } +} +run(); diff --git a/test-ts-types/js-cjs-import-esm-output/package.json b/test-ts-types/js-cjs-import-esm-output/package.json new file mode 100644 index 0000000000000..27d6b18b8a420 --- /dev/null +++ b/test-ts-types/js-cjs-import-esm-output/package.json @@ -0,0 +1,15 @@ +{ + "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" + }, + "devDependencies": { + "typescript": "^4.1.3" + }, + "dependencies": { + "puppeteer": "file:../../puppeteer-7.0.4-post.tgz" + } +} diff --git a/test-ts-types/js-cjs-import-esm-output/tsconfig.json b/test-ts-types/js-cjs-import-esm-output/tsconfig.json new file mode 100644 index 0000000000000..e2ce292bf3e0c --- /dev/null +++ b/test-ts-types/js-cjs-import-esm-output/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "esnext", + "checkJs": true, + "allowJs": true, + "strict": true, + "outDir": "dist", + "moduleResolution": "node" + }, + "files": ["good.js", "bad.js"] +} diff --git a/test-ts-types/js-esm-import-cjs-output/bad.js b/test-ts-types/js-esm-import-cjs-output/bad.js new file mode 100644 index 0000000000000..ba7b56133d4fe --- /dev/null +++ b/test-ts-types/js-esm-import-cjs-output/bad.js @@ -0,0 +1,18 @@ +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} + */ + const div = await page.$('div'); + console.log('got a div!', div); +} +run(); diff --git a/test-ts-types/js-esm-import-cjs-output/good.js b/test-ts-types/js-esm-import-cjs-output/good.js new file mode 100644 index 0000000000000..544c43cf8bafb --- /dev/null +++ b/test-ts-types/js-esm-import-cjs-output/good.js @@ -0,0 +1,17 @@ +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} + */ + const newDiv = div; + console.log('got a div!', newDiv); + } +} +run(); diff --git a/test-ts-types/js-esm-import-cjs-output/package.json b/test-ts-types/js-esm-import-cjs-output/package.json new file mode 100644 index 0000000000000..27d6b18b8a420 --- /dev/null +++ b/test-ts-types/js-esm-import-cjs-output/package.json @@ -0,0 +1,15 @@ +{ + "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" + }, + "devDependencies": { + "typescript": "^4.1.3" + }, + "dependencies": { + "puppeteer": "file:../../puppeteer-7.0.4-post.tgz" + } +} diff --git a/test-ts-types/js-esm-import-cjs-output/tsconfig.json b/test-ts-types/js-esm-import-cjs-output/tsconfig.json new file mode 100644 index 0000000000000..2889972c4b81b --- /dev/null +++ b/test-ts-types/js-esm-import-cjs-output/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "commonjs", + "checkJs": true, + "allowJs": true, + "strict": true, + "outDir": "dist", + "moduleResolution": "node" + }, + "files": ["good.js", "bad.js"] +} diff --git a/test-ts-types/js-esm-import-esm-output/bad.js b/test-ts-types/js-esm-import-esm-output/bad.js new file mode 100644 index 0000000000000..ba7b56133d4fe --- /dev/null +++ b/test-ts-types/js-esm-import-esm-output/bad.js @@ -0,0 +1,18 @@ +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} + */ + const div = await page.$('div'); + console.log('got a div!', div); +} +run(); diff --git a/test-ts-types/js-esm-import-esm-output/good.js b/test-ts-types/js-esm-import-esm-output/good.js new file mode 100644 index 0000000000000..544c43cf8bafb --- /dev/null +++ b/test-ts-types/js-esm-import-esm-output/good.js @@ -0,0 +1,17 @@ +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} + */ + const newDiv = div; + console.log('got a div!', newDiv); + } +} +run(); diff --git a/test-ts-types/js-esm-import-esm-output/package.json b/test-ts-types/js-esm-import-esm-output/package.json new file mode 100644 index 0000000000000..27d6b18b8a420 --- /dev/null +++ b/test-ts-types/js-esm-import-esm-output/package.json @@ -0,0 +1,15 @@ +{ + "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" + }, + "devDependencies": { + "typescript": "^4.1.3" + }, + "dependencies": { + "puppeteer": "file:../../puppeteer-7.0.4-post.tgz" + } +} diff --git a/test-ts-types/js-esm-import-esm-output/tsconfig.json b/test-ts-types/js-esm-import-esm-output/tsconfig.json new file mode 100644 index 0000000000000..e2ce292bf3e0c --- /dev/null +++ b/test-ts-types/js-esm-import-esm-output/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "esnext", + "checkJs": true, + "allowJs": true, + "strict": true, + "outDir": "dist", + "moduleResolution": "node" + }, + "files": ["good.js", "bad.js"] +} diff --git a/test-ts-types/ts-cjs-import-cjs-output/bad.ts b/test-ts-types/ts-cjs-import-cjs-output/bad.ts new file mode 100644 index 0000000000000..9199f8aeea9d2 --- /dev/null +++ b/test-ts-types/ts-cjs-import-cjs-output/bad.ts @@ -0,0 +1,17 @@ +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(); diff --git a/test-ts-types/ts-cjs-import-cjs-output/good.ts b/test-ts-types/ts-cjs-import-cjs-output/good.ts new file mode 100644 index 0000000000000..d055bf6f6a531 --- /dev/null +++ b/test-ts-types/ts-cjs-import-cjs-output/good.ts @@ -0,0 +1,13 @@ +import 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')) as puppeteer.ElementHandle< + HTMLAnchorElement + >; + console.log('got a div!', div); +} +run(); diff --git a/test-ts-types/ts-cjs-import-cjs-output/package.json b/test-ts-types/ts-cjs-import-cjs-output/package.json new file mode 100644 index 0000000000000..27d6b18b8a420 --- /dev/null +++ b/test-ts-types/ts-cjs-import-cjs-output/package.json @@ -0,0 +1,15 @@ +{ + "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" + }, + "devDependencies": { + "typescript": "^4.1.3" + }, + "dependencies": { + "puppeteer": "file:../../puppeteer-7.0.4-post.tgz" + } +} diff --git a/test-ts-types/ts-cjs-import-cjs-output/tsconfig.json b/test-ts-types/ts-cjs-import-cjs-output/tsconfig.json new file mode 100644 index 0000000000000..a417e47c143ed --- /dev/null +++ b/test-ts-types/ts-cjs-import-cjs-output/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "module": "commonjs", + "strict": true, + "outDir": "dist", + "moduleResolution": "node" + }, + "files": ["good.ts", "bad.ts"] +} diff --git a/test-ts-types/ts-esm-import-cjs-output/bad.ts b/test-ts-types/ts-esm-import-cjs-output/bad.ts new file mode 100644 index 0000000000000..4aeb970709652 --- /dev/null +++ b/test-ts-types/ts-esm-import-cjs-output/bad.ts @@ -0,0 +1,18 @@ +// 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(); diff --git a/test-ts-types/ts-esm-import-cjs-output/good.ts b/test-ts-types/ts-esm-import-cjs-output/good.ts new file mode 100644 index 0000000000000..ed7764140d8b6 --- /dev/null +++ b/test-ts-types/ts-esm-import-cjs-output/good.ts @@ -0,0 +1,13 @@ +// 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; + console.log('got a div!', div); +} +run(); diff --git a/test-ts-types/ts-esm-import-cjs-output/package.json b/test-ts-types/ts-esm-import-cjs-output/package.json new file mode 100644 index 0000000000000..27d6b18b8a420 --- /dev/null +++ b/test-ts-types/ts-esm-import-cjs-output/package.json @@ -0,0 +1,15 @@ +{ + "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" + }, + "devDependencies": { + "typescript": "^4.1.3" + }, + "dependencies": { + "puppeteer": "file:../../puppeteer-7.0.4-post.tgz" + } +} diff --git a/test-ts-types/ts-esm-import-cjs-output/tsconfig.json b/test-ts-types/ts-esm-import-cjs-output/tsconfig.json new file mode 100644 index 0000000000000..a417e47c143ed --- /dev/null +++ b/test-ts-types/ts-esm-import-cjs-output/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "module": "commonjs", + "strict": true, + "outDir": "dist", + "moduleResolution": "node" + }, + "files": ["good.ts", "bad.ts"] +} diff --git a/test-ts-types/ts-esm-import-esm-output/bad.ts b/test-ts-types/ts-esm-import-esm-output/bad.ts new file mode 100644 index 0000000000000..4aeb970709652 --- /dev/null +++ b/test-ts-types/ts-esm-import-esm-output/bad.ts @@ -0,0 +1,18 @@ +// 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(); diff --git a/test-ts-types/ts-esm-import-esm-output/good.ts b/test-ts-types/ts-esm-import-esm-output/good.ts new file mode 100644 index 0000000000000..ed7764140d8b6 --- /dev/null +++ b/test-ts-types/ts-esm-import-esm-output/good.ts @@ -0,0 +1,13 @@ +// 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; + console.log('got a div!', div); +} +run(); diff --git a/test-ts-types/ts-esm-import-esm-output/package.json b/test-ts-types/ts-esm-import-esm-output/package.json new file mode 100644 index 0000000000000..27d6b18b8a420 --- /dev/null +++ b/test-ts-types/ts-esm-import-esm-output/package.json @@ -0,0 +1,15 @@ +{ + "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" + }, + "devDependencies": { + "typescript": "^4.1.3" + }, + "dependencies": { + "puppeteer": "file:../../puppeteer-7.0.4-post.tgz" + } +} diff --git a/test-ts-types/ts-esm-import-esm-output/tsconfig.json b/test-ts-types/ts-esm-import-esm-output/tsconfig.json new file mode 100644 index 0000000000000..f9e9bb5f878b0 --- /dev/null +++ b/test-ts-types/ts-esm-import-esm-output/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "module": "esnext", + "strict": true, + "outDir": "dist", + "moduleResolution": "node" + }, + "files": ["good.ts", "bad.ts"] +}