test: remove output and golden directory notions (#3456)
@ -16,6 +16,7 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
import childProcess from 'child_process';
|
||||
import { LaunchOptions, BrowserType, Browser, BrowserContext, Page, BrowserServer } from '../index';
|
||||
import { TestServer } from '../utils/testserver/';
|
||||
@ -24,6 +25,9 @@ import { Transport } from '../lib/rpc/transport';
|
||||
import { setUnderTest } from '../lib/helper';
|
||||
import { installCoverageHooks } from './runner/coverage';
|
||||
import { valueFromEnv } from './runner/utils';
|
||||
import { registerFixture, registerWorkerFixture} from './runner/fixtures';
|
||||
|
||||
import {mkdtempAsync, removeFolderAsync} from './utils';
|
||||
|
||||
setUnderTest(); // Note: we must call setUnderTest before requiring Playwright
|
||||
|
||||
@ -31,13 +35,14 @@ const browserName = process.env.BROWSER || 'chromium';
|
||||
|
||||
declare global {
|
||||
interface WorkerState {
|
||||
asset: (path: string) => string;
|
||||
parallelIndex: number;
|
||||
http_server: {server: TestServer, httpsServer: TestServer};
|
||||
defaultBrowserOptions: LaunchOptions;
|
||||
golden: (path: string) => string;
|
||||
playwright: typeof import('../index');
|
||||
browserType: BrowserType<Browser>;
|
||||
browser: Browser;
|
||||
outputDir: string;
|
||||
tmpDir: string;
|
||||
}
|
||||
interface FixtureState {
|
||||
toImpl: (rpcObject: any) => any;
|
||||
@ -53,7 +58,7 @@ registerWorkerFixture('parallelIndex', async ({}, test) => {
|
||||
await test(parseInt(process.env.JEST_WORKER_ID, 10) - 1);
|
||||
});
|
||||
|
||||
registerWorkerFixture('http_server', async ({parallelIndex}, test) => {
|
||||
registerWorkerFixture('httpService', async ({parallelIndex}, test) => {
|
||||
const assetsPath = path.join(__dirname, 'assets');
|
||||
const cachedPath = path.join(__dirname, 'assets', 'cached');
|
||||
|
||||
@ -158,21 +163,30 @@ registerFixture('page', async ({context}, test) => {
|
||||
await test(page);
|
||||
});
|
||||
|
||||
registerFixture('server', async ({http_server}, test) => {
|
||||
http_server.server.reset();
|
||||
await test(http_server.server);
|
||||
registerFixture('server', async ({httpService}, test) => {
|
||||
httpService.server.reset();
|
||||
await test(httpService.server);
|
||||
});
|
||||
|
||||
registerFixture('httpsServer', async ({http_server}, test) => {
|
||||
http_server.httpsServer.reset();
|
||||
await test(http_server.httpsServer);
|
||||
registerFixture('browserName', async ({}, test) => {
|
||||
await test(browserName);
|
||||
});
|
||||
|
||||
registerWorkerFixture('outputDir', async ({}, test) => {
|
||||
const outputDir = path.join(__dirname, 'output-' + browserName);
|
||||
try {
|
||||
await fs.promises.mkdir(outputDir, { recursive: true });
|
||||
} catch (e) {
|
||||
}
|
||||
await test(outputDir);
|
||||
registerFixture('httpsServer', async ({httpService}, test) => {
|
||||
httpService.httpsServer.reset();
|
||||
await test(httpService.httpsServer);
|
||||
});
|
||||
|
||||
registerFixture('tmpDir', async ({}, test) => {
|
||||
const tmpDir = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-test-'));
|
||||
await test(tmpDir);
|
||||
await removeFolderAsync(tmpDir);
|
||||
});
|
||||
|
||||
registerWorkerFixture('asset', async ({}, test) => {
|
||||
await test(p => path.join(__dirname, `assets`, p));
|
||||
});
|
||||
|
||||
registerWorkerFixture('golden', async ({browserName}, test) => {
|
||||
await test(p => path.join(__dirname, `golden-${browserName}`, p));
|
||||
});
|
||||
|
@ -18,7 +18,7 @@ import './base.fixture';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
|
||||
const {FFOX, CHROMIUM, WEBKIT, WIN, LINUX, ASSETS_DIR} = testOptions;
|
||||
const {FFOX, CHROMIUM, WEBKIT, WIN, LINUX} = testOptions;
|
||||
|
||||
it.fail(WEBKIT && WIN)('Web Assembly should work', async function({page, server}) {
|
||||
await page.goto(server.PREFIX + '/wasm/table2.html');
|
||||
@ -51,14 +51,14 @@ it('should respect CSP', async({page, server}) => {
|
||||
expect(await page.evaluate(() => window['testStatus'])).toBe('SUCCESS');
|
||||
});
|
||||
|
||||
it.fail(WEBKIT && (WIN || LINUX))('should play video', async({page}) => {
|
||||
it.fail(WEBKIT && (WIN || LINUX))('should play video', async({page, asset}) => {
|
||||
// TODO: the test passes on Windows locally but fails on GitHub Action bot,
|
||||
// apparently due to a Media Pack issue in the Windows Server.
|
||||
// Also the test is very flaky on Linux WebKit.
|
||||
//
|
||||
// Safari only plays mp4 so we test WebKit with an .mp4 clip.
|
||||
const fileName = WEBKIT ? 'video_mp4.html' : 'video.html';
|
||||
const absolutePath = path.join(ASSETS_DIR, fileName);
|
||||
const absolutePath = asset(fileName);
|
||||
// Our test server doesn't support range requests required to play on Mac,
|
||||
// so we load the page using a file url.
|
||||
await page.goto(url.pathToFileURL(absolutePath).href);
|
||||
|
@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import '../base.fixture';
|
||||
import { registerFixture } from '../runner/fixtures';
|
||||
import { Page, Browser, BrowserContext } from '../..';
|
||||
|
||||
const {FFOX, CHROMIUM, WEBKIT} = testOptions;
|
||||
@ -188,14 +189,14 @@ it.skip(!CHROMIUM)('should respect route', async({sppBrowser, sppPage, server})
|
||||
expect(intercepted).toBe(true);
|
||||
});
|
||||
|
||||
it.skip(!CHROMIUM)('should take screenshot', async({sppBrowser, sppPage, server}) => {
|
||||
it.skip(!CHROMIUM)('should take screenshot', async({sppBrowser, sppPage, server, golden}) => {
|
||||
const browser = sppBrowser;
|
||||
const page = sppPage;
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||
expect(page.frames().length).toBe(2);
|
||||
expect(await countOOPIFs(browser)).toBe(1);
|
||||
expect(await page.screenshot()).toBeGolden('screenshot-oopif.png');
|
||||
expect(await page.screenshot()).toMatchImage(golden('screenshot-oopif.png'));
|
||||
});
|
||||
|
||||
it.skip(!CHROMIUM)('should load oopif iframes with subresources and request interception', async function({sppBrowser, sppPage, server, context}) {
|
||||
|
@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import '../base.fixture';
|
||||
import { registerFixture } from '../runner/fixtures';
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
@ -24,8 +25,8 @@ declare global {
|
||||
outputFile: string;
|
||||
}
|
||||
}
|
||||
registerFixture('outputFile', async ({outputDir, parallelIndex}, test) => {
|
||||
const outputFile = path.join(outputDir, `trace-${parallelIndex}.json`);
|
||||
registerFixture('outputFile', async ({tmpDir}, test) => {
|
||||
const outputFile = path.join(tmpDir, `trace.json`);
|
||||
await test(outputFile);
|
||||
if (fs.existsSync(outputFile))
|
||||
fs.unlinkSync(outputFile);
|
||||
|
@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import './base.fixture';
|
||||
import { registerFixture } from './runner/fixtures';
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
@ -18,22 +18,9 @@ import './base.fixture';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import util from 'util';
|
||||
import os from 'os';
|
||||
import {mkdtempAsync, removeFolderAsync} from './utils';
|
||||
|
||||
const {FFOX, CHROMIUM, WEBKIT, HEADLESS} = testOptions;
|
||||
|
||||
declare global {
|
||||
interface FixtureState {
|
||||
persistentDirectory: string;
|
||||
}
|
||||
}
|
||||
registerFixture('persistentDirectory', async ({}, test) => {
|
||||
const persistentDirectory = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-test-'));
|
||||
await test(persistentDirectory);
|
||||
await removeFolderAsync(persistentDirectory);
|
||||
});
|
||||
|
||||
beforeEach(async ({server}) => {
|
||||
server.setRoute('/download', (req, res) => {
|
||||
res.setHeader('Content-Type', 'application/octet-stream');
|
||||
@ -74,28 +61,28 @@ it('should report downloads with acceptDownloads: true', async({browser, server}
|
||||
await page.close();
|
||||
});
|
||||
|
||||
it('should save to user-specified path', async({persistentDirectory, browser, server}) => {
|
||||
it('should save to user-specified path', async({tmpDir, browser, server}) => {
|
||||
const page = await browser.newPage({ acceptDownloads: true });
|
||||
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
|
||||
const [ download ] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.click('a')
|
||||
]);
|
||||
const userPath = path.join(persistentDirectory, "download.txt");
|
||||
const userPath = path.join(tmpDir, "download.txt");
|
||||
await download.saveAs(userPath);
|
||||
expect(fs.existsSync(userPath)).toBeTruthy();
|
||||
expect(fs.readFileSync(userPath).toString()).toBe('Hello world');
|
||||
await page.close();
|
||||
});
|
||||
|
||||
it('should save to user-specified path without updating original path', async({persistentDirectory, browser, server}) => {
|
||||
it('should save to user-specified path without updating original path', async({tmpDir, browser, server}) => {
|
||||
const page = await browser.newPage({ acceptDownloads: true });
|
||||
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
|
||||
const [ download ] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.click('a')
|
||||
]);
|
||||
const userPath = path.join(persistentDirectory, "download.txt");
|
||||
const userPath = path.join(tmpDir, "download.txt");
|
||||
await download.saveAs(userPath);
|
||||
expect(fs.existsSync(userPath)).toBeTruthy();
|
||||
expect(fs.readFileSync(userPath).toString()).toBe('Hello world');
|
||||
@ -106,77 +93,77 @@ it('should save to user-specified path without updating original path', async({p
|
||||
await page.close();
|
||||
});
|
||||
|
||||
it('should save to two different paths with multiple saveAs calls', async({persistentDirectory, browser, server}) => {
|
||||
it('should save to two different paths with multiple saveAs calls', async({tmpDir, browser, server}) => {
|
||||
const page = await browser.newPage({ acceptDownloads: true });
|
||||
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
|
||||
const [ download ] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.click('a')
|
||||
]);
|
||||
const userPath = path.join(persistentDirectory, "download.txt");
|
||||
const userPath = path.join(tmpDir, "download.txt");
|
||||
await download.saveAs(userPath);
|
||||
expect(fs.existsSync(userPath)).toBeTruthy();
|
||||
expect(fs.readFileSync(userPath).toString()).toBe('Hello world');
|
||||
|
||||
const anotherUserPath = path.join(persistentDirectory, "download (2).txt");
|
||||
const anotherUserPath = path.join(tmpDir, "download (2).txt");
|
||||
await download.saveAs(anotherUserPath);
|
||||
expect(fs.existsSync(anotherUserPath)).toBeTruthy();
|
||||
expect(fs.readFileSync(anotherUserPath).toString()).toBe('Hello world');
|
||||
await page.close();
|
||||
});
|
||||
|
||||
it('should save to overwritten filepath', async({persistentDirectory, browser, server}) => {
|
||||
it('should save to overwritten filepath', async({tmpDir, browser, server}) => {
|
||||
const page = await browser.newPage({ acceptDownloads: true });
|
||||
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
|
||||
const [ download ] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.click('a')
|
||||
]);
|
||||
const userPath = path.join(persistentDirectory, "download.txt");
|
||||
const userPath = path.join(tmpDir, "download.txt");
|
||||
await download.saveAs(userPath);
|
||||
expect((await util.promisify(fs.readdir)(persistentDirectory)).length).toBe(1);
|
||||
expect((await util.promisify(fs.readdir)(tmpDir)).length).toBe(1);
|
||||
await download.saveAs(userPath);
|
||||
expect((await util.promisify(fs.readdir)(persistentDirectory)).length).toBe(1);
|
||||
expect((await util.promisify(fs.readdir)(tmpDir)).length).toBe(1);
|
||||
expect(fs.existsSync(userPath)).toBeTruthy();
|
||||
expect(fs.readFileSync(userPath).toString()).toBe('Hello world');
|
||||
await page.close();
|
||||
});
|
||||
|
||||
it('should create subdirectories when saving to non-existent user-specified path', async({persistentDirectory, browser, server}) => {
|
||||
it('should create subdirectories when saving to non-existent user-specified path', async({tmpDir, browser, server}) => {
|
||||
const page = await browser.newPage({ acceptDownloads: true });
|
||||
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
|
||||
const [ download ] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.click('a')
|
||||
]);
|
||||
const nestedPath = path.join(persistentDirectory, "these", "are", "directories", "download.txt");
|
||||
const nestedPath = path.join(tmpDir, "these", "are", "directories", "download.txt");
|
||||
await download.saveAs(nestedPath)
|
||||
expect(fs.existsSync(nestedPath)).toBeTruthy();
|
||||
expect(fs.readFileSync(nestedPath).toString()).toBe('Hello world');
|
||||
await page.close();
|
||||
});
|
||||
|
||||
it('should error when saving with downloads disabled', async({persistentDirectory, browser, server}) => {
|
||||
it('should error when saving with downloads disabled', async({tmpDir, browser, server}) => {
|
||||
const page = await browser.newPage({ acceptDownloads: false });
|
||||
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
|
||||
const [ download ] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.click('a')
|
||||
]);
|
||||
const userPath = path.join(persistentDirectory, "download.txt");
|
||||
const userPath = path.join(tmpDir, "download.txt");
|
||||
const { message } = await download.saveAs(userPath).catch(e => e);
|
||||
expect(message).toContain('Pass { acceptDownloads: true } when you are creating your browser context');
|
||||
await page.close();
|
||||
});
|
||||
|
||||
it('should error when saving after deletion', async({persistentDirectory, browser, server}) => {
|
||||
it('should error when saving after deletion', async({tmpDir, browser, server}) => {
|
||||
const page = await browser.newPage({ acceptDownloads: true });
|
||||
await page.setContent(`<a href="${server.PREFIX}/download">download</a>`);
|
||||
const [ download ] = await Promise.all([
|
||||
page.waitForEvent('download'),
|
||||
page.click('a')
|
||||
]);
|
||||
const userPath = path.join(persistentDirectory, "download.txt");
|
||||
const userPath = path.join(tmpDir, "download.txt");
|
||||
await download.delete();
|
||||
const { message } = await download.saveAs(userPath).catch(e => e);
|
||||
expect(message).toContain('Download already deleted. Save before deleting.');
|
||||
|
@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import './base.fixture';
|
||||
import { registerFixture } from './runner/fixtures';
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
@ -1,4 +1,21 @@
|
||||
/**
|
||||
* Copyright Microsoft Corporation. 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 '../base.fixture';
|
||||
import { registerFixture } from '../runner/fixtures';
|
||||
import {ElectronApplication, ElectronLauncher, ElectronPage} from '../../electron-types';
|
||||
import path from 'path';
|
||||
|
||||
|
@ -23,16 +23,16 @@ import {PNG} from 'pngjs';
|
||||
// Firefox headful produces a different image.
|
||||
const ffheadful = FFOX && !HEADLESS;
|
||||
|
||||
it.skip(ffheadful)('should work', async({page, server}) => {
|
||||
it.skip(ffheadful)('should work', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.evaluate(() => window.scrollBy(50, 100));
|
||||
const elementHandle = await page.$('.box:nth-of-type(3)');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-bounding-box.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-bounding-box.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should take into account padding and border', async({page}) => {
|
||||
it.skip(ffheadful)('should take into account padding and border', async({page, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.setContent(`
|
||||
<div style="height: 14px">oooo</div>
|
||||
@ -47,10 +47,10 @@ it.skip(ffheadful)('should take into account padding and border', async({page})
|
||||
`);
|
||||
const elementHandle = await page.$('div#d');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-padding-border.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-padding-border.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should capture full element when larger than viewport in parallel', async({page}) => {
|
||||
it.skip(ffheadful)('should capture full element when larger than viewport in parallel', async({page, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
|
||||
await page.setContent(`
|
||||
@ -73,12 +73,12 @@ it.skip(ffheadful)('should capture full element when larger than viewport in par
|
||||
const elementHandles = await page.$$('div.to-screenshot');
|
||||
const promises = elementHandles.map(handle => handle.screenshot());
|
||||
const screenshots = await Promise.all(promises);
|
||||
expect(screenshots[2]).toBeGolden('screenshot-element-larger-than-viewport.png');
|
||||
expect(screenshots[2]).toMatchImage(golden('screenshot-element-larger-than-viewport.png'));
|
||||
|
||||
await utils.verifyViewport(page, 500, 500);
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should capture full element when larger than viewport', async({page}) => {
|
||||
it.skip(ffheadful)('should capture full element when larger than viewport', async({page, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
|
||||
await page.setContent(`
|
||||
@ -100,12 +100,12 @@ it.skip(ffheadful)('should capture full element when larger than viewport', asyn
|
||||
`);
|
||||
const elementHandle = await page.$('div.to-screenshot');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-larger-than-viewport.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-larger-than-viewport.png'));
|
||||
|
||||
await utils.verifyViewport(page, 500, 500);
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should scroll element into view', async({page}) => {
|
||||
it.skip(ffheadful)('should scroll element into view', async({page, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.setContent(`
|
||||
<div style="height: 14px">oooo</div>
|
||||
@ -126,10 +126,10 @@ it.skip(ffheadful)('should scroll element into view', async({page}) => {
|
||||
`);
|
||||
const elementHandle = await page.$('div.to-screenshot');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-scrolled-into-view.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-scrolled-into-view.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should scroll 15000px into view', async({page}) => {
|
||||
it.skip(ffheadful)('should scroll 15000px into view', async({page, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.setContent(`
|
||||
<div style="height: 14px">oooo</div>
|
||||
@ -150,10 +150,10 @@ it.skip(ffheadful)('should scroll 15000px into view', async({page}) => {
|
||||
`);
|
||||
const elementHandle = await page.$('div.to-screenshot');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-scrolled-into-view.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-scrolled-into-view.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should work with a rotated element', async({page}) => {
|
||||
it.skip(ffheadful)('should work with a rotated element', async({page, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.setContent(`<div style="position:absolute;
|
||||
top: 100px;
|
||||
@ -164,7 +164,7 @@ it.skip(ffheadful)('should work with a rotated element', async({page}) => {
|
||||
transform: rotateZ(200deg);"> </div>`);
|
||||
const elementHandle = await page.$('div');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-rotate.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-rotate.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should fail to screenshot a detached element', async({page, server}) => {
|
||||
@ -183,7 +183,7 @@ it.skip(ffheadful)('should timeout waiting for visible', async({page, server}) =
|
||||
expect(error.message).toContain('element is not visible');
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should wait for visible', async({page, server}) => {
|
||||
it.skip(ffheadful)('should wait for visible', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.evaluate(() => window.scrollBy(50, 100));
|
||||
@ -199,43 +199,43 @@ it.skip(ffheadful)('should wait for visible', async({page, server}) => {
|
||||
expect(done).toBe(false);
|
||||
await elementHandle.evaluate(e => e.style.visibility = 'visible');
|
||||
const screenshot = await promise;
|
||||
expect(screenshot).toBeGolden('screenshot-element-bounding-box.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-bounding-box.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should work for an element with fractional dimensions', async({page}) => {
|
||||
it.skip(ffheadful)('should work for an element with fractional dimensions', async({page, golden}) => {
|
||||
await page.setContent('<div style="width:48.51px;height:19.8px;border:1px solid black;"></div>');
|
||||
const elementHandle = await page.$('div');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-fractional.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-fractional.png'));
|
||||
});
|
||||
|
||||
it.skip(FFOX)('should work with a mobile viewport', async({browser, server}) => {
|
||||
it.skip(FFOX)('should work with a mobile viewport', async({browser, server, golden}) => {
|
||||
const context = await browser.newContext({viewport: { width: 320, height: 480 }, isMobile: true});
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.evaluate(() => window.scrollBy(50, 100));
|
||||
const elementHandle = await page.$('.box:nth-of-type(3)');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-mobile.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-mobile.png'));
|
||||
await context.close();
|
||||
});
|
||||
|
||||
it.skip(FFOX)('should work with device scale factor', async({browser, server}) => {
|
||||
it.skip(FFOX)('should work with device scale factor', async({browser, server, golden}) => {
|
||||
const context = await browser.newContext({ viewport: { width: 320, height: 480 }, deviceScaleFactor: 2 });
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.evaluate(() => window.scrollBy(50, 100));
|
||||
const elementHandle = await page.$('.box:nth-of-type(3)');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-mobile-dsf.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-mobile-dsf.png'));
|
||||
await context.close();
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should work for an element with an offset', async({page}) => {
|
||||
it.skip(ffheadful)('should work for an element with an offset', async({page, golden}) => {
|
||||
await page.setContent('<div style="position:absolute; top: 10.3px; left: 20.4px;width:50.3px;height:20.2px;border:1px solid black;"></div>');
|
||||
const elementHandle = await page.$('div');
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-fractional-offset.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-fractional-offset.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should take screenshots when default viewport is null', async({server, browser}) => {
|
||||
@ -350,7 +350,7 @@ it.skip(ffheadful || WIRE)('should restore viewport after element screenshot and
|
||||
await context.close();
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should wait for element to stop moving', async({page, server}) => {
|
||||
it.skip(ffheadful)('should wait for element to stop moving', async({page, server, golden}) => {
|
||||
await page.setViewportSize({ width: 500, height: 500 });
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const elementHandle = await page.$('.box:nth-of-type(3)');
|
||||
@ -359,7 +359,7 @@ it.skip(ffheadful)('should wait for element to stop moving', async({page, server
|
||||
return new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f)));
|
||||
});
|
||||
const screenshot = await elementHandle.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-element-bounding-box.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-element-bounding-box.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should take screenshot of disabled button', async({page}) => {
|
||||
|
@ -102,7 +102,7 @@ it('should change document.activeElement', async({page, server}) => {
|
||||
expect(active).toEqual(['INPUT', 'TEXTAREA']);
|
||||
});
|
||||
|
||||
it.skip(FFOX && !HEADLESS)('should not affect screenshots', async({page, server}) => {
|
||||
it.skip(FFOX && !HEADLESS)('should not affect screenshots', async({page, server, golden}) => {
|
||||
// Firefox headful produces a different image.
|
||||
const page2 = await page.context().newPage();
|
||||
await Promise.all([
|
||||
@ -119,8 +119,8 @@ it.skip(FFOX && !HEADLESS)('should not affect screenshots', async({page, server}
|
||||
page.screenshot(),
|
||||
page2.screenshot(),
|
||||
]);
|
||||
expect(screenshots[0]).toBeGolden('screenshot-sanity.png');
|
||||
expect(screenshots[1]).toBeGolden('grid-cell-0.png');
|
||||
expect(screenshots[0]).toMatchImage(golden('screenshot-sanity.png'));
|
||||
expect(screenshots[1]).toMatchImage(golden('grid-cell-0.png'));
|
||||
});
|
||||
|
||||
it('should change focused iframe', async({page, server}) => {
|
||||
|
@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import './base.fixture';
|
||||
import { registerFixture } from './runner/fixtures';
|
||||
|
||||
import path from 'path';
|
||||
import {spawn, execSync} from 'child_process';
|
||||
|
@ -19,7 +19,7 @@ import './base.fixture';
|
||||
import utils from './utils';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
const {FFOX, CHROMIUM, WEBKIT, ASSETS_DIR, MAC, WIN} = testOptions;
|
||||
const {FFOX, CHROMIUM, WEBKIT, MAC, WIN} = testOptions;
|
||||
|
||||
it('should navigate subframes', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/frames/one-frame.html');
|
||||
|
Before Width: | Height: | Size: 276 B After Width: | Height: | Size: 301 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 461 B After Width: | Height: | Size: 474 B |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 168 B After Width: | Height: | Size: 181 B |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 168 B After Width: | Height: | Size: 181 B |
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
@ -19,7 +19,7 @@ import './base.fixture';
|
||||
import utils from './utils';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
const {FFOX, CHROMIUM, WEBKIT, ASSETS_DIR, MAC, WIN} = testOptions;
|
||||
const {FFOX, CHROMIUM, WEBKIT, MAC, WIN} = testOptions;
|
||||
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
|
@ -18,7 +18,7 @@ import './base.fixture';
|
||||
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
const {FFOX, CHROMIUM, WEBKIT, ASSETS_DIR, MAC, WIN} = testOptions;
|
||||
const {FFOX, CHROMIUM, WEBKIT, MAC, WIN} = testOptions;
|
||||
|
||||
it('page.goBack should work', async({page, server}) => {
|
||||
expect(await page.goBack()).toBe(null);
|
||||
@ -54,9 +54,9 @@ it('page.goBack should work with HistoryAPI', async({page, server}) => {
|
||||
expect(page.url()).toBe(server.PREFIX + '/first.html');
|
||||
});
|
||||
|
||||
it.fail(WEBKIT && MAC)('page.goBack should work for file urls', async ({page, server}) => {
|
||||
it.fail(WEBKIT && MAC)('page.goBack should work for file urls', async ({page, server, asset}) => {
|
||||
// WebKit embedder fails to go back/forward to the file url.
|
||||
const url1 = url.pathToFileURL(path.join(ASSETS_DIR, 'empty.html')).href;
|
||||
const url1 = url.pathToFileURL(asset('empty.html')).href;
|
||||
const url2 = server.EMPTY_PAGE;
|
||||
await page.goto(url1);
|
||||
await page.setContent(`<a href='${url2}'>url2</a>`);
|
||||
|
@ -21,7 +21,7 @@ import path from 'path';
|
||||
import url from 'url';
|
||||
import { Frame, Page } from '..';
|
||||
import { TestServer } from '../utils/testserver';
|
||||
const {FFOX, CHROMIUM, WEBKIT, ASSETS_DIR, MAC, WIN} = testOptions;
|
||||
const {FFOX, CHROMIUM, WEBKIT, MAC, WIN} = testOptions;
|
||||
|
||||
it('should navigate to empty page with networkidle', async({page, server}) => {
|
||||
const response = await page.goto(server.EMPTY_PAGE, { waitUntil: 'networkidle' });
|
||||
|
@ -17,20 +17,19 @@
|
||||
import './base.fixture';
|
||||
|
||||
import utils from './utils';
|
||||
const {FFOX, CHROMIUM, WEBKIT, WIRE, HEADLESS} = testOptions;
|
||||
import {PNG} from 'pngjs';
|
||||
const {FFOX, WEBKIT, HEADLESS} = testOptions;
|
||||
|
||||
// Firefox headful produces a different image.
|
||||
const ffheadful = FFOX && !HEADLESS;
|
||||
|
||||
it.skip(ffheadful)('should work', async({page, server}) => {
|
||||
it.skip(ffheadful)('should work', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const screenshot = await page.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-sanity.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-sanity.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should clip rect', async({page, server}) => {
|
||||
it.skip(ffheadful)('should clip rect', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const screenshot = await page.screenshot({
|
||||
@ -41,10 +40,10 @@ it.skip(ffheadful)('should clip rect', async({page, server}) => {
|
||||
height: 100
|
||||
}
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-clip-rect.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-clip-rect.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should clip rect with fullPage', async({page, server}) => {
|
||||
it.skip(ffheadful)('should clip rect with fullPage', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.evaluate(() => window.scrollBy(150, 200));
|
||||
@ -57,10 +56,10 @@ it.skip(ffheadful)('should clip rect with fullPage', async({page, server}) => {
|
||||
height: 100,
|
||||
},
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-clip-rect.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-clip-rect.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should clip elements to the viewport', async({page, server}) => {
|
||||
it.skip(ffheadful)('should clip elements to the viewport', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const screenshot = await page.screenshot({
|
||||
@ -71,10 +70,10 @@ it.skip(ffheadful)('should clip elements to the viewport', async({page, server})
|
||||
height: 100
|
||||
}
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-offscreen-clip.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-offscreen-clip.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should throw on clip outside the viewport', async({page, server}) => {
|
||||
it.skip(ffheadful)('should throw on clip outside the viewport', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const screenshotError = await page.screenshot({
|
||||
@ -88,7 +87,7 @@ it.skip(ffheadful)('should throw on clip outside the viewport', async({page, ser
|
||||
expect(screenshotError.message).toContain('Clipped area is either empty or outside the resulting image');
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should run in parallel', async({page, server}) => {
|
||||
it.skip(ffheadful)('should run in parallel', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const promises = [];
|
||||
@ -103,16 +102,16 @@ it.skip(ffheadful)('should run in parallel', async({page, server}) => {
|
||||
}));
|
||||
}
|
||||
const screenshots = await Promise.all(promises);
|
||||
expect(screenshots[1]).toBeGolden('grid-cell-1.png');
|
||||
expect(screenshots[1]).toMatchImage(golden('grid-cell-1.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should take fullPage screenshots', async({page, server}) => {
|
||||
it.skip(ffheadful)('should take fullPage screenshots', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const screenshot = await page.screenshot({
|
||||
fullPage: true
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-grid-fullpage.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-grid-fullpage.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should restore viewport after fullPage screenshot', async({page, server}) => {
|
||||
@ -123,7 +122,7 @@ it.skip(ffheadful)('should restore viewport after fullPage screenshot', async({p
|
||||
await utils.verifyViewport(page, 500, 500);
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should run in parallel in multiple pages', async({page, server, context}) => {
|
||||
it.skip(ffheadful)('should run in parallel in multiple pages', async({server, context, golden}) => {
|
||||
const N = 5;
|
||||
const pages = await Promise.all(Array(N).fill(0).map(async() => {
|
||||
const page = await context.newPage();
|
||||
@ -135,11 +134,11 @@ it.skip(ffheadful)('should run in parallel in multiple pages', async({page, serv
|
||||
promises.push(pages[i].screenshot({ clip: { x: 50 * (i % 2), y: 0, width: 50, height: 50 } }));
|
||||
const screenshots = await Promise.all(promises);
|
||||
for (let i = 0; i < N; ++i)
|
||||
expect(screenshots[i]).toBeGolden(`grid-cell-${i % 2}.png`);
|
||||
expect(screenshots[i]).toMatchImage(golden(`grid-cell-${i % 2}.png`));
|
||||
await Promise.all(pages.map(page => page.close()));
|
||||
});
|
||||
|
||||
it.fail(FFOX)('should allow transparency', async({page}) => {
|
||||
it.fail(FFOX)('should allow transparency', async({page, golden}) => {
|
||||
await page.setViewportSize({ width: 50, height: 150 });
|
||||
await page.setContent(`
|
||||
<style>
|
||||
@ -151,17 +150,17 @@ it.fail(FFOX)('should allow transparency', async({page}) => {
|
||||
<div style="background:transparent"></div>
|
||||
`);
|
||||
const screenshot = await page.screenshot({omitBackground: true});
|
||||
expect(screenshot).toBeGolden('transparent.png');
|
||||
expect(screenshot).toMatchImage(golden('transparent.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should render white background on jpeg file', async({page, server}) => {
|
||||
it.skip(ffheadful)('should render white background on jpeg file', async({page, server, golden}) => {
|
||||
await page.setViewportSize({ width: 100, height: 100 });
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const screenshot = await page.screenshot({omitBackground: true, type: 'jpeg'});
|
||||
expect(screenshot).toBeGolden('white.jpg');
|
||||
expect(screenshot).toMatchImage(golden('white.jpg'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should work with odd clip size on Retina displays', async({page}) => {
|
||||
it.skip(ffheadful)('should work with odd clip size on Retina displays', async({page, golden}) => {
|
||||
const screenshot = await page.screenshot({
|
||||
clip: {
|
||||
x: 0,
|
||||
@ -170,55 +169,55 @@ it.skip(ffheadful)('should work with odd clip size on Retina displays', async({p
|
||||
height: 11,
|
||||
}
|
||||
});
|
||||
expect(screenshot).toBeGolden('screenshot-clip-odd-size.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-clip-odd-size.png'));
|
||||
});
|
||||
|
||||
it.skip(FFOX)('should work with a mobile viewport', async({browser, server}) => {
|
||||
it.skip(FFOX)('should work with a mobile viewport', async({browser, server, golden}) => {
|
||||
const context = await browser.newContext({ viewport: { width: 320, height: 480 }, isMobile: true });
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.PREFIX + '/overflow.html');
|
||||
const screenshot = await page.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-mobile.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-mobile.png'));
|
||||
await context.close();
|
||||
});
|
||||
|
||||
it.skip(FFOX)('should work with a mobile viewport and clip', async({browser, server}) => {
|
||||
it.skip(FFOX)('should work with a mobile viewport and clip', async({browser, server, golden}) => {
|
||||
const context = await browser.newContext({viewport: { width: 320, height: 480 }, isMobile: true});
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.PREFIX + '/overflow.html');
|
||||
const screenshot = await page.screenshot({ clip: { x: 10, y: 10, width: 100, height: 150 } });
|
||||
expect(screenshot).toBeGolden('screenshot-mobile-clip.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-mobile-clip.png'));
|
||||
await context.close();
|
||||
});
|
||||
|
||||
it.skip(FFOX)('should work with a mobile viewport and fullPage', async({browser, server}) => {
|
||||
it.skip(FFOX)('should work with a mobile viewport and fullPage', async({browser, server, golden}) => {
|
||||
const context = await browser.newContext({viewport: { width: 320, height: 480 }, isMobile: true});
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.PREFIX + '/overflow-large.html');
|
||||
const screenshot = await page.screenshot({ fullPage: true });
|
||||
expect(screenshot).toBeGolden('screenshot-mobile-fullpage.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-mobile-fullpage.png'));
|
||||
await context.close();
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should work for canvas', async({page, server}) => {
|
||||
it.skip(ffheadful)('should work for canvas', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/screenshots/canvas.html');
|
||||
const screenshot = await page.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-canvas.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-canvas.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should work for translateZ', async({page, server}) => {
|
||||
it.skip(ffheadful)('should work for translateZ', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/screenshots/translateZ.html');
|
||||
const screenshot = await page.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-translateZ.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-translateZ.png'));
|
||||
});
|
||||
|
||||
it.fail(FFOX || WEBKIT)('should work for webgl', async({page, server}) => {
|
||||
it.fail(FFOX || WEBKIT)('should work for webgl', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 640, height: 480});
|
||||
await page.goto(server.PREFIX + '/screenshots/webgl.html');
|
||||
const screenshot = await page.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-webgl.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-webgl.png'));
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should work while navigating', async({page, server}) => {
|
||||
@ -234,17 +233,17 @@ it.skip(ffheadful)('should work while navigating', async({page, server}) => {
|
||||
}
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should work with device scale factor', async({browser, server}) => {
|
||||
it.skip(ffheadful)('should work with device scale factor', async({browser, server, golden}) => {
|
||||
const context = await browser.newContext({ viewport: { width: 320, height: 480 }, deviceScaleFactor: 2 });
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
const screenshot = await page.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-device-scale-factor.png');
|
||||
expect(screenshot).toMatchImage(golden('screenshot-device-scale-factor.png'));
|
||||
await context.close();
|
||||
});
|
||||
|
||||
it.skip(ffheadful)('should work with iframe in shadow', async({browser, page, server}) => {
|
||||
it.skip(ffheadful)('should work with iframe in shadow', async({page, server, golden}) => {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.goto(server.PREFIX + '/grid-iframe-in-shadow.html');
|
||||
expect(await page.screenshot()).toBeGolden('screenshot-iframe.png');
|
||||
expect(await page.screenshot()).toMatchImage(golden('screenshot-iframe.png'));
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ import utils from './utils';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
import { Route } from '..';
|
||||
const {FFOX, CHROMIUM, WEBKIT, ASSETS_DIR, MAC, WIN} = testOptions;
|
||||
const {FFOX, CHROMIUM, WEBKIT, MAC, WIN} = testOptions;
|
||||
|
||||
it('should pick up ongoing navigation', async({page, server}) => {
|
||||
let response = null;
|
||||
|
@ -21,7 +21,7 @@ import path from 'path';
|
||||
import url from 'url';
|
||||
import { Frame } from '..';
|
||||
|
||||
const {FFOX, CHROMIUM, WEBKIT, ASSETS_DIR, MAC, WIN} = testOptions;
|
||||
const {FFOX, CHROMIUM, WEBKIT, MAC, WIN} = testOptions;
|
||||
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
|
@ -21,8 +21,8 @@ import path from 'path'
|
||||
const {FFOX, CHROMIUM, WEBKIT, HEADLESS} = testOptions;
|
||||
|
||||
// Printing to pdf is currently only supported in headless chromium.
|
||||
it.skip(!(HEADLESS && CHROMIUM))('should be able to save file', async({page, outputDir}) => {
|
||||
const outputFile = path.join(outputDir, 'output.pdf');
|
||||
it.skip(!(HEADLESS && CHROMIUM))('should be able to save file', async({page, tmpDir}) => {
|
||||
const outputFile = path.join(tmpDir, 'output.pdf');
|
||||
await page.pdf({path: outputFile});
|
||||
expect(fs.readFileSync(outputFile).byteLength).toBeGreaterThan(0);
|
||||
fs.unlinkSync(outputFile);
|
||||
|
@ -52,7 +52,7 @@ it('should work with status code 422', async({page, server}) => {
|
||||
expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, page!');
|
||||
});
|
||||
|
||||
it.skip(FFOX && !HEADLESS)('should allow mocking binary responses', async({page, server}) => {
|
||||
it.skip(FFOX && !HEADLESS)('should allow mocking binary responses', async({page, server, golden}) => {
|
||||
// Firefox headful produces a different image.
|
||||
await page.route('**/*', route => {
|
||||
const imageBuffer = fs.readFileSync(path.join(__dirname, 'assets', 'pptr.png'));
|
||||
@ -68,10 +68,10 @@ it.skip(FFOX && !HEADLESS)('should allow mocking binary responses', async({page,
|
||||
return new Promise(fulfill => img.onload = fulfill);
|
||||
}, server.PREFIX);
|
||||
const img = await page.$('img');
|
||||
expect(await img.screenshot()).toBeGolden('mock-binary-response.png');
|
||||
expect(await img.screenshot()).toMatchImage(golden('mock-binary-response.png'));
|
||||
});
|
||||
|
||||
it.skip(FFOX && !HEADLESS)('should allow mocking svg with charset', async({page, server}) => {
|
||||
it.skip(FFOX && !HEADLESS)('should allow mocking svg with charset', async({page, server, golden}) => {
|
||||
// Firefox headful produces a different image.
|
||||
await page.route('**/*', route => {
|
||||
route.fulfill({
|
||||
@ -86,10 +86,10 @@ it.skip(FFOX && !HEADLESS)('should allow mocking svg with charset', async({page,
|
||||
return new Promise((f, r) => { img.onload = f; img.onerror = r; });
|
||||
}, server.PREFIX);
|
||||
const img = await page.$('img');
|
||||
expect(await img.screenshot()).toBeGolden('mock-svg.png');
|
||||
expect(await img.screenshot()).toMatchImage(golden('mock-svg.png'));
|
||||
});
|
||||
|
||||
it('should work with file path', async({page, server}) => {
|
||||
it('should work with file path', async({page, server, golden}) => {
|
||||
await page.route('**/*', route => route.fulfill({ contentType: 'shouldBeIgnored', path: path.join(__dirname, 'assets', 'pptr.png') }));
|
||||
await page.evaluate(PREFIX => {
|
||||
const img = document.createElement('img');
|
||||
@ -98,7 +98,7 @@ it('should work with file path', async({page, server}) => {
|
||||
return new Promise(fulfill => img.onload = fulfill);
|
||||
}, server.PREFIX);
|
||||
const img = await page.$('img');
|
||||
expect(await img.screenshot()).toBeGolden('mock-binary-response.png');
|
||||
expect(await img.screenshot()).toMatchImage(golden('mock-binary-response.png'));
|
||||
});
|
||||
|
||||
it('should stringify intercepted request response headers', async({page, server}) => {
|
||||
|
@ -85,76 +85,53 @@ function compareText(actual, expectedBuffer) {
|
||||
|
||||
/**
|
||||
* @param {?Object} actual
|
||||
* @param {!{goldenPath: string, outputPath: string, goldenName: string}} golden
|
||||
* @param {string} path
|
||||
* @return {!{pass: boolean, message: (undefined|string)}}
|
||||
*/
|
||||
function compare(actual, golden) {
|
||||
const goldenPath = path.normalize(golden.goldenPath);
|
||||
const outputPath = path.normalize(golden.outputPath);
|
||||
const goldenName = golden.goldenName;
|
||||
const expectedPath = path.resolve(goldenPath, goldenName);
|
||||
const actualPath = path.resolve(outputPath, goldenName);
|
||||
|
||||
const messageSuffix = 'Output is saved in "' + path.basename(outputPath + '" directory');
|
||||
|
||||
function compare(actual, expectedPath) {
|
||||
if (!fs.existsSync(expectedPath)) {
|
||||
ensureOutputDir();
|
||||
fs.writeFileSync(actualPath, actual);
|
||||
fs.writeFileSync(expectedPath, actual);
|
||||
return {
|
||||
pass: false,
|
||||
message: goldenName + ' is missing in golden results. ' + messageSuffix
|
||||
message: expectedPath + ' is missing in golden results, writing actual.'
|
||||
};
|
||||
}
|
||||
const expected = fs.readFileSync(expectedPath);
|
||||
const extension = goldenName.substring(goldenName.lastIndexOf('.') + 1);
|
||||
const extension = path.extname(expectedPath).substring(1);
|
||||
const mimeType = extensionToMimeType[extension];
|
||||
const comparator = GoldenComparators[mimeType];
|
||||
if (!comparator) {
|
||||
return {
|
||||
pass: false,
|
||||
message: 'Failed to find comparator with type ' + mimeType + ': ' + goldenName,
|
||||
message: 'Failed to find comparator with type ' + mimeType + ': ' + expectedPath,
|
||||
};
|
||||
}
|
||||
|
||||
const result = comparator(actual, expected, mimeType);
|
||||
if (!result)
|
||||
return { pass: true };
|
||||
ensureOutputDir();
|
||||
|
||||
const actualPath = addSuffix(expectedPath, '-actual');
|
||||
const diffPath = addSuffix(expectedPath, '-diff', result.diffExtension);
|
||||
fs.writeFileSync(actualPath, actual);
|
||||
if (result.diff)
|
||||
fs.writeFileSync(diffPath, result.diff);
|
||||
|
||||
const output = [
|
||||
c.red(`GOLDEN FAILED: `) + c.yellow('"' + goldenName + '"'),
|
||||
c.red(`Image comparison failed:`),
|
||||
];
|
||||
if (result.errorMessage)
|
||||
output.push(' ' + result.errorMessage);
|
||||
output.push('');
|
||||
output.push(`Expected: ${c.yellow(expectedPath)}`);
|
||||
if (goldenPath === outputPath) {
|
||||
const filepath = addSuffix(actualPath, '-actual');
|
||||
fs.writeFileSync(filepath, actual);
|
||||
output.push(`Received: ${c.yellow(filepath)}`);
|
||||
} else {
|
||||
fs.writeFileSync(actualPath, actual);
|
||||
// Copy expected to the output/ folder for convenience.
|
||||
fs.writeFileSync(addSuffix(actualPath, '-expected'), expected);
|
||||
output.push(`Received: ${c.yellow(actualPath)}`);
|
||||
}
|
||||
if (result.diff) {
|
||||
const diffPath = addSuffix(actualPath, '-diff', result.diffExtension);
|
||||
fs.writeFileSync(diffPath, result.diff);
|
||||
output.push(`Received: ${c.yellow(actualPath)}`);
|
||||
if (result.diff)
|
||||
output.push(` Diff: ${c.yellow(diffPath)}`);
|
||||
}
|
||||
|
||||
let message = goldenName + ' mismatch!';
|
||||
if (result.errorMessage)
|
||||
message += ' ' + result.errorMessage;
|
||||
return {
|
||||
pass: false,
|
||||
message: message + ' ' + messageSuffix,
|
||||
formatter: () => output.join('\n'),
|
||||
message: output.join('n'),
|
||||
};
|
||||
|
||||
function ensureOutputDir() {
|
||||
if (!fs.existsSync(outputPath))
|
||||
fs.mkdirSync(outputPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const { FixturePool, registerFixture, registerWorkerFixture } = require('./fixturePool');
|
||||
const { FixturePool, registerFixture, registerWorkerFixture } = require('./fixtures');
|
||||
const { Test, Suite } = require('mocha');
|
||||
const {installTransform} = require('./transform');
|
||||
const commonSuite = require('mocha/lib/interfaces/common');
|
||||
|
@ -30,7 +30,5 @@ testOptions.FFOX = browserName === 'firefox';
|
||||
testOptions.WEBKIT = browserName === 'webkit';
|
||||
testOptions.WIRE = process.env.PWWIRE;
|
||||
testOptions.HEADLESS = !!valueFromEnv('HEADLESS', true);
|
||||
testOptions.ASSETS_DIR = path.join(__dirname, '..', 'assets');
|
||||
testOptions.GOLDEN_DIR = path.join(__dirname, '..', 'golden-' + browserName);
|
||||
|
||||
module.exports = testOptions;
|
||||
|
@ -16,14 +16,10 @@
|
||||
|
||||
const path = require('path');
|
||||
const Mocha = require('mocha');
|
||||
const { registerWorkerFixture } = require('./fixturePool');
|
||||
const { fixturesUI, fixturePool } = require('./fixturesUI');
|
||||
const { gracefullyCloseAll } = require('../../lib/server/processLauncher');
|
||||
const GoldenUtils = require('./GoldenUtils');
|
||||
|
||||
const browserName = process.env.BROWSER || 'chromium';
|
||||
const goldenPath = path.join(__dirname, '..', 'golden-' + browserName);
|
||||
const outputPath = path.join(__dirname, '..', 'output-' + browserName);
|
||||
global.expect = require('expect');
|
||||
global.testOptions = require('./testOptions');
|
||||
|
||||
@ -155,13 +151,9 @@ function serializeError(error) {
|
||||
}
|
||||
|
||||
function extendExpects() {
|
||||
function toBeGolden(received, goldenName) {
|
||||
const {pass, message} = GoldenUtils.compare(received, {
|
||||
goldenPath,
|
||||
outputPath,
|
||||
goldenName
|
||||
});
|
||||
function toMatchImage(received, path) {
|
||||
const {pass, message} = GoldenUtils.compare(received, path);
|
||||
return {pass, message: () => message};
|
||||
};
|
||||
global.expect.extend({ toBeGolden });
|
||||
global.expect.extend({ toMatchImage });
|
||||
}
|
||||
|
@ -14,29 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import './base.fixture';
|
||||
import { registerFixture } from './runner/fixtures';
|
||||
import { Page } from '..';
|
||||
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
const {mkdtempAsync, removeFolderAsync} = require('./utils');
|
||||
|
||||
const {FFOX, CHROMIUM, WEBKIT, MAC, LINUX, WIN, HEADLESS, WIRE} = testOptions;
|
||||
|
||||
declare global {
|
||||
interface FixtureState {
|
||||
persistentDirectory: string;
|
||||
videoPlayer: VideoPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
registerFixture('persistentDirectory', async ({}, test) => {
|
||||
const persistentDirectory = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-test-'));
|
||||
await test(persistentDirectory);
|
||||
await removeFolderAsync(persistentDirectory);
|
||||
});
|
||||
|
||||
registerFixture('videoPlayer', async ({playwright, context}, test) => {
|
||||
let firefox;
|
||||
if (WEBKIT && !LINUX) {
|
||||
@ -180,10 +172,10 @@ class VideoPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
it.fail(CHROMIUM)('should capture static page', async({page, persistentDirectory, videoPlayer, toImpl}) => {
|
||||
it.fail(CHROMIUM)('should capture static page', async({page, tmpDir, videoPlayer, toImpl}) => {
|
||||
if (!toImpl)
|
||||
return;
|
||||
const videoFile = path.join(persistentDirectory, 'v.webm');
|
||||
const videoFile = path.join(tmpDir, 'v.webm');
|
||||
await page.evaluate(() => document.body.style.backgroundColor = 'red');
|
||||
await toImpl(page)._delegate.startVideoRecording({outputFile: videoFile, width: 640, height: 480});
|
||||
// TODO: in WebKit figure out why video size is not reported correctly for
|
||||
@ -206,10 +198,10 @@ it.fail(CHROMIUM)('should capture static page', async({page, persistentDirectory
|
||||
expectAll(pixels, almostRed);
|
||||
});
|
||||
|
||||
it.fail(CHROMIUM)('should capture navigation', async({page, persistentDirectory, server, videoPlayer, toImpl}) => {
|
||||
it.fail(CHROMIUM)('should capture navigation', async({page, tmpDir, server, videoPlayer, toImpl}) => {
|
||||
if (!toImpl)
|
||||
return;
|
||||
const videoFile = path.join(persistentDirectory, 'v.webm');
|
||||
const videoFile = path.join(tmpDir, 'v.webm');
|
||||
await page.goto(server.PREFIX + '/background-color.html#rgb(0,0,0)');
|
||||
await toImpl(page)._delegate.startVideoRecording({outputFile: videoFile, width: 640, height: 480});
|
||||
// TODO: in WebKit figure out why video size is not reported correctly for
|
||||
@ -239,10 +231,10 @@ it.fail(CHROMIUM)('should capture navigation', async({page, persistentDirectory,
|
||||
}
|
||||
});
|
||||
|
||||
it.fail(CHROMIUM)('should capture css transformation', async({page, persistentDirectory, server, videoPlayer, toImpl}) => {
|
||||
it.fail(CHROMIUM)('should capture css transformation', async({page, tmpDir, server, videoPlayer, toImpl}) => {
|
||||
if (!toImpl)
|
||||
return;
|
||||
const videoFile = path.join(persistentDirectory, 'v.webm');
|
||||
const videoFile = path.join(tmpDir, 'v.webm');
|
||||
await page.goto(server.PREFIX + '/rotate-z.html');
|
||||
await toImpl(page)._delegate.startVideoRecording({outputFile: videoFile, width: 640, height: 480});
|
||||
// TODO: in WebKit figure out why video size is not reported correctly for
|
||||
|
6
test/types.d.ts
vendored
@ -19,7 +19,7 @@ interface FixtureState {
|
||||
declare module '' {
|
||||
module 'expect/build/types' {
|
||||
interface Matchers<R> {
|
||||
toBeGolden(name: string): R;
|
||||
toMatchImage(path: string): R;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,9 +41,6 @@ declare const afterEach: (inner: (state: FixtureState & WorkerState) => Promise<
|
||||
declare const beforeAll: (inner: (state: WorkerState) => Promise<void>) => void;
|
||||
declare const afterAll: (inner: (state: WorkerState) => Promise<void>) => void;
|
||||
|
||||
declare const registerFixture: <T extends keyof FixtureState>(name: T, inner: (state: FixtureState & WorkerState, test: (arg: FixtureState[T]) => Promise<void>) => Promise<void>) => void;
|
||||
declare const registerWorkerFixture: <T extends keyof WorkerState>(name: T, inner: (state: WorkerState, test: (arg: WorkerState[T]) => Promise<void>) => Promise<void>) => void;
|
||||
|
||||
declare const browserType: import('../index').BrowserType<import('../index').Browser>;
|
||||
|
||||
// global variables in assets
|
||||
@ -56,7 +53,6 @@ declare const testOptions: {
|
||||
WIN: boolean;
|
||||
HEADLESS: boolean;
|
||||
WIRE: boolean;
|
||||
ASSETS_DIR: string;
|
||||
};
|
||||
|
||||
declare const testPath : string;
|
||||
|
@ -52,7 +52,7 @@ async function testLint(name) {
|
||||
const jsSources = await Source.readdir(dirPath, '.js');
|
||||
const messages = await checkPublicAPI(page, mdSources, jsSources.concat(tsSources));
|
||||
const errors = messages.map(message => message.text);
|
||||
expect(errors.join('\n')).toBeGolden(path.join(dirPath, 'result.txt'));
|
||||
expect(errors.join('\n')).toMatchImage(path.join(dirPath, 'result.txt'));
|
||||
});
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ async function testMDBuilder(name) {
|
||||
const dirPath = path.join(__dirname, name);
|
||||
const sources = await Source.readdir(dirPath, '.md');
|
||||
const {documentation} = await mdBuilder(page, sources);
|
||||
expect(serialize(documentation)).toBeGolden(path.join(dirPath, 'result.txt'));
|
||||
expect(serialize(documentation)).toMatchImage(path.join(dirPath, 'result.txt'));
|
||||
});
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ async function testJSBuilder(name) {
|
||||
const jsSources = await Source.readdir(dirPath, '.js');
|
||||
const tsSources = await Source.readdir(dirPath, '.ts');
|
||||
const {documentation} = await jsBuilder.checkSources(jsSources.concat(tsSources));
|
||||
expect(serialize(documentation)).toBeGolden(path.join(dirPath, 'result.txt'));
|
||||
expect(serialize(documentation)).toMatchImage(path.join(dirPath, 'result.txt'));
|
||||
});
|
||||
}
|
||||
|
||||
|