diff --git a/package-lock.json b/package-lock.json index 07a271480b..4f17825d9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,7 @@ "@types/extract-zip": "^1.6.2", "@types/mime": "^2.0.3", "@types/minimatch": "^3.0.3", - "@types/node": "^10.17.28", + "@types/node": "^14.17.15", "@types/pixelmatch": "^5.2.1", "@types/pngjs": "^3.4.2", "@types/progress": "^2.0.3", @@ -87,7 +87,7 @@ "concurrently": "^6.2.1", "cross-env": "^7.0.2", "css-loader": "^5.2.6", - "electron": "^11.1.1", + "electron": "^12.2.1", "eslint": "^7.31.0", "eslint-plugin-notice": "^0.9.10", "eslint-plugin-react-hooks": "^4.2.0", @@ -1486,9 +1486,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + "version": "14.17.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.15.tgz", + "integrity": "sha512-D1sdW0EcSCmNdLKBGMYb38YsHUS6JcM7yQ6sLQ9KuZ35ck7LYCKE7kYFHOO59ayFOY3zobWVZxf4KXhYHcHYFA==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -4151,13 +4151,14 @@ } }, "node_modules/electron": { - "version": "11.4.6", - "resolved": "https://registry.npmjs.org/electron/-/electron-11.4.6.tgz", - "integrity": "sha512-WN7zUwaAmcB1lXyyaMxPsNWAFCpRMDltQb4zCjvoD5TBBoePcjd6UwyVUD93pSKJXjmWoae8PbZWrbZlXowcSg==", + "version": "12.2.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-12.2.1.tgz", + "integrity": "sha512-Gp+rO81qoaRDP7PTVtBOvnSgDgGlwUuAEWXxi621uOJMIlYFas9ChXe8pjdL0R0vyUpiHVzp6Vrjx41VZqEpsw==", "dev": true, + "hasInstallScript": true, "dependencies": { "@electron/get": "^1.0.1", - "@types/node": "^12.0.12", + "@types/node": "^14.6.2", "extract-zip": "^1.0.3" }, "bin": { @@ -4173,9 +4174,9 @@ "integrity": "sha512-WmCgAeURsMFiyoJ646eUaJQ7GNfvMRLXo+GamUyKVNEM4MqTAsXyC0f38JEB4N3BtbD0tlAKozGP5E2T9K3YGg==" }, "node_modules/electron/node_modules/@types/node": { - "version": "12.20.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.13.tgz", - "integrity": "sha512-1x8W5OpxPq+T85OUsHRP6BqXeosKmeXRtjoF39STcdf/UWLqUsoehstZKOi0CunhVqHG17AyZgpj20eRVooK6A==", + "version": "14.17.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.20.tgz", + "integrity": "sha512-gI5Sl30tmhXsqkNvopFydP7ASc4c2cLfGNQrVKN3X90ADFWFsPEsotm/8JHSUJQKTHbwowAHtcJPeyVhtKv0TQ==", "dev": true }, "node_modules/electron/node_modules/debug": { @@ -11936,9 +11937,9 @@ "dev": true }, "@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + "version": "14.17.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.15.tgz", + "integrity": "sha512-D1sdW0EcSCmNdLKBGMYb38YsHUS6JcM7yQ6sLQ9KuZ35ck7LYCKE7kYFHOO59ayFOY3zobWVZxf4KXhYHcHYFA==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -14161,20 +14162,20 @@ } }, "electron": { - "version": "11.4.6", - "resolved": "https://registry.npmjs.org/electron/-/electron-11.4.6.tgz", - "integrity": "sha512-WN7zUwaAmcB1lXyyaMxPsNWAFCpRMDltQb4zCjvoD5TBBoePcjd6UwyVUD93pSKJXjmWoae8PbZWrbZlXowcSg==", + "version": "12.2.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-12.2.1.tgz", + "integrity": "sha512-Gp+rO81qoaRDP7PTVtBOvnSgDgGlwUuAEWXxi621uOJMIlYFas9ChXe8pjdL0R0vyUpiHVzp6Vrjx41VZqEpsw==", "dev": true, "requires": { "@electron/get": "^1.0.1", - "@types/node": "^12.0.12", + "@types/node": "^14.6.2", "extract-zip": "^1.0.3" }, "dependencies": { "@types/node": { - "version": "12.20.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.13.tgz", - "integrity": "sha512-1x8W5OpxPq+T85OUsHRP6BqXeosKmeXRtjoF39STcdf/UWLqUsoehstZKOi0CunhVqHG17AyZgpj20eRVooK6A==", + "version": "14.17.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.20.tgz", + "integrity": "sha512-gI5Sl30tmhXsqkNvopFydP7ASc4c2cLfGNQrVKN3X90ADFWFsPEsotm/8JHSUJQKTHbwowAHtcJPeyVhtKv0TQ==", "dev": true }, "debug": { diff --git a/package.json b/package.json index d6e6635c8b..df56ca2bce 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "@types/extract-zip": "^1.6.2", "@types/mime": "^2.0.3", "@types/minimatch": "^3.0.3", - "@types/node": "^10.17.28", + "@types/node": "^14.17.15", "@types/pixelmatch": "^5.2.1", "@types/pngjs": "^3.4.2", "@types/progress": "^2.0.3", @@ -116,7 +116,7 @@ "concurrently": "^6.2.1", "cross-env": "^7.0.2", "css-loader": "^5.2.6", - "electron": "^11.1.1", + "electron": "^12.2.1", "eslint": "^7.31.0", "eslint-plugin-notice": "^0.9.10", "eslint-plugin-react-hooks": "^4.2.0", diff --git a/src/client/fetch.ts b/src/client/fetch.ts index 6d3a02184a..cd03432506 100644 --- a/src/client/fetch.ts +++ b/src/client/fetch.ts @@ -241,7 +241,7 @@ function filePayloadToJson(payload: FilePayload): ServerFilePayload { async function readStreamToJson(stream: fs.ReadStream): Promise { const buffer = await new Promise((resolve, reject) => { const chunks: Buffer[] = []; - stream.on('data', chunk => chunks.push(chunk)); + stream.on('data', chunk => chunks.push(chunk as Buffer)); stream.on('end', () => resolve(Buffer.concat(chunks))); stream.on('error', err => reject(err)); }); diff --git a/src/client/stream.ts b/src/client/stream.ts index 51b06aceac..151d225cef 100644 --- a/src/client/stream.ts +++ b/src/client/stream.ts @@ -48,7 +48,7 @@ class StreamImpl extends Readable { this.push(null); } - override _destroy(error: Error | null, callback: (error: Error | null) => void): void { + override _destroy(error: Error | null, callback: (error: Error | null | undefined) => void): void { // Stream might be destroyed after the connection was closed. this._channel.close().catch(e => null); super._destroy(error, callback); diff --git a/src/outofprocess.ts b/src/outofprocess.ts index 3a58403a83..69d831f528 100644 --- a/src/outofprocess.ts +++ b/src/outofprocess.ts @@ -51,7 +51,7 @@ class PlaywrightClient { this._driverProcess.on('exit', this._onExit); const connection = new Connection(); - const transport = new Transport(this._driverProcess.stdin, this._driverProcess.stdout); + const transport = new Transport(this._driverProcess.stdin!, this._driverProcess.stdout!); connection.onmessage = message => transport.send(JSON.stringify(message)); transport.onmessage = message => connection.dispatch(JSON.parse(message)); this._closePromise = new Promise(f => transport.onclose = f); @@ -61,9 +61,9 @@ class PlaywrightClient { async stop() { this._driverProcess.removeListener('exit', this._onExit); - this._driverProcess.stdin.destroy(); - this._driverProcess.stdout.destroy(); - this._driverProcess.stderr.destroy(); + this._driverProcess.stdin!.destroy(); + this._driverProcess.stdout!.destroy(); + this._driverProcess.stderr!.destroy(); await this._closePromise; } } diff --git a/src/remote/playwrightServer.ts b/src/remote/playwrightServer.ts index 11fe45d393..16f632c179 100644 --- a/src/remote/playwrightServer.ts +++ b/src/remote/playwrightServer.ts @@ -76,6 +76,10 @@ export class PlaywrightServer { const wsEndpoint = await new Promise((resolve, reject) => { server.listen(port, () => { const address = server.address(); + if (!address) { + reject(new Error('Could not bind server socket')); + return; + } const wsEndpoint = typeof address === 'string' ? `${address}${path}` : `ws://127.0.0.1:${address.port}${path}`; resolve(wsEndpoint); }).on('error', reject); diff --git a/src/server/chromium/videoRecorder.ts b/src/server/chromium/videoRecorder.ts index 65e7948e6a..644af4fe18 100644 --- a/src/server/chromium/videoRecorder.ts +++ b/src/server/chromium/videoRecorder.ts @@ -109,16 +109,16 @@ export class VideoRecorder { tempDirectories: [], attemptToGracefullyClose: async () => { progress.log('Closing stdin...'); - launchedProcess.stdin.end(); + launchedProcess.stdin!.end(); }, onExit: (exitCode, signal) => { progress.log(`ffmpeg onkill exitCode=${exitCode} signal=${signal}`); }, }); - launchedProcess.stdin.on('finish', () => { + launchedProcess.stdin!.on('finish', () => { progress.log('ffmpeg finished input.'); }); - launchedProcess.stdin.on('error', () => { + launchedProcess.stdin!.on('error', () => { progress.log('ffmpeg error.'); }); this._process = launchedProcess; @@ -150,7 +150,7 @@ export class VideoRecorder { } private async _sendFrame(frame: Buffer) { - return new Promise(f => this._process!.stdin.write(frame, f)).then(error => { + return new Promise(f => this._process!.stdin!.write(frame, f)).then(error => { if (error) this._progress.log(`ffmpeg failed to write: ${error}`); }); diff --git a/src/server/electron/electron.ts b/src/server/electron/electron.ts index 884b0968f1..d59f3d11d7 100644 --- a/src/server/electron/electron.ts +++ b/src/server/electron/electron.ts @@ -193,7 +193,7 @@ export class Electron extends SdkObject { function waitForLine(progress: Progress, process: childProcess.ChildProcess, regex: RegExp): Promise { return new Promise((resolve, reject) => { - const rl = readline.createInterface({ input: process.stderr }); + const rl = readline.createInterface({ input: process.stderr! }); const failError = new Error('Process failed to launch!'); const listeners = [ eventsHelper.addEventListener(rl, 'line', onLine), diff --git a/src/test/webServer.ts b/src/test/webServer.ts index 31f5a6cdae..b02d3586b6 100644 --- a/src/test/webServer.ts +++ b/src/test/webServer.ts @@ -78,8 +78,8 @@ export class WebServer { }); this._killProcess = kill; - launchedProcess.stderr.pipe(newProcessLogPrefixer()).pipe(process.stderr); - launchedProcess.stdout.on('data', () => {}); + launchedProcess.stderr!.pipe(newProcessLogPrefixer()).pipe(process.stderr); + launchedProcess.stdout!.on('data', () => {}); } private async _waitForProcess() { diff --git a/src/utils/httpServer.ts b/src/utils/httpServer.ts index 6f91766439..2380cc82be 100644 --- a/src/utils/httpServer.ts +++ b/src/utils/httpServer.ts @@ -19,6 +19,7 @@ import fs from 'fs'; import path from 'path'; import { Server as WebSocketServer } from 'ws'; import * as mime from 'mime'; +import { assert } from './utils'; export type ServerRouteHandler = (request: http.IncomingMessage, response: http.ServerResponse) => boolean; @@ -61,6 +62,7 @@ export class HttpServer { if (typeof address === 'string') { this._urlPrefix = address; } else { + assert(address, 'Could not bind server socket'); this._port = address.port; this._urlPrefix = `http://127.0.0.1:${address.port}`; } diff --git a/src/utils/processLauncher.ts b/src/utils/processLauncher.ts index 8fc94aaaa6..9586e92e2f 100644 --- a/src/utils/processLauncher.ts +++ b/src/utils/processLauncher.ts @@ -73,7 +73,7 @@ export async function launchProcess(options: LaunchProcessOptions): Promise { options.log(`[pid=${spawnedProcess.pid || 'N/A'}] starting temporary directories cleanup`); @@ -98,12 +98,12 @@ export async function launchProcess(options: LaunchProcessOptions): Promise pid=${spawnedProcess.pid}`); - const stdout = readline.createInterface({ input: spawnedProcess.stdout }); + const stdout = readline.createInterface({ input: spawnedProcess.stdout! }); stdout.on('line', (data: string) => { options.log(`[pid=${spawnedProcess.pid}][out] ` + data); }); - const stderr = readline.createInterface({ input: spawnedProcess.stderr }); + const stderr = readline.createInterface({ input: spawnedProcess.stderr! }); stderr.on('line', (data: string) => { options.log(`[pid=${spawnedProcess.pid}][err] ` + data); }); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 80fe8b7280..dee2df8636 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -226,7 +226,7 @@ function toMegabytes(bytes: number) { return `${Math.round(mb * 10) / 10} Mb`; } -export function spawnAsync(cmd: string, args: string[], options?: SpawnOptions): Promise<{stdout: string, stderr: string, code: number, error?: Error}> { +export function spawnAsync(cmd: string, args: string[], options: SpawnOptions = {}): Promise<{stdout: string, stderr: string, code: number | null, error?: Error}> { const process = spawn(cmd, args, options); return new Promise(resolve => { diff --git a/tests/config/proxy.ts b/tests/config/proxy.ts index 8ad66e1f83..1b5d953423 100644 --- a/tests/config/proxy.ts +++ b/tests/config/proxy.ts @@ -31,7 +31,7 @@ export class TestProxy { static async create(port: number): Promise { const proxy = new TestProxy(port); - await new Promise(f => proxy._server.listen(port, f)); + await new Promise(f => proxy._server.listen(port, f)); return proxy; } diff --git a/tests/page/frame-evaluate.spec.ts b/tests/page/frame-evaluate.spec.ts index b2340304a4..83ce00fb2f 100644 --- a/tests/page/frame-evaluate.spec.ts +++ b/tests/page/frame-evaluate.spec.ts @@ -42,8 +42,9 @@ function expectContexts(pageImpl, count, browserName) { expect(pageImpl._delegate._contextIdToContext.size).toBe(count); } -it('should dispose context on navigation', async ({ page, server, toImpl, browserName, mode }) => { +it('should dispose context on navigation', async ({ page, server, toImpl, browserName, mode, isElectron }) => { it.skip(mode !== 'default'); + it.skip(isElectron); await page.goto(server.PREFIX + '/frames/one-frame.html'); expect(page.frames().length).toBe(2); @@ -52,8 +53,9 @@ it('should dispose context on navigation', async ({ page, server, toImpl, browse expectContexts(toImpl(page), 2, browserName); }); -it('should dispose context on cross-origin navigation', async ({ page, server, toImpl, browserName, mode }) => { +it('should dispose context on cross-origin navigation', async ({ page, server, toImpl, browserName, mode, isElectron }) => { it.skip(mode !== 'default'); + it.skip(isElectron); await page.goto(server.PREFIX + '/frames/one-frame.html'); expect(page.frames().length).toBe(2); diff --git a/tests/page/interception.spec.ts b/tests/page/interception.spec.ts index 8896d2c58f..93e638ecb6 100644 --- a/tests/page/interception.spec.ts +++ b/tests/page/interception.spec.ts @@ -33,8 +33,9 @@ it('should work with navigation', async ({ page, server }) => { expect(requests.get('style.css').isNavigationRequest()).toBe(false); }); -it('should intercept after a service worker', async ({ page, server, isAndroid }) => { +it('should intercept after a service worker', async ({ page, server, isAndroid, isElectron }) => { it.skip(isAndroid); + it.skip(isElectron); await page.goto(server.PREFIX + '/serviceworkers/fetchdummy/sw.html'); await page.evaluate(() => window['activationPromise']); diff --git a/tests/page/page-event-request.spec.ts b/tests/page/page-event-request.spec.ts index be741acb34..0858f1a44b 100644 --- a/tests/page/page-event-request.spec.ts +++ b/tests/page/page-event-request.spec.ts @@ -41,8 +41,9 @@ it('should fire for fetches', async ({ page, server }) => { expect(requests.length).toBe(2); }); -it('should report requests and responses handled by service worker', async ({ page, server, isAndroid }) => { +it('should report requests and responses handled by service worker', async ({ page, server, isAndroid, isElectron }) => { it.fixme(isAndroid); + it.fixme(isElectron); await page.goto(server.PREFIX + '/serviceworkers/fetchdummy/sw.html'); await page.evaluate(() => window['activationPromise']); diff --git a/tests/page/page-goto.spec.ts b/tests/page/page-goto.spec.ts index 041d1272c5..f4d7db01cc 100644 --- a/tests/page/page-goto.spec.ts +++ b/tests/page/page-goto.spec.ts @@ -495,7 +495,8 @@ it('should fail when navigating and show the url at the error message', async fu expect(error.message).toContain(url); }); -it('should be able to navigate to a page controlled by service worker', async ({ page, server }) => { +it('should be able to navigate to a page controlled by service worker', async ({ page, server, isElectron }) => { + it.skip(isElectron); await page.goto(server.PREFIX + '/serviceworkers/fetch/sw.html'); await page.evaluate(() => window['activationPromise']); await page.goto(server.PREFIX + '/serviceworkers/fetch/sw.html'); diff --git a/tests/page/page-screenshot.spec.ts b/tests/page/page-screenshot.spec.ts index 266fd64468..71b6347244 100644 --- a/tests/page/page-screenshot.spec.ts +++ b/tests/page/page-screenshot.spec.ts @@ -171,8 +171,9 @@ it.describe('page screenshot', () => { expect(screenshot).toMatchSnapshot('screenshot-canvas.png', { threshold: 0.4 }); }); - it('should capture canvas changes', async ({ page, browserName, isMac }) => { + it('should capture canvas changes', async ({ page, browserName, isMac, isElectron }) => { it.fail(browserName === 'webkit' && isMac, 'https://github.com/microsoft/playwright/issues/8796'); + it.skip(isElectron); await page.goto('data:text/html,'); await page.evaluate(() => { const canvas = document.querySelector('canvas'); diff --git a/tests/playwright-test/web-server.spec.ts b/tests/playwright-test/web-server.spec.ts index 3b8662fc8b..9ffebb5836 100644 --- a/tests/playwright-test/web-server.spec.ts +++ b/tests/playwright-test/web-server.spec.ts @@ -138,7 +138,7 @@ test('should be able to specify the baseURL without the server', async ({ runInl const server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => { res.end('hello'); }); - await new Promise(resolve => server.listen(port, resolve)); + await new Promise(resolve => server.listen(port, resolve)); const result = await runInlineTest({ 'test.spec.ts': ` const { test } = pwt; @@ -167,7 +167,7 @@ test('should be able to use an existing server when reuseExistingServer:true ', const server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => { res.end('hello'); }); - await new Promise(resolve => server.listen(port, resolve)); + await new Promise(resolve => server.listen(port, resolve)); const result = await runInlineTest({ 'test.spec.ts': ` const { test } = pwt; @@ -200,7 +200,7 @@ test('should throw when a server is already running on the given port and strict const server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => { res.end('hello'); }); - await new Promise(resolve => server.listen(port, resolve)); + await new Promise(resolve => server.listen(port, resolve)); const result = await runInlineTest({ 'test.spec.ts': ` const { test } = pwt; @@ -232,7 +232,7 @@ for (const host of ['localhost', '127.0.0.1', '0.0.0.0']) { const server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => { res.end('hello'); }); - await new Promise(resolve => server.listen(port, host, resolve)); + await new Promise(resolve => server.listen(port, host, resolve)); try { const result = await runInlineTest({ 'test.spec.ts': ` diff --git a/tests/port-forwarding-server.spec.ts b/tests/port-forwarding-server.spec.ts index b51195e10a..dcd87cf79a 100644 --- a/tests/port-forwarding-server.spec.ts +++ b/tests/port-forwarding-server.spec.ts @@ -86,7 +86,7 @@ async function startTestServer() { const server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => { res.end('from-retargeted-server'); }); - await new Promise(resolve => server.listen(0, resolve)); + await new Promise(resolve => server.listen(0, resolve)); return { testServerPort: (server.address() as net.AddressInfo).port, stopTestServer: () => server.close() diff --git a/tests/proxy.spec.ts b/tests/proxy.spec.ts index 6b2d0d1fae..23293598e9 100644 --- a/tests/proxy.spec.ts +++ b/tests/proxy.spec.ts @@ -186,7 +186,7 @@ it('should use proxy with emulated user agent', async ({ browserType, browserOpt socket.end(); }); }); - await new Promise(f => server.listen(0, f)); + await new Promise(f => server.listen(0, f)); const browser = await browserType.launch({ ...browserOptions, @@ -221,7 +221,7 @@ async function setupSocksForwardingServer(port: number, forwardPort: number){ dstSock.connect(forwardPort, '127.0.0.1'); } }); - await new Promise(resolve => socksServer.listen(port, 'localhost', resolve)); + await new Promise(resolve => socksServer.listen(port, 'localhost', resolve)); socksServer.useAuth(socks.auth.None()); return { closeProxyServer: () => socksServer.close(),