diff --git a/src/rpc/client/browserContext.ts b/src/rpc/client/browserContext.ts index 80d1336252..d8e6e087fa 100644 --- a/src/rpc/client/browserContext.ts +++ b/src/rpc/client/browserContext.ts @@ -204,8 +204,8 @@ export class BrowserContext extends ChannelOwner { - const timeout = this._timeoutSettings.timeout(optionsOrPredicate instanceof Function ? {} : optionsOrPredicate); - const predicate = optionsOrPredicate instanceof Function ? optionsOrPredicate : optionsOrPredicate.predicate; + const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate); + const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate; const waiter = new Waiter(); waiter.rejectOnTimeout(timeout, new TimeoutError(`Timeout while waiting for event "${event}"`)); if (event !== Events.BrowserContext.Close) diff --git a/src/rpc/client/electron.ts b/src/rpc/client/electron.ts index 8e34aa7ed2..541e84b316 100644 --- a/src/rpc/client/electron.ts +++ b/src/rpc/client/electron.ts @@ -93,8 +93,8 @@ export class ElectronApplication extends ChannelOwner { - const timeout = this._timeoutSettings.timeout(optionsOrPredicate instanceof Function ? {} : optionsOrPredicate); - const predicate = optionsOrPredicate instanceof Function ? optionsOrPredicate : optionsOrPredicate.predicate; + const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate); + const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate; const waiter = new Waiter(); waiter.rejectOnTimeout(timeout, new TimeoutError(`Timeout while waiting for event "${event}"`)); if (event !== ElectronEvents.ElectronApplication.Close) diff --git a/src/rpc/client/page.ts b/src/rpc/client/page.ts index 98c1b7d8cd..e49d7e4d6f 100644 --- a/src/rpc/client/page.ts +++ b/src/rpc/client/page.ts @@ -332,8 +332,8 @@ export class Page extends ChannelOwner { } async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise { - const timeout = this._timeoutSettings.timeout(optionsOrPredicate instanceof Function ? {} : optionsOrPredicate); - const predicate = optionsOrPredicate instanceof Function ? optionsOrPredicate : optionsOrPredicate.predicate; + const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate); + const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate; const waiter = new Waiter(); waiter.rejectOnTimeout(timeout, new TimeoutError(`Timeout while waiting for event "${event}"`)); if (event !== Events.Page.Crash) diff --git a/src/rpc/client/playwright.ts b/src/rpc/client/playwright.ts index d22de2d1b6..98f5914b42 100644 --- a/src/rpc/client/playwright.ts +++ b/src/rpc/client/playwright.ts @@ -20,13 +20,15 @@ import { BrowserType } from './browserType'; import { ChannelOwner } from './channelOwner'; import { Selectors } from './selectors'; import { Electron } from './electron'; +import { TimeoutError } from '../../errors'; export class Playwright extends ChannelOwner { - chromium: BrowserType; - firefox: BrowserType; - webkit: BrowserType; - devices: types.Devices; - selectors: Selectors; + readonly chromium: BrowserType; + readonly firefox: BrowserType; + readonly webkit: BrowserType; + readonly devices: types.Devices; + readonly selectors: Selectors; + readonly errors: { TimeoutError: typeof TimeoutError }; constructor(parent: ChannelOwner, type: string, guid: string, initializer: PlaywrightInitializer) { super(parent, type, guid, initializer); @@ -39,5 +41,6 @@ export class Playwright extends ChannelOwner window.result)).toBe(1); }); - it.skip(USES_HOOKS).fail(true)('should retarget when element is recycled during hit testing', async ({page, server}) => { + it.fail(true)('should retarget when element is recycled during hit testing', async ({page, server}) => { await page.goto(server.PREFIX + '/react.html'); await page.evaluate(() => { renderComponent(e('div', {}, [e(MyButton, { name: 'button1' }), e(MyButton, { name: 'button2' })] )); @@ -760,7 +760,7 @@ describe('Page.click', function() { expect(await page.evaluate(() => window.button1)).toBe(true); expect(await page.evaluate(() => window.button2)).toBe(undefined); }); - it.skip(USES_HOOKS).fail(true)('should report that selector does not match anymore', async ({page, server}) => { + it.fail(true)('should report that selector does not match anymore', async ({page, server}) => { await page.goto(server.PREFIX + '/react.html'); await page.evaluate(() => { renderComponent(e('div', {}, [e(MyButton, { name: 'button1' }), e(MyButton, { name: 'button2' })] )); @@ -778,7 +778,7 @@ describe('Page.click', function() { expect(error.message).toContain('page.dblclick: Timeout 3000ms exceeded.'); expect(error.message).toContain('element does not match the selector anymore'); }); - it.skip(USES_HOOKS).fail(true)('should retarget when element is recycled before enabled check', async ({page, server}) => { + it.fail(true)('should retarget when element is recycled before enabled check', async ({page, server}) => { await page.goto(server.PREFIX + '/react.html'); await page.evaluate(() => { renderComponent(e('div', {}, [e(MyButton, { name: 'button1' }), e(MyButton, { name: 'button2', disabled: true })] )); @@ -792,7 +792,7 @@ describe('Page.click', function() { expect(await page.evaluate(() => window.button1)).toBe(true); expect(await page.evaluate(() => window.button2)).toBe(undefined); }); - it.skip(USES_HOOKS).fail(true)('should not retarget the handle when element is recycled', async ({page, server}) => { + it.fail(true)('should not retarget the handle when element is recycled', async ({page, server}) => { await page.goto(server.PREFIX + '/react.html'); await page.evaluate(() => { renderComponent(e('div', {}, [e(MyButton, { name: 'button1' }), e(MyButton, { name: 'button2', disabled: true })] )); diff --git a/test/dialog.spec.js b/test/dialog.jest.js similarity index 97% rename from test/dialog.spec.js rename to test/dialog.jest.js index dc50793a62..e75f39926e 100644 --- a/test/dialog.spec.js +++ b/test/dialog.jest.js @@ -15,7 +15,7 @@ * limitations under the License. */ -const {FFOX, CHROMIUM, WEBKIT, CHANNEL} = require('./utils').testOptions(browserType); +const {FFOX, CHROMIUM, WEBKIT, CHANNEL} = testOptions; describe('Page.Events.Dialog', function() { it('should fire', async({page, server}) => { diff --git a/test/dispatchevent.spec.js b/test/dispatchevent.jest.js similarity index 98% rename from test/dispatchevent.spec.js rename to test/dispatchevent.jest.js index d62ee21c8c..67be46e7c0 100644 --- a/test/dispatchevent.spec.js +++ b/test/dispatchevent.jest.js @@ -15,7 +15,7 @@ */ const utils = require('./utils'); -const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS} = utils.testOptions(browserType); +const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS} = testOptions; describe('Page.dispatchEvent(click)', function() { it('should dispatch click event', async({page, server}) => { diff --git a/test/download.spec.js b/test/download.jest.js similarity index 96% rename from test/download.spec.js rename to test/download.jest.js index 92d9f27618..5c0a1969dd 100644 --- a/test/download.spec.js +++ b/test/download.jest.js @@ -16,16 +16,16 @@ const fs = require('fs'); const path = require('path'); -const {FFOX, CHROMIUM, WEBKIT, MAC, WIN} = require('./utils').testOptions(browserType); +const {FFOX, CHROMIUM, WEBKIT, HEADLESS} = testOptions; describe('Download', function() { - beforeEach(async(state) => { - state.server.setRoute('/download', (req, res) => { + beforeEach(async ({server}) => { + server.setRoute('/download', (req, res) => { res.setHeader('Content-Type', 'application/octet-stream'); res.setHeader('Content-Disposition', 'attachment'); res.end(`Hello world`); }); - state.server.setRoute('/downloadWithFilename', (req, res) => { + server.setRoute('/downloadWithFilename', (req, res) => { res.setHeader('Content-Type', 'application/octet-stream'); res.setHeader('Content-Disposition', 'attachment; filename=file.txt'); res.end(`Hello world`); @@ -103,7 +103,7 @@ describe('Download', function() { expect(fs.readFileSync(path).toString()).toBe('Hello world'); await page.close(); }) - it.skip(FFOX).fail(WEBKIT)('should report alt-click downloads', async({browser, server}) => { + it.fail(FFOX || WEBKIT)('should report alt-click downloads', async({browser, server}) => { // Firefox does not download on alt-click by default. // Our WebKit embedder does not download on alt-click, although Safari does. server.setRoute('/download', (req, res) => { diff --git a/test/elementhandle.spec.js b/test/elementhandle.jest.js similarity index 99% rename from test/elementhandle.spec.js rename to test/elementhandle.jest.js index f9e563f59e..2e375b2247 100644 --- a/test/elementhandle.spec.js +++ b/test/elementhandle.jest.js @@ -16,7 +16,7 @@ */ const utils = require('./utils'); -const {FFOX, CHROMIUM, WEBKIT, USES_HOOKS} = require('./utils').testOptions(browserType); +const {FFOX, HEADLESS} = testOptions; describe('ElementHandle.boundingBox', function() { it.fail(FFOX && !HEADLESS)('should work', async({page, server}) => { diff --git a/test/emulation.spec.js b/test/emulation.jest.js similarity index 99% rename from test/emulation.spec.js rename to test/emulation.jest.js index bdd87b916d..30eb2f22db 100644 --- a/test/emulation.spec.js +++ b/test/emulation.jest.js @@ -16,7 +16,7 @@ */ const utils = require('./utils'); -const {FFOX, CHROMIUM, WEBKIT, LINUX} = utils.testOptions(browserType); +const {FFOX, HEADLESS} = testOptions; describe('BrowserContext({viewport})', function() { it('should get the proper default viewport size', async({page, server}) => { @@ -567,7 +567,7 @@ describe('focus', function() { ]); expect(active).toEqual(['INPUT', 'TEXTAREA']); }); - it.skip(FFOX && !HEADLESS)('should not affect screenshots', async({page, server, golden}) => { + it.skip(FFOX && !HEADLESS)('should not affect screenshots', async({page, server}) => { // Firefox headful produces a different image. const page2 = await page.context().newPage(); await Promise.all([ @@ -584,8 +584,8 @@ describe('focus', function() { page.screenshot(), page2.screenshot(), ]); - expect(screenshots[0]).toBeGolden(golden('screenshot-sanity.png')); - expect(screenshots[1]).toBeGolden(golden('grid-cell-0.png')); + expect(screenshots[0]).toMatchImageSnapshot('screenshot-sanity'); + expect(screenshots[1]).toMatchImageSnapshot('grid-cell-0'); }); it('should change focused iframe', async({page, server}) => { await page.goto(server.EMPTY_PAGE); diff --git a/test/focus.spec.js b/test/focus.jest.js similarity index 96% rename from test/focus.spec.js rename to test/focus.jest.js index 2333d79092..e486707eaa 100644 --- a/test/focus.spec.js +++ b/test/focus.jest.js @@ -14,7 +14,7 @@ * limitations under the License. */ -const {FFOX, CHROMIUM, LINUX, WEBKIT} = require('./utils').testOptions(browserType); +const {FFOX, CHROMIUM, LINUX, WEBKIT} = testOptions; describe('Page.focus', function() { it('should work', async function({page, server}) { diff --git a/test/frame.spec.js b/test/frame.jest.js similarity index 98% rename from test/frame.spec.js rename to test/frame.jest.js index fc0b432c34..6c2821d878 100644 --- a/test/frame.spec.js +++ b/test/frame.jest.js @@ -16,7 +16,7 @@ */ const utils = require('./utils'); -const {FFOX, CHROMIUM, WEBKIT} = utils.testOptions(browserType); +const {FFOX, CHROMIUM, WEBKIT} = testOptions; describe('Frame.evaluateHandle', function() { it('should work', async({page, server}) => { @@ -101,7 +101,7 @@ describe('Frame.evaluate', function() { // Main world should work. expect(await page.frames()[1].evaluate(() => window.location.href)).toBe('about:blank'); // Utility world should work. - expect(await page.frames()[1].$('div')).toBeTruthy(null); + expect(await page.frames()[1].$('div')).toBeTruthy(); }); it.fail(CHROMIUM)('should work in iframes that interrupted initial javascript url navigation', async({page, server}) => { // Chromium does not report isolated world for the iframe. @@ -117,7 +117,7 @@ describe('Frame.evaluate', function() { // Main world should work. expect(await page.frames()[1].evaluate(() => window.top.location.href)).toBe(server.EMPTY_PAGE); // Utility world should work. - expect(await page.frames()[1].$('div')).toBeTruthy(null); + expect(await page.frames()[1].$('div')).toBeTruthy(); }); }); diff --git a/test/golden-chromium/grid-cell-0-snap.png b/test/golden-chromium/grid-cell-0-snap.png new file mode 100644 index 0000000000..ff282e989b Binary files /dev/null and b/test/golden-chromium/grid-cell-0-snap.png differ diff --git a/test/golden-chromium/screenshot-sanity-snap.png b/test/golden-chromium/screenshot-sanity-snap.png new file mode 100644 index 0000000000..ecab61fe17 Binary files /dev/null and b/test/golden-chromium/screenshot-sanity-snap.png differ diff --git a/test/golden-firefox/grid-cell-0-snap.png b/test/golden-firefox/grid-cell-0-snap.png new file mode 100644 index 0000000000..4677bdbc4f Binary files /dev/null and b/test/golden-firefox/grid-cell-0-snap.png differ diff --git a/test/golden-firefox/screenshot-sanity-snap.png b/test/golden-firefox/screenshot-sanity-snap.png new file mode 100644 index 0000000000..ecab61fe17 Binary files /dev/null and b/test/golden-firefox/screenshot-sanity-snap.png differ diff --git a/test/golden-webkit/grid-cell-0-snap.png b/test/golden-webkit/grid-cell-0-snap.png new file mode 100644 index 0000000000..5ae546557b Binary files /dev/null and b/test/golden-webkit/grid-cell-0-snap.png differ diff --git a/test/golden-webkit/screenshot-sanity-snap.png b/test/golden-webkit/screenshot-sanity-snap.png new file mode 100644 index 0000000000..ecab61fe17 Binary files /dev/null and b/test/golden-webkit/screenshot-sanity-snap.png differ diff --git a/test/jest/fixtures.js b/test/jest/fixtures.js index 1014e29598..b80ce5554c 100644 --- a/test/jest/fixtures.js +++ b/test/jest/fixtures.js @@ -26,7 +26,6 @@ const { PlaywrightDispatcher } = require('../../lib/rpc/server/playwrightDispatc const { setUseApiName } = require('../../lib/progress'); module.exports = function registerFixtures(global) { - global.registerWorkerFixture('http_server', async ({}, test) => { const assetsPath = path.join(__dirname, '..', 'assets'); const cachedPath = path.join(__dirname, '..', 'assets', 'cached'); diff --git a/test/jest/playwrightEnvironment.js b/test/jest/playwrightEnvironment.js index a0052be227..1520e58513 100644 --- a/test/jest/playwrightEnvironment.js +++ b/test/jest/playwrightEnvironment.js @@ -16,10 +16,13 @@ const NodeEnvironment = require('jest-environment-node'); const registerFixtures = require('./fixtures'); +const { toMatchImageSnapshot: jestImageSnapshot } = require('jest-image-snapshot'); const os = require('os'); - +const path = require('path'); const platform = os.platform(); +const browserName = process.env.BROWSER || 'chromium'; + class PlaywrightEnvironment extends NodeEnvironment { constructor(config, context) { super(config, context); @@ -28,9 +31,9 @@ class PlaywrightEnvironment extends NodeEnvironment { testOptions.MAC = platform === 'darwin'; testOptions.LINUX = platform === 'linux'; testOptions.WIN = platform === 'win32'; - testOptions.CHROMIUM = process.env.BROWSER === 'chromium' || !process.env.BROWSER; - testOptions.FFOX = process.env.BROWSER === 'firefox'; - testOptions.WEBKIT = process.env.BROWSER === 'webkit'; + testOptions.CHROMIUM = browserName === 'chromium'; + testOptions.FFOX = browserName === 'firefox'; + testOptions.WEBKIT = browserName === 'webkit'; testOptions.USES_HOOKS = process.env.PWCHANNEL === 'wire'; testOptions.CHANNEL = !!process.env.PWCHANNEL; testOptions.HEADLESS = !!valueFromEnv('HEADLESS', true); @@ -60,6 +63,12 @@ class PlaywrightEnvironment extends NodeEnvironment { async handleTestEvent(event, state) { if (event.name === 'setup') { + const beforeEach = this.global.beforeEach; + this.global.beforeEach = fn => { + return beforeEach(async () => { + return await this.fixturePool.resolveParametersAndRun(fn); + }); + } const describeSkip = this.global.describe.skip; this.global.describe.skip = (...args) => { if (args.length = 1) @@ -76,6 +85,15 @@ class PlaywrightEnvironment extends NodeEnvironment { }; this.global.it.fail = this.global.it.skip; this.global.it.slow = () => this.global.it; + + function toMatchImageSnapshot(received, fileName) { + return jestImageSnapshot.call(this, received, { + customDiffConfig: { threshold: 0.2 }, + customSnapshotsDir: path.join(__dirname, '..', `golden-${browserName}`), + customSnapshotIdentifier: fileName + }); + }; + this.global.expect.extend({ toMatchImageSnapshot }); } if (event.name === 'test_start') { const fn = event.test.fn; diff --git a/test/test.config.js b/test/test.config.js index d7a860b82f..3a76858f63 100644 --- a/test/test.config.js +++ b/test/test.config.js @@ -71,13 +71,6 @@ module.exports = { specs: [ { files: [ - './dialog.spec.js', - './dispatchevent.spec.js', - './download.spec.js', - './elementhandle.spec.js', - './emulation.spec.js', - './frame.spec.js', - './focus.spec.js', './input.spec.js', './jshandle.spec.js', './keyboard.spec.ts',