From 80373f7a12d7e35806177260a0c48d2b9d16e486 Mon Sep 17 00:00:00 2001 From: jrandolf <101637635+jrandolf@users.noreply.github.com> Date: Wed, 15 Jun 2022 12:05:25 +0200 Subject: [PATCH] chore: use `composite` builds for tests (#8522) --- .eslintignore | 20 +- .gitignore | 38 +-- .../puppeteer-unit-tests.js => .mocharc.cjs | 15 +- .prettierignore | 30 +- compat/cjs/tsconfig.json | 7 +- compat/esm/tsconfig.json | 7 +- mocha-config/base.js | 6 - mocha-config/doclint-tests.js | 6 - package.json | 15 +- src/{compat.ts => compat.d.ts} | 0 src/tsconfig.cjs.json | 5 +- src/tsconfig.esm.json | 5 +- test/coverage-utils.js | 167 ---------- test/mocha-ts-require.js | 11 - test/run_static_server.js | 33 -- test/{ => src}/CDPSession.spec.ts | 0 test/{ => src}/EventEmitter.spec.ts | 2 +- test/{ => src}/NetworkManager.spec.ts | 8 +- test/{ => src}/accessibility.spec.ts | 0 test/{ => src}/ariaqueryhandler.spec.ts | 2 +- test/{ => src}/browser.spec.ts | 0 test/{ => src}/browsercontext.spec.ts | 0 test/{ => src}/chromiumonly.spec.ts | 0 test/{ => src}/click.spec.ts | 0 test/{ => src}/cookies.spec.ts | 0 test/{ => src}/coverage.spec.ts | 0 test/{ => src}/defaultbrowsercontext.spec.ts | 0 test/{ => src}/dialog.spec.ts | 0 test/{ => src}/diffstyle.css | 0 test/{ => src}/drag-and-drop.spec.ts | 0 test/{ => src}/elementhandle.spec.ts | 2 +- test/{ => src}/emulation.spec.ts | 0 test/{ => src}/evaluation.spec.ts | 0 test/{ => src}/fixtures.spec.ts | 6 +- test/{ => src}/frame.spec.ts | 2 +- test/{ => src}/golden-utils.js | 0 test/{ => src}/headful.spec.ts | 2 +- test/{ => src}/idle_override.spec.ts | 0 test/{ => src}/ignorehttpserrors.spec.ts | 9 +- test/{ => src}/input.spec.ts | 6 +- test/{ => src}/jshandle.spec.ts | 2 +- test/{ => src}/keyboard.spec.ts | 2 +- test/{ => src}/launcher.spec.ts | 7 +- test/{ => src}/mocha-utils.ts | 26 +- test/{ => src}/mouse.spec.ts | 2 +- test/{ => src}/navigation.spec.ts | 0 test/{ => src}/network.spec.ts | 6 +- test/{ => src}/oopif.spec.ts | 2 +- test/{ => src}/page.spec.ts | 22 +- test/{ => src}/proxy.spec.ts | 5 +- test/{ => src}/queryselector.spec.ts | 2 +- .../requestinterception-experimental.spec.ts | 8 +- test/{ => src}/requestinterception.spec.ts | 4 +- test/{ => src}/screenshot.spec.ts | 0 test/{ => src}/target.spec.ts | 2 +- test/{ => src}/touchscreen.spec.ts | 0 test/{ => src}/tracing.spec.ts | 2 +- test/{ => src}/utils.js | 5 +- test/{ => src}/waittask.spec.ts | 0 test/{ => src}/worker.spec.ts | 4 +- test/tsconfig.json | 21 +- test/tsconfig.test.json | 14 - utils/doclint/check_public_api/index.js | 33 +- utils/testserver/index.js | 303 ------------------ utils/testserver/package.json | 2 +- utils/testserver/src/index.ts | 278 ++++++++++++++++ utils/testserver/tsconfig.json | 11 + 67 files changed, 480 insertions(+), 687 deletions(-) rename mocha-config/puppeteer-unit-tests.js => .mocharc.cjs (78%) delete mode 100644 mocha-config/base.js delete mode 100644 mocha-config/doclint-tests.js rename src/{compat.ts => compat.d.ts} (100%) delete mode 100644 test/coverage-utils.js delete mode 100644 test/mocha-ts-require.js delete mode 100755 test/run_static_server.js rename test/{ => src}/CDPSession.spec.ts (100%) rename test/{ => src}/EventEmitter.spec.ts (98%) rename test/{ => src}/NetworkManager.spec.ts (98%) rename test/{ => src}/accessibility.spec.ts (100%) rename test/{ => src}/ariaqueryhandler.spec.ts (99%) rename test/{ => src}/browser.spec.ts (100%) rename test/{ => src}/browsercontext.spec.ts (100%) rename test/{ => src}/chromiumonly.spec.ts (100%) rename test/{ => src}/click.spec.ts (100%) rename test/{ => src}/cookies.spec.ts (100%) rename test/{ => src}/coverage.spec.ts (100%) rename test/{ => src}/defaultbrowsercontext.spec.ts (100%) rename test/{ => src}/dialog.spec.ts (100%) rename test/{ => src}/diffstyle.css (100%) rename test/{ => src}/drag-and-drop.spec.ts (100%) rename test/{ => src}/elementhandle.spec.ts (99%) rename test/{ => src}/emulation.spec.ts (100%) rename test/{ => src}/evaluation.spec.ts (100%) rename test/{ => src}/fixtures.spec.ts (95%) rename test/{ => src}/frame.spec.ts (99%) rename test/{ => src}/golden-utils.js (100%) rename test/{ => src}/headful.spec.ts (99%) rename test/{ => src}/idle_override.spec.ts (100%) rename test/{ => src}/ignorehttpserrors.spec.ts (94%) rename test/{ => src}/input.spec.ts (98%) rename test/{ => src}/jshandle.spec.ts (99%) rename test/{ => src}/keyboard.spec.ts (99%) rename test/{ => src}/launcher.spec.ts (99%) rename test/{ => src}/mocha-utils.ts (92%) rename test/{ => src}/mouse.spec.ts (99%) rename test/{ => src}/navigation.spec.ts (100%) rename test/{ => src}/network.spec.ts (99%) rename test/{ => src}/oopif.spec.ts (99%) rename test/{ => src}/page.spec.ts (98%) rename test/{ => src}/proxy.spec.ts (97%) rename test/{ => src}/queryselector.spec.ts (99%) rename test/{ => src}/requestinterception-experimental.spec.ts (99%) rename test/{ => src}/requestinterception.spec.ts (99%) rename test/{ => src}/screenshot.spec.ts (100%) rename test/{ => src}/target.spec.ts (99%) rename test/{ => src}/touchscreen.spec.ts (100%) rename test/{ => src}/tracing.spec.ts (98%) rename test/{ => src}/utils.js (95%) rename test/{ => src}/waittask.spec.ts (100%) rename test/{ => src}/worker.spec.ts (96%) delete mode 100644 test/tsconfig.test.json delete mode 100644 utils/testserver/index.js create mode 100644 utils/testserver/src/index.ts create mode 100644 utils/testserver/tsconfig.json diff --git a/.eslintignore b/.eslintignore index da45113a..b52c3378 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,16 +1,8 @@ -test/assets/modernizr.js -third_party/* -utils/doclint/check_public_api/test/ -node6/* -node6-test/* -experimental/ +assets/ +build/ +coverage/ +doclint/ lib/ -/index.d.ts -# We ignore this file because it uses ES imports which we don't yet use -# in the Puppeteer src, so it trips up the ESLint-TypeScript parser. -utils/doclint/generate_types/test/test.ts -vendor/ -web-test-runner.config.mjs test-ts-types/ -website/ -docs-dist/ +tsconfig.tsbuildinfo +vendor/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 391fe991..3b1cc7d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,20 @@ -/node_modules/ -test-ts-types/**/node_modules -test-ts-types/**/dist/ -/test/output-chromium -/test/output-firefox -/test/test-user-data-dir* +.DS_Store +.vscode +/.dev_profile* /.local-chromium/ /.local-firefox/ -/.dev_profile* -.DS_Store -*.swp -*.pyc -.vscode -package-lock.json -yarn.lock -/node6 -lib -test/coverage.json -temp/ -new-docs/ -puppeteer*.tgz -docs-api-json/ -docs-dist/ +/test/test-user-data-dir* +build/ coverage -website/docs +coverage/ +doclint/ +docs-api-json/ docs/api.html +lib/ +node_modules/ +package-lock.json +puppeteer*.tgz +test-ts-types/**/dist/ +test-ts-types/**/node_modules +tsconfig.tsbuildinfo +yarn.lock \ No newline at end of file diff --git a/mocha-config/puppeteer-unit-tests.js b/.mocharc.cjs similarity index 78% rename from mocha-config/puppeteer-unit-tests.js rename to .mocharc.cjs index 2f037051..e7168715 100644 --- a/mocha-config/puppeteer-unit-tests.js +++ b/.mocharc.cjs @@ -14,17 +14,12 @@ * limitations under the License. */ -const base = require('./base.js'); - module.exports = { - ...base, - require: [ - './test/mocha-ts-require', - './test/mocha-utils.ts', - 'source-map-support/register', - ], - spec: 'test/*.spec.ts', - extension: ['js', 'ts'], + reporter: 'dot', + logLevel: 'debug', + require: ['./test/build/mocha-utils.js', 'source-map-support/register'], + spec: 'test/build/*.spec.js', + exit: !!process.env.CI, retries: process.env.CI ? 2 : 0, parallel: !!process.env.PARALLEL, timeout: 25 * 1000, diff --git a/.prettierignore b/.prettierignore index 91dde135..94574cbf 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,17 +1,17 @@ -node_modules/ -lib/ -third_party/ -vendor/ - -package-lock.json -yarn.lock -package.json -docs-api-json/ -docs-dist/ -website/ -experimental/ +.local-chromium/ +.local-firefox/ +assets/ +build/ CHANGELOG.md +coverage/ +doclint/ +docs-api-json/ +lib/ +node_modules/ +package-lock.json +package.json +test-ts-types/ test/assets/ -/.local-chromium/ -/.local-firefox/ -test-ts-types +tsconfig.tsbuildinfo +vendor/ +yarn.lock \ No newline at end of file diff --git a/compat/cjs/tsconfig.json b/compat/cjs/tsconfig.json index b9ad322f..54292688 100644 --- a/compat/cjs/tsconfig.json +++ b/compat/cjs/tsconfig.json @@ -1,3 +1,8 @@ { - "extends": "../../src/tsconfig.cjs.json" + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "../../lib/cjs/puppeteer", + "module": "CommonJS" + } } diff --git a/compat/esm/tsconfig.json b/compat/esm/tsconfig.json index 94d6b560..5afe459a 100644 --- a/compat/esm/tsconfig.json +++ b/compat/esm/tsconfig.json @@ -1,3 +1,8 @@ { - "extends": "../../src/tsconfig.esm.json" + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "../../lib/esm/puppeteer", + "module": "esnext" + } } diff --git a/mocha-config/base.js b/mocha-config/base.js deleted file mode 100644 index dc0b04d7..00000000 --- a/mocha-config/base.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - reporter: 'dot', - // Allow `console.log`s to show up during test execution - logLevel: 'debug', - exit: !!process.env.CI, -}; diff --git a/mocha-config/doclint-tests.js b/mocha-config/doclint-tests.js deleted file mode 100644 index e6e817a3..00000000 --- a/mocha-config/doclint-tests.js +++ /dev/null @@ -1,6 +0,0 @@ -const base = require('./base.js'); - -module.exports = { - ...base, - spec: 'utils/doclint/**/*.spec.js', -}; diff --git a/package.json b/package.json index f6e5d26f..b677db13 100644 --- a/package.json +++ b/package.json @@ -27,15 +27,15 @@ "node": ">=14.1.0" }, "scripts": { - "test": "npm run build && npm run lint --silent && npm run test:unit:coverage", - "test:unit": "npm run build:tsc:cjs && npm run build:tsc:cjs:compat && mocha --config mocha-config/puppeteer-unit-tests.js", + "test": "npm run lint --silent && npm run test:unit:coverage", + "test:unit": "npm run build:test && mocha", "test:unit:firefox": "cross-env PUPPETEER_PRODUCT=firefox npm run test:unit", "test:unit:coverage": "c8 --check-coverage --lines 94 npm run test:unit", "test:unit:chrome-headless": "cross-env HEADLESS=chrome npm run test:unit", "test:protocol-revision": "ts-node -s scripts/ensure-correct-devtools-protocol-package", "test:pinned-deps": "ts-node -s scripts/ensure-pinned-deps", "test:install": "scripts/test-install.sh", - "test:debug": "npm run build:tsc:cjs && npm run build:tsc:cjs:compat && mocha --inspect-brk --config mocha-config/puppeteer-unit-tests.js", + "test:debug": "npm run build:test && mocha --inspect-brk", "test:types": "ts-node -s scripts/test-ts-definition-files.ts", "prepublishOnly": "npm run build", "prepare": "node typescript-if-required.js && ([[ $HUSKY = 0 ]] || husky install)", @@ -54,11 +54,10 @@ "clean:lib": "rimraf lib", "clean:docs": "rimraf docs-api-json", "build": "npm run build:tsc && npm run generate:types && npm run generate:esm-package-json", - "build:tsc": "npm run clean:lib && tsc --version && (npm run build:tsc:cjs && npm run build:tsc:esm) && (npm run build:tsc:cjs:compat && npm run build:tsc:esm:compat)", + "build:test": "tsc -b test", + "build:tsc": "npm run clean:lib && tsc --version && (npm run build:tsc:cjs && npm run build:tsc:esm)", "build:tsc:esm": "tsc -b src/tsconfig.esm.json", - "build:tsc:esm:compat": "tsc -b compat/esm/tsconfig.json", - "build:tsc:cjs": "tsc -b src/tsconfig.cjs.json", - "build:tsc:cjs:compat": "tsc -b compat/cjs/tsconfig.json" + "build:tsc:cjs": "tsc -b src/tsconfig.cjs.json" }, "files": [ "lib", @@ -104,6 +103,7 @@ "cross-env": "7.0.3", "eslint": "8.16.0", "eslint-config-prettier": "8.5.0", + "eslint-formatter-codeframe": "7.32.1", "eslint-plugin-import": "2.26.0", "eslint-plugin-mocha": "10.0.5", "eslint-plugin-prettier": "4.0.0", @@ -122,7 +122,6 @@ "sinon": "14.0.0", "source-map-support": "0.5.21", "text-diff": "1.0.1", - "ts-node": "10.8.0", "typescript": "4.7.2" } } diff --git a/src/compat.ts b/src/compat.d.ts similarity index 100% rename from src/compat.ts rename to src/compat.d.ts diff --git a/src/tsconfig.cjs.json b/src/tsconfig.cjs.json index 50639760..9fc0e7ee 100644 --- a/src/tsconfig.cjs.json +++ b/src/tsconfig.cjs.json @@ -5,5 +5,8 @@ "outDir": "../lib/cjs/puppeteer", "module": "CommonJS" }, - "references": [{ "path": "../vendor/tsconfig.cjs.json" }] + "references": [ + { "path": "../vendor/tsconfig.cjs.json" }, + { "path": "../compat/cjs/tsconfig.json" } + ] } diff --git a/src/tsconfig.esm.json b/src/tsconfig.esm.json index 29fabd9a..cb4e47eb 100644 --- a/src/tsconfig.esm.json +++ b/src/tsconfig.esm.json @@ -5,5 +5,8 @@ "outDir": "../lib/esm/puppeteer", "module": "esnext" }, - "references": [{ "path": "../vendor/tsconfig.esm.json" }] + "references": [ + { "path": "../vendor/tsconfig.esm.json" }, + { "path": "../compat/esm/tsconfig.json" } + ] } diff --git a/test/coverage-utils.js b/test/coverage-utils.js deleted file mode 100644 index 0f64f709..00000000 --- a/test/coverage-utils.js +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Copyright 2020 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. - */ - -// TODO (@jackfranklin): convert this to TypeScript and enable type-checking -// @ts-nocheck - -/* We want to ensure that all of Puppeteer's public API is tested via our unit - * tests but we can't use a tool like Istanbul because the way it instruments - * code unfortunately breaks in Puppeteer where some of that code is then being - * executed in a browser context. - * - * So instead we maintain this coverage code which does the following: - * * takes every public method that we expect to be tested - * * replaces it with a method that calls the original but also updates a Map of calls - * * in an after() test callback it asserts that every public method was called. - * - * We run this when COVERAGE=1. - */ - -const path = require('path'); -const fs = require('fs'); - -/** - * This object is also used by DocLint to know which classes to check are - * documented. It's a pretty hacky solution but DocLint is going away soon as - * part of the TSDoc migration. - */ -const MODULES_TO_CHECK_FOR_COVERAGE = { - Accessibility: '../lib/cjs/puppeteer/common/Accessibility', - Browser: '../lib/cjs/puppeteer/common/Browser', - BrowserContext: '../lib/cjs/puppeteer/common/Browser', - BrowserFetcher: '../lib/cjs/puppeteer/node/BrowserFetcher', - CDPSession: '../lib/cjs/puppeteer/common/Connection', - ConsoleMessage: '../lib/cjs/puppeteer/common/ConsoleMessage', - Coverage: '../lib/cjs/puppeteer/common/Coverage', - Dialog: '../lib/cjs/puppeteer/common/Dialog', - ElementHandle: '../lib/cjs/puppeteer/common/JSHandle', - ExecutionContext: '../lib/cjs/puppeteer/common/ExecutionContext', - EventEmitter: '../lib/cjs/puppeteer/common/EventEmitter', - FileChooser: '../lib/cjs/puppeteer/common/FileChooser', - Frame: '../lib/cjs/puppeteer/common/FrameManager', - JSHandle: '../lib/cjs/puppeteer/common/JSHandle', - Keyboard: '../lib/cjs/puppeteer/common/Input', - Mouse: '../lib/cjs/puppeteer/common/Input', - Page: '../lib/cjs/puppeteer/common/Page', - Puppeteer: '../lib/cjs/puppeteer/common/Puppeteer', - PuppeteerNode: '../lib/cjs/puppeteer/node/Puppeteer', - HTTPRequest: '../lib/cjs/puppeteer/common/HTTPRequest', - HTTPResponse: '../lib/cjs/puppeteer/common/HTTPResponse', - SecurityDetails: '../lib/cjs/puppeteer/common/SecurityDetails', - Target: '../lib/cjs/puppeteer/common/Target', - TimeoutError: '../lib/cjs/puppeteer/common/Errors', - Touchscreen: '../lib/cjs/puppeteer/common/Input', - Tracing: '../lib/cjs/puppeteer/common/Tracing', - WebWorker: '../lib/cjs/puppeteer/common/WebWorker', -}; - -function traceAPICoverage(apiCoverage, className, modulePath) { - const loadedModule = require(modulePath); - const classType = loadedModule[className]; - - if (!classType || !classType.prototype) { - console.error( - `Coverage error: could not find class for ${className}. Is src/api.ts up to date?` - ); - process.exit(1); - } - for (const methodName of Reflect.ownKeys(classType.prototype)) { - const method = Reflect.get(classType.prototype, methodName); - if ( - methodName === 'constructor' || - typeof methodName !== 'string' || - methodName.startsWith('_') || - typeof method !== 'function' - ) { - continue; - } - apiCoverage.set(`${className}.${methodName}`, false); - Reflect.set(classType.prototype, methodName, function (...args) { - apiCoverage.set(`${className}.${methodName}`, true); - return method.call(this, ...args); - }); - } - - /** - * If classes emit events, those events are exposed via an object in the same - * module named XEmittedEvents, where X is the name of the class. For example, - * the Page module exposes PageEmittedEvents. - */ - const eventsName = `${className}EmittedEvents`; - if (loadedModule[eventsName]) { - for (const event of Object.values(loadedModule[eventsName])) { - if (typeof event !== 'symbol') { - apiCoverage.set(`${className}.emit(${JSON.stringify(event)})`, false); - } - } - const method = Reflect.get(classType.prototype, 'emit'); - Reflect.set(classType.prototype, 'emit', function (event, ...args) { - if (typeof event !== 'symbol' && this.listenerCount(event)) { - apiCoverage.set(`${className}.emit(${JSON.stringify(event)})`, true); - } - return method.call(this, event, ...args); - }); - } -} - -const coverageLocation = path.join(__dirname, 'coverage.json'); - -const clearOldCoverage = () => { - try { - fs.unlinkSync(coverageLocation); - } catch (error) { - // do nothing, the file didn't exist - } -}; -const writeCoverage = (coverage) => { - fs.writeFileSync(coverageLocation, JSON.stringify([...coverage.entries()])); -}; - -const getCoverageResults = () => { - let contents; - try { - contents = fs.readFileSync(coverageLocation, { encoding: 'utf8' }); - } catch (error) { - console.error('Warning: coverage file does not exist or is not readable.'); - } - - const coverageMap = new Map(JSON.parse(contents)); - return coverageMap; -}; - -const trackCoverage = () => { - clearOldCoverage(); - const coverageMap = new Map(); - - return { - beforeAll: () => { - for (const [className, moduleFilePath] of Object.entries( - MODULES_TO_CHECK_FOR_COVERAGE - )) { - traceAPICoverage(coverageMap, className, moduleFilePath); - } - }, - afterAll: () => { - writeCoverage(coverageMap); - }, - }; -}; - -module.exports = { - trackCoverage, - getCoverageResults, - MODULES_TO_CHECK_FOR_COVERAGE, -}; diff --git a/test/mocha-ts-require.js b/test/mocha-ts-require.js deleted file mode 100644 index a0ac64fa..00000000 --- a/test/mocha-ts-require.js +++ /dev/null @@ -1,11 +0,0 @@ -const path = require('path'); - -require('ts-node').register({ - /** - * We ignore the lib/ directory because that's already been TypeScript - * compiled and checked. So we don't want to check it again as part of running - * the unit tests. - */ - ignore: ['lib/*', 'node_modules'], - project: path.join(__dirname, 'tsconfig.test.json'), -}); diff --git a/test/run_static_server.js b/test/run_static_server.js deleted file mode 100755 index 0cd10f26..00000000 --- a/test/run_static_server.js +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env node -/** - * Copyright 2017 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. - */ -const path = require('path'); -const { TestServer } = require('../utils/testserver/index.js'); - -const port = 8907; -const httpsPort = 8908; -const assetsPath = path.join(__dirname, 'assets'); -const cachedPath = path.join(__dirname, 'assets', 'cached'); - -Promise.all([ - TestServer.create(assetsPath, port), - TestServer.createHTTPS(assetsPath, httpsPort), -]).then(([server, httpsServer]) => { - server.enableHTTPCache(cachedPath); - httpsServer.enableHTTPCache(cachedPath); - console.log(`HTTP: server is running on http://localhost:${port}`); - console.log(`HTTPS: server is running on https://localhost:${httpsPort}`); -}); diff --git a/test/CDPSession.spec.ts b/test/src/CDPSession.spec.ts similarity index 100% rename from test/CDPSession.spec.ts rename to test/src/CDPSession.spec.ts diff --git a/test/EventEmitter.spec.ts b/test/src/EventEmitter.spec.ts similarity index 98% rename from test/EventEmitter.spec.ts rename to test/src/EventEmitter.spec.ts index bf20e7fe..f15a7952 100644 --- a/test/EventEmitter.spec.ts +++ b/test/src/EventEmitter.spec.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { EventEmitter } from '../lib/cjs/puppeteer/common/EventEmitter.js'; +import { EventEmitter } from '../../lib/cjs/puppeteer/common/EventEmitter.js'; import sinon from 'sinon'; import expect from 'expect'; diff --git a/test/NetworkManager.spec.ts b/test/src/NetworkManager.spec.ts similarity index 98% rename from test/NetworkManager.spec.ts rename to test/src/NetworkManager.spec.ts index c48e945d..b78aa8c3 100644 --- a/test/NetworkManager.spec.ts +++ b/test/src/NetworkManager.spec.ts @@ -20,10 +20,10 @@ import expect from 'expect'; import { NetworkManager, NetworkManagerEmittedEvents, -} from '../lib/cjs/puppeteer/common/NetworkManager.js'; -import { HTTPRequest } from '../lib/cjs/puppeteer/common/HTTPRequest.js'; -import { EventEmitter } from '../lib/cjs/puppeteer/common/EventEmitter.js'; -import { Frame } from '../lib/cjs/puppeteer/common/FrameManager.js'; +} from '../../lib/cjs/puppeteer/common/NetworkManager.js'; +import { HTTPRequest } from '../../lib/cjs/puppeteer/common/HTTPRequest.js'; +import { EventEmitter } from '../../lib/cjs/puppeteer/common/EventEmitter.js'; +import { Frame } from '../../lib/cjs/puppeteer/common/FrameManager.js'; class MockCDPSession extends EventEmitter { async send(): Promise {} diff --git a/test/accessibility.spec.ts b/test/src/accessibility.spec.ts similarity index 100% rename from test/accessibility.spec.ts rename to test/src/accessibility.spec.ts diff --git a/test/ariaqueryhandler.spec.ts b/test/src/ariaqueryhandler.spec.ts similarity index 99% rename from test/ariaqueryhandler.spec.ts rename to test/src/ariaqueryhandler.spec.ts index 061f5b6b..45d5bfc6 100644 --- a/test/ariaqueryhandler.spec.ts +++ b/test/src/ariaqueryhandler.spec.ts @@ -22,7 +22,7 @@ import { describeChromeOnly, } from './mocha-utils'; // eslint-disable-line import/extensions -import { ElementHandle } from '../lib/cjs/puppeteer/common/JSHandle.js'; +import { ElementHandle } from '../../lib/cjs/puppeteer/common/JSHandle.js'; import utils from './utils.js'; describeChromeOnly('AriaQueryHandler', () => { diff --git a/test/browser.spec.ts b/test/src/browser.spec.ts similarity index 100% rename from test/browser.spec.ts rename to test/src/browser.spec.ts diff --git a/test/browsercontext.spec.ts b/test/src/browsercontext.spec.ts similarity index 100% rename from test/browsercontext.spec.ts rename to test/src/browsercontext.spec.ts diff --git a/test/chromiumonly.spec.ts b/test/src/chromiumonly.spec.ts similarity index 100% rename from test/chromiumonly.spec.ts rename to test/src/chromiumonly.spec.ts diff --git a/test/click.spec.ts b/test/src/click.spec.ts similarity index 100% rename from test/click.spec.ts rename to test/src/click.spec.ts diff --git a/test/cookies.spec.ts b/test/src/cookies.spec.ts similarity index 100% rename from test/cookies.spec.ts rename to test/src/cookies.spec.ts diff --git a/test/coverage.spec.ts b/test/src/coverage.spec.ts similarity index 100% rename from test/coverage.spec.ts rename to test/src/coverage.spec.ts diff --git a/test/defaultbrowsercontext.spec.ts b/test/src/defaultbrowsercontext.spec.ts similarity index 100% rename from test/defaultbrowsercontext.spec.ts rename to test/src/defaultbrowsercontext.spec.ts diff --git a/test/dialog.spec.ts b/test/src/dialog.spec.ts similarity index 100% rename from test/dialog.spec.ts rename to test/src/dialog.spec.ts diff --git a/test/diffstyle.css b/test/src/diffstyle.css similarity index 100% rename from test/diffstyle.css rename to test/src/diffstyle.css diff --git a/test/drag-and-drop.spec.ts b/test/src/drag-and-drop.spec.ts similarity index 100% rename from test/drag-and-drop.spec.ts rename to test/src/drag-and-drop.spec.ts diff --git a/test/elementhandle.spec.ts b/test/src/elementhandle.spec.ts similarity index 99% rename from test/elementhandle.spec.ts rename to test/src/elementhandle.spec.ts index 794c41ed..8e8c3c4b 100644 --- a/test/elementhandle.spec.ts +++ b/test/src/elementhandle.spec.ts @@ -25,7 +25,7 @@ import { } from './mocha-utils'; // eslint-disable-line import/extensions import utils from './utils.js'; -import { ElementHandle } from '../lib/cjs/puppeteer/common/JSHandle.js'; +import { ElementHandle } from '../../lib/cjs/puppeteer/common/JSHandle.js'; describe('ElementHandle specs', function () { setupTestBrowserHooks(); diff --git a/test/emulation.spec.ts b/test/src/emulation.spec.ts similarity index 100% rename from test/emulation.spec.ts rename to test/src/emulation.spec.ts diff --git a/test/evaluation.spec.ts b/test/src/evaluation.spec.ts similarity index 100% rename from test/evaluation.spec.ts rename to test/src/evaluation.spec.ts diff --git a/test/fixtures.spec.ts b/test/src/fixtures.spec.ts similarity index 95% rename from test/fixtures.spec.ts rename to test/src/fixtures.spec.ts index 2a5f04a6..ec68dbe1 100644 --- a/test/fixtures.spec.ts +++ b/test/src/fixtures.spec.ts @@ -32,7 +32,7 @@ describe('Fixtures', function () { dumpio: true, }); const res = spawn('node', [ - path.join(__dirname, 'fixtures', 'dumpio.js'), + path.join(__dirname, '../fixtures', 'dumpio.js'), puppeteerPath, JSON.stringify(options), ]); @@ -47,7 +47,7 @@ describe('Fixtures', function () { const { spawn } = await import('child_process'); const options = Object.assign({}, defaultBrowserOptions, { dumpio: true }); const res = spawn('node', [ - path.join(__dirname, 'fixtures', 'dumpio.js'), + path.join(__dirname, '../fixtures', 'dumpio.js'), puppeteerPath, JSON.stringify(options), ]); @@ -64,7 +64,7 @@ describe('Fixtures', function () { dumpio: false, }); const res = spawn('node', [ - path.join(__dirname, 'fixtures', 'closeme.js'), + path.join(__dirname, '../fixtures', 'closeme.js'), puppeteerPath, JSON.stringify(options), ]); diff --git a/test/frame.spec.ts b/test/src/frame.spec.ts similarity index 99% rename from test/frame.spec.ts rename to test/src/frame.spec.ts index f731ac12..18e6c448 100644 --- a/test/frame.spec.ts +++ b/test/src/frame.spec.ts @@ -22,7 +22,7 @@ import { setupTestPageAndContextHooks, itFailsFirefox, } from './mocha-utils'; // eslint-disable-line import/extensions -import { CDPSession } from '../lib/cjs/puppeteer/common/Connection.js'; +import { CDPSession } from '../../lib/cjs/puppeteer/common/Connection.js'; describe('Frame specs', function () { setupTestBrowserHooks(); diff --git a/test/golden-utils.js b/test/src/golden-utils.js similarity index 100% rename from test/golden-utils.js rename to test/src/golden-utils.js diff --git a/test/headful.spec.ts b/test/src/headful.spec.ts similarity index 99% rename from test/headful.spec.ts rename to test/src/headful.spec.ts index 44688433..1eeb67bf 100644 --- a/test/headful.spec.ts +++ b/test/src/headful.spec.ts @@ -31,7 +31,7 @@ const mkdtempAsync = promisify(fs.mkdtemp); const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); -const extensionPath = path.join(__dirname, 'assets', 'simple-extension'); +const extensionPath = path.join(__dirname, '../assets', 'simple-extension'); describeChromeOnly('headful tests', function () { /* These tests fire up an actual browser so let's diff --git a/test/idle_override.spec.ts b/test/src/idle_override.spec.ts similarity index 100% rename from test/idle_override.spec.ts rename to test/src/idle_override.spec.ts diff --git a/test/ignorehttpserrors.spec.ts b/test/src/ignorehttpserrors.spec.ts similarity index 94% rename from test/ignorehttpserrors.spec.ts rename to test/src/ignorehttpserrors.spec.ts index de6f0504..688cee88 100644 --- a/test/ignorehttpserrors.spec.ts +++ b/test/src/ignorehttpserrors.spec.ts @@ -15,6 +15,7 @@ */ import expect from 'expect'; +import { TLSSocket } from 'tls'; import { getTestState, describeFailsFirefox, @@ -65,7 +66,9 @@ describe('ignoreHTTPSErrors', function () { ]); const securityDetails = response.securityDetails(); expect(securityDetails.issuer()).toBe('puppeteer-tests'); - const protocol = serverRequest.socket.getProtocol().replace('v', ' '); + const protocol = (serverRequest.socket as TLSSocket) + .getProtocol() + .replace('v', ' '); expect(securityDetails.protocol()).toBe(protocol); expect(securityDetails.subjectName()).toBe('puppeteer-tests'); expect(securityDetails.validFrom()).toBe(1589357069); @@ -94,7 +97,9 @@ describe('ignoreHTTPSErrors', function () { expect(responses.length).toBe(2); expect(responses[0].status()).toBe(302); const securityDetails = responses[0].securityDetails(); - const protocol = serverRequest.socket.getProtocol().replace('v', ' '); + const protocol = (serverRequest.socket as TLSSocket) + .getProtocol() + .replace('v', ' '); expect(securityDetails.protocol()).toBe(protocol); }); }); diff --git a/test/input.spec.ts b/test/src/input.spec.ts similarity index 98% rename from test/input.spec.ts rename to test/src/input.spec.ts index 2b03d8f3..ad96a47c 100644 --- a/test/input.spec.ts +++ b/test/src/input.spec.ts @@ -23,7 +23,7 @@ import { describeFailsFirefox, } from './mocha-utils'; // eslint-disable-line import/extensions -const FILE_TO_UPLOAD = path.join(__dirname, '/assets/file-to-upload.txt'); +const FILE_TO_UPLOAD = path.join(__dirname, '/../assets/file-to-upload.txt'); describe('input tests', function () { setupTestBrowserHooks(); @@ -228,9 +228,9 @@ describe('input tests', function () { .accept([ path.relative( process.cwd(), - __dirname + '/assets/file-to-upload.txt' + __dirname + '/../assets/file-to-upload.txt' ), - path.relative(process.cwd(), __dirname + '/assets/pptr.png'), + path.relative(process.cwd(), __dirname + '/../assets/pptr.png'), ]) .catch((error_) => (error = error_)); expect(error).not.toBe(null); diff --git a/test/jshandle.spec.ts b/test/src/jshandle.spec.ts similarity index 99% rename from test/jshandle.spec.ts rename to test/src/jshandle.spec.ts index 0d4ec685..9a37ac48 100644 --- a/test/jshandle.spec.ts +++ b/test/src/jshandle.spec.ts @@ -15,7 +15,7 @@ */ import expect from 'expect'; -import { JSHandle } from '../lib/cjs/puppeteer/common/JSHandle.js'; +import { JSHandle } from '../../lib/cjs/puppeteer/common/JSHandle.js'; import { getTestState, setupTestBrowserHooks, diff --git a/test/keyboard.spec.ts b/test/src/keyboard.spec.ts similarity index 99% rename from test/keyboard.spec.ts rename to test/src/keyboard.spec.ts index bfe7d3fe..bde9649c 100644 --- a/test/keyboard.spec.ts +++ b/test/src/keyboard.spec.ts @@ -23,7 +23,7 @@ import { setupTestPageAndContextHooks, itFailsFirefox, } from './mocha-utils'; // eslint-disable-line import/extensions -import { KeyInput } from '../lib/cjs/puppeteer/common/USKeyboardLayout.js'; +import { KeyInput } from '../../lib/cjs/puppeteer/common/USKeyboardLayout.js'; describe('Keyboard', function () { setupTestBrowserHooks(); diff --git a/test/launcher.spec.ts b/test/src/launcher.spec.ts similarity index 99% rename from test/launcher.spec.ts rename to test/src/launcher.spec.ts index ec145280..e01a5d70 100644 --- a/test/launcher.spec.ts +++ b/test/src/launcher.spec.ts @@ -29,7 +29,8 @@ import { import utils from './utils.js'; import expect from 'expect'; import rimraf from 'rimraf'; -import { Page } from '../lib/cjs/puppeteer/common/Page.js'; +import { Page } from '../../lib/cjs/puppeteer/common/Page.js'; +import { TLSSocket } from 'tls'; const mkdtempAsync = promisify(fs.mkdtemp); const readFileAsync = promisify(fs.readFile); @@ -677,7 +678,9 @@ describe('Launcher specs', function () { expect(error).toBe(null); expect(response.ok()).toBe(true); expect(response.securityDetails()).toBeTruthy(); - const protocol = serverRequest.socket.getProtocol().replace('v', ' '); + const protocol = (serverRequest.socket as TLSSocket) + .getProtocol() + .replace('v', ' '); expect(response.securityDetails().protocol()).toBe(protocol); await page.close(); await browser.close(); diff --git a/test/mocha-utils.ts b/test/src/mocha-utils.ts similarity index 92% rename from test/mocha-utils.ts rename to test/src/mocha-utils.ts index 3ed3fd13..8e92f2e0 100644 --- a/test/mocha-utils.ts +++ b/test/src/mocha-utils.ts @@ -24,17 +24,17 @@ import sinon from 'sinon'; import { Browser, BrowserContext, -} from '../lib/cjs/puppeteer/common/Browser.js'; -import { isErrorLike } from '../lib/cjs/puppeteer/common/util.js'; -import { Page } from '../lib/cjs/puppeteer/common/Page.js'; -import { PuppeteerNode } from '../lib/cjs/puppeteer/node/Puppeteer.js'; -import puppeteer from '../lib/cjs/puppeteer/puppeteer.js'; -import { TestServer } from '../utils/testserver/index.js'; +} from '../../lib/cjs/puppeteer/common/Browser.js'; +import { isErrorLike } from '../../lib/cjs/puppeteer/common/util.js'; +import { Page } from '../../lib/cjs/puppeteer/common/Page.js'; +import { PuppeteerNode } from '../../lib/cjs/puppeteer/node/Puppeteer.js'; +import puppeteer from '../../lib/cjs/puppeteer/puppeteer.js'; import utils from './utils.js'; +import { TestServer } from '../../utils/testserver/lib/index.js'; const setupServer = async () => { - const assetsPath = path.join(__dirname, 'assets'); - const cachedPath = path.join(__dirname, 'assets', 'cached'); + const assetsPath = path.join(__dirname, '../assets'); + const cachedPath = path.join(__dirname, '../assets', 'cached'); const port = 8907; const server = await TestServer.create(assetsPath, port); @@ -122,8 +122,8 @@ declare module 'expect/build/types' { const setupGoldenAssertions = (): void => { const suffix = product.toLowerCase(); - const GOLDEN_DIR = path.join(__dirname, 'golden-' + suffix); - const OUTPUT_DIR = path.join(__dirname, 'output-' + suffix); + const GOLDEN_DIR = path.join(__dirname, `../golden-${suffix}`); + const OUTPUT_DIR = path.join(__dirname, `../output-${suffix}`); if (fs.existsSync(OUTPUT_DIR)) { rimraf.sync(OUTPUT_DIR); } @@ -140,8 +140,8 @@ interface PuppeteerTestState { defaultBrowserOptions: { [x: string]: any; }; - server: any; - httpsServer: any; + server: TestServer; + httpsServer: TestServer; isFirefox: boolean; isChrome: boolean; isHeadless: boolean; @@ -299,7 +299,7 @@ export const mochaHooks = { state.isChrome = isChrome; state.isHeadless = isHeadless; state.headless = headless; - state.puppeteerPath = path.resolve(path.join(__dirname, '..')); + state.puppeteerPath = path.resolve(path.join(__dirname, '../..')); }, ], diff --git a/test/mouse.spec.ts b/test/src/mouse.spec.ts similarity index 99% rename from test/mouse.spec.ts rename to test/src/mouse.spec.ts index 9cf880f9..289954ba 100644 --- a/test/mouse.spec.ts +++ b/test/src/mouse.spec.ts @@ -21,7 +21,7 @@ import { setupTestPageAndContextHooks, itFailsFirefox, } from './mocha-utils'; // eslint-disable-line import/extensions -import { KeyInput } from '../lib/cjs/puppeteer/common/USKeyboardLayout.js'; +import { KeyInput } from '../../lib/cjs/puppeteer/common/USKeyboardLayout.js'; interface Dimensions { x: number; diff --git a/test/navigation.spec.ts b/test/src/navigation.spec.ts similarity index 100% rename from test/navigation.spec.ts rename to test/src/navigation.spec.ts diff --git a/test/network.spec.ts b/test/src/network.spec.ts similarity index 99% rename from test/network.spec.ts rename to test/src/network.spec.ts index 01db2768..b1106293 100644 --- a/test/network.spec.ts +++ b/test/src/network.spec.ts @@ -27,7 +27,7 @@ import { itChromeOnly, itFirefoxOnly, } from './mocha-utils'; // eslint-disable-line import/extensions -import { HTTPResponse } from '../lib/cjs/puppeteer/api-docs-entry.js'; +import { HTTPResponse } from '../../lib/cjs/puppeteer/api-docs-entry.js'; describe('network', function () { setupTestBrowserHooks(); @@ -363,7 +363,7 @@ describe('network', function () { const response = await page.goto(server.PREFIX + '/pptr.png'); const imageBuffer = fs.readFileSync( - path.join(__dirname, 'assets', 'pptr.png') + path.join(__dirname, '../assets', 'pptr.png') ); const responseBuffer = await response.buffer(); expect(responseBuffer.equals(imageBuffer)).toBe(true); @@ -374,7 +374,7 @@ describe('network', function () { server.enableGzip('/pptr.png'); const response = await page.goto(server.PREFIX + '/pptr.png'); const imageBuffer = fs.readFileSync( - path.join(__dirname, 'assets', 'pptr.png') + path.join(__dirname, '../assets', 'pptr.png') ); const responseBuffer = await response.buffer(); expect(responseBuffer.equals(imageBuffer)).toBe(true); diff --git a/test/oopif.spec.ts b/test/src/oopif.spec.ts similarity index 99% rename from test/oopif.spec.ts rename to test/src/oopif.spec.ts index 0732ca36..0a4d4a7a 100644 --- a/test/oopif.spec.ts +++ b/test/src/oopif.spec.ts @@ -25,7 +25,7 @@ import { Browser, BrowserContext, Page, -} from '../lib/cjs/puppeteer/api-docs-entry.js'; +} from '../../lib/cjs/puppeteer/api-docs-entry.js'; describeChromeOnly('OOPIF', function () { /* We use a special browser for this test as we need the --site-per-process flag */ diff --git a/test/page.spec.ts b/test/src/page.spec.ts similarity index 98% rename from test/page.spec.ts rename to test/src/page.spec.ts index 45001c45..37cb14ae 100644 --- a/test/page.spec.ts +++ b/test/src/page.spec.ts @@ -26,9 +26,9 @@ import { itFailsFirefox, describeFailsFirefox, } from './mocha-utils'; // eslint-disable-line import/extensions -import { Page, Metrics } from '../lib/cjs/puppeteer/common/Page.js'; -import { CDPSession } from '../lib/cjs/puppeteer/common/Connection.js'; -import { JSHandle } from '../lib/cjs/puppeteer/common/JSHandle.js'; +import { Page, Metrics } from '../../lib/cjs/puppeteer/common/Page.js'; +import { CDPSession } from '../../lib/cjs/puppeteer/common/Connection.js'; +import { JSHandle } from '../../lib/cjs/puppeteer/common/JSHandle.js'; describe('Page', function () { setupTestBrowserHooks(); @@ -967,7 +967,7 @@ describe('Page', function () { it('should throw exception in page context', async () => { const { page } = getTestState(); - await page.exposeFunction('woof', function () { + await page.exposeFunction('woof', () => { throw new Error('WOOF WOOF'); }); const { message, stack } = await page.evaluate(async () => { @@ -978,7 +978,7 @@ describe('Page', function () { } }); expect(message).toBe('WOOF WOOF'); - expect(stack).toContain(__filename); + expect(stack).toContain('page.spec.ts'); }); it('should support throwing "null"', async () => { const { page } = getTestState(); @@ -1425,7 +1425,7 @@ describe('Page', function () { await page.goto(server.EMPTY_PAGE); await page.addScriptTag({ - path: path.join(__dirname, 'assets/es6/es6pathimport.js'), + path: path.join(__dirname, '../assets/es6/es6pathimport.js'), type: 'module', }); await page.waitForFunction('window.__es6injected'); @@ -1462,7 +1462,7 @@ describe('Page', function () { await page.goto(server.EMPTY_PAGE); const scriptHandle = await page.addScriptTag({ - path: path.join(__dirname, 'assets/injectedfile.js'), + path: path.join(__dirname, '../assets/injectedfile.js'), }); expect(scriptHandle.asElement()).not.toBeNull(); expect(await page.evaluate(() => globalThis.__injected)).toBe(42); @@ -1473,7 +1473,7 @@ describe('Page', function () { await page.goto(server.EMPTY_PAGE); await page.addScriptTag({ - path: path.join(__dirname, 'assets/injectedfile.js'), + path: path.join(__dirname, '../assets/injectedfile.js'), }); const result = await page.evaluate( () => globalThis.__injectedError.stack @@ -1572,7 +1572,7 @@ describe('Page', function () { await page.goto(server.EMPTY_PAGE); const styleHandle = await page.addStyleTag({ - path: path.join(__dirname, 'assets/injectedstyle.css'), + path: path.join(__dirname, '../assets/injectedstyle.css'), }); expect(styleHandle.asElement()).not.toBeNull(); expect( @@ -1587,7 +1587,7 @@ describe('Page', function () { await page.goto(server.EMPTY_PAGE); await page.addStyleTag({ - path: path.join(__dirname, 'assets/injectedstyle.css'), + path: path.join(__dirname, '../assets/injectedstyle.css'), }); const styleHandle = await page.$('style'); const styleContent = await page.evaluate( @@ -1717,7 +1717,7 @@ describe('Page', function () { return; } - const outputFile = __dirname + '/assets/output.pdf'; + const outputFile = __dirname + '/../assets/output.pdf'; await page.pdf({ path: outputFile }); expect(fs.readFileSync(outputFile).byteLength).toBeGreaterThan(0); fs.unlinkSync(outputFile); diff --git a/test/proxy.spec.ts b/test/src/proxy.spec.ts similarity index 97% rename from test/proxy.spec.ts rename to test/src/proxy.spec.ts index d26d64e6..3c102fe6 100644 --- a/test/proxy.spec.ts +++ b/test/src/proxy.spec.ts @@ -23,8 +23,9 @@ import { itFailsWindows, } from './mocha-utils'; // eslint-disable-line import/extensions import type { Server, IncomingMessage, ServerResponse } from 'http'; -import type { Browser } from '../lib/cjs/puppeteer/common/Browser.js'; +import type { Browser } from '../../lib/cjs/puppeteer/common/Browser.js'; import type { AddressInfo } from 'net'; +import { TestServer } from '../../utils/testserver/lib/index.js'; const HOSTNAME = os.hostname().toLowerCase(); @@ -32,7 +33,7 @@ const HOSTNAME = os.hostname().toLowerCase(); * Requests to localhost do not get proxied by default. Create a URL using the hostname * instead. */ -function getEmptyPageUrl(server: { PORT: number; EMPTY_PAGE: string }): string { +function getEmptyPageUrl(server: TestServer): string { const emptyPagePath = new URL(server.EMPTY_PAGE).pathname; return `http://${HOSTNAME}:${server.PORT}${emptyPagePath}`; diff --git a/test/queryselector.spec.ts b/test/src/queryselector.spec.ts similarity index 99% rename from test/queryselector.spec.ts rename to test/src/queryselector.spec.ts index be05fb3b..08f9363e 100644 --- a/test/queryselector.spec.ts +++ b/test/src/queryselector.spec.ts @@ -19,7 +19,7 @@ import { setupTestBrowserHooks, setupTestPageAndContextHooks, } from './mocha-utils'; // eslint-disable-line import/extensions -import { CustomQueryHandler } from '../lib/cjs/puppeteer/common/QueryHandler.js'; +import { CustomQueryHandler } from '../../lib/cjs/puppeteer/common/QueryHandler.js'; describe('querySelector', function () { setupTestBrowserHooks(); diff --git a/test/requestinterception-experimental.spec.ts b/test/src/requestinterception-experimental.spec.ts similarity index 99% rename from test/requestinterception-experimental.spec.ts rename to test/src/requestinterception-experimental.spec.ts index ee941102..2365764b 100644 --- a/test/requestinterception-experimental.spec.ts +++ b/test/src/requestinterception-experimental.spec.ts @@ -24,8 +24,8 @@ import { setupTestPageAndContextHooks, describeFailsFirefox, } from './mocha-utils'; // eslint-disable-line import/extensions -import { ActionResult } from '../lib/cjs/puppeteer/api-docs-entry.js'; -import { InterceptResolutionAction } from '../lib/cjs/puppeteer/common/HTTPRequest.js'; +import { ActionResult } from '../../lib/cjs/puppeteer/api-docs-entry.js'; +import { InterceptResolutionAction } from '../../lib/cjs/puppeteer/common/HTTPRequest.js'; describe('request interception', function () { setupTestBrowserHooks(); @@ -592,7 +592,7 @@ describe('request interception', function () { request.continue({}, 0); }); await page.goto( - pathToFileURL(path.join(__dirname, 'assets', 'one-style.html')) + pathToFileURL(path.join(__dirname, '../assets', 'one-style.html')) ); expect(urls.size).toBe(2); expect(urls.has('one-style.html')).toBe(true); @@ -827,7 +827,7 @@ describe('request interception', function () { await page.setRequestInterception(true); page.on('request', (request) => { const imageBuffer = fs.readFileSync( - path.join(__dirname, 'assets', 'pptr.png') + path.join(__dirname, '../assets', 'pptr.png') ); request.respond( { diff --git a/test/requestinterception.spec.ts b/test/src/requestinterception.spec.ts similarity index 99% rename from test/requestinterception.spec.ts rename to test/src/requestinterception.spec.ts index 2bd7660f..f2bd9bf5 100644 --- a/test/requestinterception.spec.ts +++ b/test/src/requestinterception.spec.ts @@ -507,7 +507,7 @@ describe('request interception', function () { request.continue(); }); await page.goto( - pathToFileURL(path.join(__dirname, 'assets', 'one-style.html')) + pathToFileURL(path.join(__dirname, '../assets', 'one-style.html')) ); expect(urls.size).toBe(2); expect(urls.has('one-style.html')).toBe(true); @@ -759,7 +759,7 @@ describe('request interception', function () { await page.setRequestInterception(true); page.on('request', (request) => { const imageBuffer = fs.readFileSync( - path.join(__dirname, 'assets', 'pptr.png') + path.join(__dirname, '../assets', 'pptr.png') ); request.respond({ contentType: 'image/png', diff --git a/test/screenshot.spec.ts b/test/src/screenshot.spec.ts similarity index 100% rename from test/screenshot.spec.ts rename to test/src/screenshot.spec.ts diff --git a/test/target.spec.ts b/test/src/target.spec.ts similarity index 99% rename from test/target.spec.ts rename to test/src/target.spec.ts index c35bbddf..b1656a64 100644 --- a/test/target.spec.ts +++ b/test/src/target.spec.ts @@ -23,7 +23,7 @@ import { setupTestPageAndContextHooks, itFailsFirefox, } from './mocha-utils'; // eslint-disable-line import/extensions -import { Target } from '../lib/cjs/puppeteer/common/Target.js'; +import { Target } from '../../lib/cjs/puppeteer/common/Target.js'; describe('Target', function () { setupTestBrowserHooks(); diff --git a/test/touchscreen.spec.ts b/test/src/touchscreen.spec.ts similarity index 100% rename from test/touchscreen.spec.ts rename to test/src/touchscreen.spec.ts diff --git a/test/tracing.spec.ts b/test/src/tracing.spec.ts similarity index 98% rename from test/tracing.spec.ts rename to test/src/tracing.spec.ts index 67259329..39907e89 100644 --- a/test/tracing.spec.ts +++ b/test/src/tracing.spec.ts @@ -32,7 +32,7 @@ describeChromeOnly('Tracing', function () { const { defaultBrowserOptions, puppeteer } = getTestState(); browser = await puppeteer.launch(defaultBrowserOptions); page = await browser.newPage(); - outputFile = path.join(__dirname, 'assets', 'trace.json'); + outputFile = path.join(__dirname, 'trace.json'); }); afterEach(async () => { diff --git a/test/utils.js b/test/src/utils.js similarity index 95% rename from test/utils.js rename to test/src/utils.js index 63f1c2d7..60271411 100644 --- a/test/utils.js +++ b/test/src/utils.js @@ -17,13 +17,10 @@ // TODO (@jackfranklin): convert to TS and enable type checking. // @ts-nocheck -const fs = require('fs'); const path = require('path'); const expect = require('expect'); const GoldenUtils = require('./golden-utils.js'); -const PROJECT_ROOT = fs.existsSync(path.join(__dirname, '..', 'package.json')) - ? path.join(__dirname, '..') - : path.join(__dirname, '..', '..'); +const PROJECT_ROOT = path.join(__dirname, '..', '..'); const utils = (module.exports = { extendExpectWithToBeGolden: function (goldenDir, outputDir) { diff --git a/test/waittask.spec.ts b/test/src/waittask.spec.ts similarity index 100% rename from test/waittask.spec.ts rename to test/src/waittask.spec.ts diff --git a/test/worker.spec.ts b/test/src/worker.spec.ts similarity index 96% rename from test/worker.spec.ts rename to test/src/worker.spec.ts index b4f81dbb..fde54500 100644 --- a/test/worker.spec.ts +++ b/test/src/worker.spec.ts @@ -22,8 +22,8 @@ import { describeFailsFirefox, } from './mocha-utils'; // eslint-disable-line import/extensions import utils from './utils.js'; -import { WebWorker } from '../lib/cjs/puppeteer/common/WebWorker.js'; -import { ConsoleMessage } from '../lib/cjs/puppeteer/common/ConsoleMessage.js'; +import { WebWorker } from '../../lib/cjs/puppeteer/common/WebWorker.js'; +import { ConsoleMessage } from '../../lib/cjs/puppeteer/common/ConsoleMessage.js'; const { waitEvent } = utils; describeFailsFirefox('Workers', function () { diff --git a/test/tsconfig.json b/test/tsconfig.json index 15b145c0..abe9d117 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -1,6 +1,21 @@ { - "extends": "./tsconfig.test.json", "compilerOptions": { - "noEmit": true - } + "esModuleInterop": true, + "allowJs": true, + "checkJs": false, + "target": "esnext", + "module": "CommonJS", + "moduleResolution": "node", + "declaration": false, + "declarationMap": false, + "resolveJsonModule": true, + "sourceMap": true, + "rootDir": "src", + "outDir": "build" + }, + "include": ["src"], + "references": [ + { "path": "../src/tsconfig.cjs.json" }, + { "path": "../utils/testserver/tsconfig.json" } + ] } diff --git a/test/tsconfig.test.json b/test/tsconfig.test.json deleted file mode 100644 index 7db8c441..00000000 --- a/test/tsconfig.test.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "esModuleInterop": true, - "allowJs": true, - "checkJs": true, - "target": "esnext", - "module": "CommonJS", - "moduleResolution": "node", - "declaration": true, - "declarationMap": true, - "resolveJsonModule": true, - "sourceMap": true - } -} diff --git a/utils/doclint/check_public_api/index.js b/utils/doclint/check_public_api/index.js index 29fd9b58..fea3ad4c 100644 --- a/utils/doclint/check_public_api/index.js +++ b/utils/doclint/check_public_api/index.js @@ -18,9 +18,36 @@ const jsBuilder = require('./JSBuilder.js'); const mdBuilder = require('./MDBuilder.js'); const Documentation = require('./Documentation.js'); const Message = require('../Message.js'); -const { - MODULES_TO_CHECK_FOR_COVERAGE, -} = require('../../../test/coverage-utils.js'); + +const MODULES_TO_CHECK_FOR_COVERAGE = { + Accessibility: '../../lib/cjs/puppeteer/common/Accessibility', + Browser: '../../lib/cjs/puppeteer/common/Browser', + BrowserContext: '../../lib/cjs/puppeteer/common/Browser', + BrowserFetcher: '../../lib/cjs/puppeteer/node/BrowserFetcher', + CDPSession: '../../lib/cjs/puppeteer/common/Connection', + ConsoleMessage: '../../lib/cjs/puppeteer/common/ConsoleMessage', + Coverage: '../../lib/cjs/puppeteer/common/Coverage', + Dialog: '../../lib/cjs/puppeteer/common/Dialog', + ElementHandle: '../../lib/cjs/puppeteer/common/JSHandle', + ExecutionContext: '../../lib/cjs/puppeteer/common/ExecutionContext', + EventEmitter: '../../lib/cjs/puppeteer/common/EventEmitter', + FileChooser: '../../lib/cjs/puppeteer/common/FileChooser', + Frame: '../../lib/cjs/puppeteer/common/FrameManager', + JSHandle: '../../lib/cjs/puppeteer/common/JSHandle', + Keyboard: '../../lib/cjs/puppeteer/common/Input', + Mouse: '../../lib/cjs/puppeteer/common/Input', + Page: '../../lib/cjs/puppeteer/common/Page', + Puppeteer: '../../lib/cjs/puppeteer/common/Puppeteer', + PuppeteerNode: '../../lib/cjs/puppeteer/node/Puppeteer', + HTTPRequest: '../../lib/cjs/puppeteer/common/HTTPRequest', + HTTPResponse: '../../lib/cjs/puppeteer/common/HTTPResponse', + SecurityDetails: '../../lib/cjs/puppeteer/common/SecurityDetails', + Target: '../../lib/cjs/puppeteer/common/Target', + TimeoutError: '../../lib/cjs/puppeteer/common/Errors', + Touchscreen: '../../lib/cjs/puppeteer/common/Input', + Tracing: '../../lib/cjs/puppeteer/common/Tracing', + WebWorker: '../../lib/cjs/puppeteer/common/WebWorker', +}; const EXCLUDE_PROPERTIES = new Set([ 'Browser.create', diff --git a/utils/testserver/index.js b/utils/testserver/index.js deleted file mode 100644 index 86191533..00000000 --- a/utils/testserver/index.js +++ /dev/null @@ -1,303 +0,0 @@ -// @ts-nocheck - -/** - * Copyright 2017 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. - */ - -const http = require('http'); -const https = require('https'); -const url = require('url'); -const fs = require('fs'); -const path = require('path'); -const mime = require('mime'); -const WebSocketServer = require('ws').Server; - -const fulfillSymbol = Symbol('fullfil callback'); -const rejectSymbol = Symbol('reject callback'); - -class TestServer { - /** @type number */ - PORT = undefined; - /** @type string */ - PREFIX = undefined; - /** @type string */ - CROSS_PROCESS_PREFIX = undefined; - /** @type string */ - EMPTY_PAGE = undefined; - - /** - * @param {string} dirPath - * @param {number} port - * @returns {!TestServer} - */ - static async create(dirPath, port) { - const server = new TestServer(dirPath, port); - await new Promise((x) => server._server.once('listening', x)); - return server; - } - - /** - * @param {string} dirPath - * @param {number} port - * @returns {!TestServer} - */ - static async createHTTPS(dirPath, port) { - const server = new TestServer(dirPath, port, { - key: fs.readFileSync(path.join(__dirname, 'key.pem')), - cert: fs.readFileSync(path.join(__dirname, 'cert.pem')), - passphrase: 'aaaa', - }); - await new Promise((x) => server._server.once('listening', x)); - return server; - } - - /** - * @param {string} dirPath - * @param {number} port - * @param {!Object=} sslOptions - */ - constructor(dirPath, port, sslOptions) { - if (sslOptions) { - this._server = https.createServer(sslOptions, this._onRequest.bind(this)); - } else { - this._server = http.createServer(this._onRequest.bind(this)); - } - this._server.on('connection', (socket) => this._onSocket(socket)); - this._wsServer = new WebSocketServer({ server: this._server }); - this._wsServer.on('connection', this._onWebSocketConnection.bind(this)); - this._server.listen(port); - this._dirPath = dirPath; - - this._startTime = new Date(); - this._cachedPathPrefix = null; - - /** @type {!Set} */ - this._sockets = new Set(); - - /** @type {!Map} */ - this._routes = new Map(); - /** @type {!Map} */ - this._auths = new Map(); - /** @type {!Map} */ - this._csp = new Map(); - /** @type {!Set} */ - this._gzipRoutes = new Set(); - /** @type {!Map} */ - this._requestSubscribers = new Map(); - } - - _onSocket(socket) { - this._sockets.add(socket); - // ECONNRESET is a legit error given - // that tab closing simply kills process. - socket.on('error', (error) => { - if (error.code !== 'ECONNRESET') { - throw error; - } - }); - socket.once('close', () => this._sockets.delete(socket)); - } - - /** - * @param {string} pathPrefix - */ - enableHTTPCache(pathPrefix) { - this._cachedPathPrefix = pathPrefix; - } - - /** - * @param {string} path - * @param {string} username - * @param {string} password - */ - setAuth(path, username, password) { - this._auths.set(path, { username, password }); - } - - enableGzip(path) { - this._gzipRoutes.add(path); - } - - /** - * @param {string} path - * @param {string} csp - */ - setCSP(path, csp) { - this._csp.set(path, csp); - } - - async stop() { - this.reset(); - for (const socket of this._sockets) { - socket.destroy(); - } - this._sockets.clear(); - await new Promise((x) => this._server.close(x)); - } - - /** - * @param {string} path - * @param {function(!IncomingMessage, !ServerResponse)} handler - */ - setRoute(path, handler) { - this._routes.set(path, handler); - } - - /** - * @param {string} from - * @param {string} to - */ - setRedirect(from, to) { - this.setRoute(from, (req, res) => { - res.writeHead(302, { location: to }); - res.end(); - }); - } - - /** - * @param {string} path - * @returns {!Promise} - */ - waitForRequest(path) { - let promise = this._requestSubscribers.get(path); - if (promise) { - return promise; - } - let fulfill, reject; - promise = new Promise((f, r) => { - fulfill = f; - reject = r; - }); - promise[fulfillSymbol] = fulfill; - promise[rejectSymbol] = reject; - this._requestSubscribers.set(path, promise); - return promise; - } - - reset() { - this._routes.clear(); - this._auths.clear(); - this._csp.clear(); - this._gzipRoutes.clear(); - const error = new Error('Static Server has been reset'); - for (const subscriber of this._requestSubscribers.values()) { - subscriber[rejectSymbol].call(null, error); - } - this._requestSubscribers.clear(); - } - - _onRequest(request, response) { - request.on('error', (error) => { - if (error.code === 'ECONNRESET') { - response.end(); - } else { - throw error; - } - }); - request.postBody = new Promise((resolve) => { - let body = ''; - request.on('data', (chunk) => (body += chunk)); - request.on('end', () => resolve(body)); - }); - const pathName = url.parse(request.url).path; - if (this._auths.has(pathName)) { - const auth = this._auths.get(pathName); - const credentials = Buffer.from( - (request.headers.authorization || '').split(' ')[1] || '', - 'base64' - ).toString(); - if (credentials !== `${auth.username}:${auth.password}`) { - response.writeHead(401, { - 'WWW-Authenticate': 'Basic realm="Secure Area"', - }); - response.end('HTTP Error 401 Unauthorized: Access is denied'); - return; - } - } - // Notify request subscriber. - if (this._requestSubscribers.has(pathName)) { - this._requestSubscribers.get(pathName)[fulfillSymbol].call(null, request); - this._requestSubscribers.delete(pathName); - } - const handler = this._routes.get(pathName); - if (handler) { - handler.call(null, request, response); - } else { - const pathName = url.parse(request.url).path; - this.serveFile(request, response, pathName); - } - } - - /** - * @param {!IncomingMessage} request - * @param {!ServerResponse} response - * @param {string} pathName - */ - serveFile(request, response, pathName) { - if (pathName === '/') { - pathName = '/index.html'; - } - const filePath = path.join(this._dirPath, pathName.substring(1)); - - if ( - this._cachedPathPrefix !== null && - filePath.startsWith(this._cachedPathPrefix) - ) { - if (request.headers['if-modified-since']) { - response.statusCode = 304; // not modified - response.end(); - return; - } - response.setHeader('Cache-Control', 'public, max-age=31536000'); - response.setHeader('Last-Modified', this._startTime.toISOString()); - } else { - response.setHeader('Cache-Control', 'no-cache, no-store'); - } - if (this._csp.has(pathName)) { - response.setHeader('Content-Security-Policy', this._csp.get(pathName)); - } - - fs.readFile(filePath, (err, data) => { - if (err) { - response.statusCode = 404; - response.end(`File not found: ${filePath}`); - return; - } - const mimeType = mime.getType(filePath); - const isTextEncoding = /^text\/|^application\/(javascript|json)/.test( - mimeType - ); - const contentType = isTextEncoding - ? `${mimeType}; charset=utf-8` - : mimeType; - response.setHeader('Content-Type', contentType); - if (this._gzipRoutes.has(pathName)) { - response.setHeader('Content-Encoding', 'gzip'); - const zlib = require('zlib'); - zlib.gzip(data, (_, result) => { - response.end(result); - }); - } else { - response.end(data); - } - }); - } - - _onWebSocketConnection(connection) { - connection.send('opened'); - } -} - -module.exports = { TestServer }; diff --git a/utils/testserver/package.json b/utils/testserver/package.json index 6cac90ff..1029f16d 100644 --- a/utils/testserver/package.json +++ b/utils/testserver/package.json @@ -2,7 +2,7 @@ "name": "@pptr/testserver", "version": "0.5.0", "description": "testing server", - "main": "index.js", + "main": "lib/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/utils/testserver/src/index.ts b/utils/testserver/src/index.ts new file mode 100644 index 00000000..203b113a --- /dev/null +++ b/utils/testserver/src/index.ts @@ -0,0 +1,278 @@ +/** + * Copyright 2017 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 assert from 'assert'; +import { readFile, readFileSync } from 'fs'; +import { + createServer as createHttpServer, + IncomingMessage, + RequestListener, + Server as HttpServer, + ServerResponse, +} from 'http'; +import { + createServer as createHttpsServer, + Server as HttpsServer, + ServerOptions as HttpsServerOptions, +} from 'https'; +import { getType as getMimeType } from 'mime'; +import { join } from 'path'; +import { Duplex } from 'stream'; +import { Server as WebSocketServer, WebSocket } from 'ws'; +import { gzip } from 'zlib'; + +interface Subscriber { + resolve: (msg: IncomingMessage) => void; + reject: (err?: Error) => void; + promise: Promise; +} + +type TestIncomingMessage = IncomingMessage & { postBody?: Promise }; + +export class TestServer { + PORT?: number; + PREFIX?: string; + CROSS_PROCESS_PREFIX?: string; + EMPTY_PAGE?: string; + + #dirPath: string; + #server: HttpsServer | HttpServer; + #wsServer: WebSocketServer; + + #startTime = new Date(); + #cachedPathPrefix?: string; + + #connections = new Set(); + #routes = new Map< + string, + (msg: IncomingMessage, res: ServerResponse) => void + >(); + #auths = new Map(); + #csp = new Map(); + #gzipRoutes = new Set(); + #requestSubscribers = new Map(); + + static async create(dirPath: string, port: number): Promise { + const server = new TestServer(dirPath, port); + await new Promise((x) => server.#server.once('listening', x)); + return server; + } + + static async createHTTPS(dirPath: string, port: number): Promise { + const server = new TestServer(dirPath, port, { + key: readFileSync(join(__dirname, '..', 'key.pem')), + cert: readFileSync(join(__dirname, '..', 'cert.pem')), + passphrase: 'aaaa', + }); + await new Promise((x) => server.#server.once('listening', x)); + return server; + } + + constructor(dirPath: string, port: number, sslOptions?: HttpsServerOptions) { + this.#dirPath = dirPath; + + if (sslOptions) { + this.#server = createHttpsServer(sslOptions, this.#onRequest); + } else { + this.#server = createHttpServer(this.#onRequest); + } + this.#server.on('connection', this.#onServerConnection); + this.#wsServer = new WebSocketServer({ server: this.#server }); + this.#wsServer.on('connection', this.#onWebSocketConnection); + this.#server.listen(port); + } + + #onServerConnection = (connection: Duplex): void => { + this.#connections.add(connection); + // ECONNRESET is a legit error given + // that tab closing simply kills process. + connection.on('error', (error) => { + if ((error as NodeJS.ErrnoException).code !== 'ECONNRESET') { + throw error; + } + }); + connection.once('close', () => this.#connections.delete(connection)); + }; + + enableHTTPCache(pathPrefix: string): void { + this.#cachedPathPrefix = pathPrefix; + } + + setAuth(path: string, username: string, password: string): void { + this.#auths.set(path, { username, password }); + } + + enableGzip(path: string): void { + this.#gzipRoutes.add(path); + } + + setCSP(path: string, csp: string): void { + this.#csp.set(path, csp); + } + + async stop(): Promise { + this.reset(); + for (const socket of this.#connections) { + socket.destroy(); + } + this.#connections.clear(); + await new Promise((x) => this.#server.close(x)); + } + + setRoute( + path: string, + handler: (req: IncomingMessage, res: ServerResponse) => void + ): void { + this.#routes.set(path, handler); + } + + setRedirect(from: string, to: string): void { + this.setRoute(from, (_, res) => { + res.writeHead(302, { location: to }); + res.end(); + }); + } + + waitForRequest(path: string): Promise { + const subscriber = this.#requestSubscribers.get(path); + if (subscriber) { + return subscriber.promise; + } + let resolve!: (value: IncomingMessage) => void; + let reject!: (reason?: Error) => void; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + this.#requestSubscribers.set(path, { resolve, reject, promise }); + return promise; + } + + reset(): void { + this.#routes.clear(); + this.#auths.clear(); + this.#csp.clear(); + this.#gzipRoutes.clear(); + const error = new Error('Static Server has been reset'); + for (const subscriber of this.#requestSubscribers.values()) { + subscriber.reject.call(undefined, error); + } + this.#requestSubscribers.clear(); + } + + #onRequest: RequestListener = ( + request: TestIncomingMessage, + response + ): void => { + request.on('error', (error: { code: string }) => { + if (error.code === 'ECONNRESET') { + response.end(); + } else { + throw error; + } + }); + request.postBody = new Promise((resolve) => { + let body = ''; + request.on('data', (chunk: string) => (body += chunk)); + request.on('end', () => resolve(body)); + }); + assert(request.url); + const url = new URL(request.url, `https://${request.headers.host}`); + const path = url.pathname + url.search; + const auth = this.#auths.get(path); + if (auth) { + const credentials = Buffer.from( + (request.headers.authorization || '').split(' ')[1] || '', + 'base64' + ).toString(); + if (credentials !== `${auth.username}:${auth.password}`) { + response.writeHead(401, { + 'WWW-Authenticate': 'Basic realm="Secure Area"', + }); + response.end('HTTP Error 401 Unauthorized: Access is denied'); + return; + } + } + const subscriber = this.#requestSubscribers.get(path); + if (subscriber) { + subscriber.resolve.call(undefined, request); + this.#requestSubscribers.delete(path); + } + const handler = this.#routes.get(path); + if (handler) { + handler.call(undefined, request, response); + } else { + this.serveFile(request, response, path); + } + }; + + serveFile( + request: IncomingMessage, + response: ServerResponse, + pathName: string + ): void { + if (pathName === '/') { + pathName = '/index.html'; + } + const filePath = join(this.#dirPath, pathName.substring(1)); + + if (this.#cachedPathPrefix && filePath.startsWith(this.#cachedPathPrefix)) { + if (request.headers['if-modified-since']) { + response.statusCode = 304; // not modified + response.end(); + return; + } + response.setHeader('Cache-Control', 'public, max-age=31536000'); + response.setHeader('Last-Modified', this.#startTime.toISOString()); + } else { + response.setHeader('Cache-Control', 'no-cache, no-store'); + } + const csp = this.#csp.get(pathName); + if (csp) { + response.setHeader('Content-Security-Policy', csp); + } + + readFile(filePath, (err, data) => { + if (err) { + response.statusCode = 404; + response.end(`File not found: ${filePath}`); + return; + } + const mimeType = getMimeType(filePath); + if (mimeType) { + const isTextEncoding = /^text\/|^application\/(javascript|json)/.test( + mimeType + ); + const contentType = isTextEncoding + ? `${mimeType}; charset=utf-8` + : mimeType; + response.setHeader('Content-Type', contentType); + } + if (this.#gzipRoutes.has(pathName)) { + response.setHeader('Content-Encoding', 'gzip'); + gzip(data, (_, result) => { + response.end(result); + }); + } else { + response.end(data); + } + }); + } + + #onWebSocketConnection = (socket: WebSocket): void => { + socket.send('opened'); + }; +} diff --git a/utils/testserver/tsconfig.json b/utils/testserver/tsconfig.json new file mode 100644 index 00000000..16efc532 --- /dev/null +++ b/utils/testserver/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib", + "composite": true, + "allowJs": true, + "module": "CommonJS" + }, + "include": ["src"] +}