test: simplify more tests (#6471)

This commit is contained in:
Dmitry Gozman 2021-05-09 17:47:20 -07:00 committed by GitHub
parent a5143ebaa9
commit 76e409637a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 95 deletions

View File

@ -15,15 +15,8 @@
*/
import { browserTest as it, expect } from './config/browserTest';
import type { Browser } from '../index';
let browser: Browser;
it.beforeAll(async ({ browserType, browserOptions }) => {
browser = await browserType.launch({ ...browserOptions, proxy: { server: 'per-context' } });
});
it.afterAll(async () => {
await browser.close();
});
it.useOptions({ launchOptions: { proxy: { server: 'per-context' } } });
it('should throw for missing global proxy on Chromium Windows', async ({ browserName, platform, browserType, browserOptions, server }) => {
it.skip(browserName !== 'chromium' || platform !== 'win32');
@ -44,8 +37,8 @@ it('should work when passing the proxy only on the context level', async ({brows
res.end('<html><title>Served by the proxy</title></html>');
});
delete browserOptions.proxy;
const browserWithoutProxyInLaunch = await browserType.launch(browserOptions);
const context = await browserWithoutProxyInLaunch.newContext({
const browser = await browserType.launch(browserOptions);
const context = await browser.newContext({
...contextOptions,
proxy: { server: `localhost:${server.PORT}` }
});
@ -53,24 +46,22 @@ it('should work when passing the proxy only on the context level', async ({brows
const page = await context.newPage();
await page.goto('http://non-existent.com/target.html');
expect(await page.title()).toBe('Served by the proxy');
await browserWithoutProxyInLaunch.close();
await browser.close();
});
it('should throw for bad server value', async ({ contextOptions }) => {
const error = await browser.newContext({
...contextOptions,
it('should throw for bad server value', async ({ contextFactory }) => {
const error = await contextFactory({
// @ts-expect-error server must be a string
proxy: { server: 123 }
}).catch(e => e);
expect(error.message).toContain('proxy.server: expected string, got number');
});
it('should use proxy', async ({ contextOptions, server }) => {
it('should use proxy', async ({ contextFactory, server }) => {
server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>');
});
const context = await browser.newContext({
...contextOptions,
const context = await contextFactory({
proxy: { server: `localhost:${server.PORT}` }
});
const page = await context.newPage();
@ -79,12 +70,11 @@ it('should use proxy', async ({ contextOptions, server }) => {
await context.close();
});
it('should use proxy twice', async ({ contextOptions, server }) => {
it('should use proxy twice', async ({ contextFactory, server }) => {
server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>');
});
const context = await browser.newContext({
...contextOptions,
const context = await contextFactory({
proxy: { server: `localhost:${server.PORT}` }
});
const page = await context.newPage();
@ -94,12 +84,11 @@ it('should use proxy twice', async ({ contextOptions, server }) => {
await context.close();
});
it('should use proxy for second page', async ({contextOptions, server}) => {
it('should use proxy for second page', async ({contextFactory, server}) => {
server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>');
});
const context = await browser.newContext({
...contextOptions,
const context = await contextFactory({
proxy: { server: `localhost:${server.PORT}` }
});
@ -114,12 +103,11 @@ it('should use proxy for second page', async ({contextOptions, server}) => {
await context.close();
});
it('should work with IP:PORT notion', async ({contextOptions, server}) => {
it('should work with IP:PORT notion', async ({contextFactory, server}) => {
server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>');
});
const context = await browser.newContext({
...contextOptions,
const context = await contextFactory({
proxy: { server: `127.0.0.1:${server.PORT}` }
});
const page = await context.newPage();
@ -128,23 +116,21 @@ it('should work with IP:PORT notion', async ({contextOptions, server}) => {
await context.close();
});
it('should throw for socks5 authentication', async ({contextOptions}) => {
const error = await browser.newContext({
...contextOptions,
it('should throw for socks5 authentication', async ({contextFactory}) => {
const error = await contextFactory({
proxy: { server: `socks5://localhost:1234`, username: 'user', password: 'secret' }
}).catch(e => e);
expect(error.message).toContain('Browser does not support socks5 proxy authentication');
});
it('should throw for socks4 authentication', async ({contextOptions}) => {
const error = await browser.newContext({
...contextOptions,
it('should throw for socks4 authentication', async ({contextFactory}) => {
const error = await contextFactory({
proxy: { server: `socks4://localhost:1234`, username: 'user', password: 'secret' }
}).catch(e => e);
expect(error.message).toContain('Socks4 proxy protocol does not support authentication');
});
it('should authenticate', async ({contextOptions, server}) => {
it('should authenticate', async ({contextFactory, server}) => {
server.setRoute('/target.html', async (req, res) => {
const auth = req.headers['proxy-authorization'];
if (!auth) {
@ -156,8 +142,7 @@ it('should authenticate', async ({contextOptions, server}) => {
res.end(`<html><title>${auth}</title></html>`);
}
});
const context = await browser.newContext({
...contextOptions,
const context = await contextFactory({
proxy: { server: `localhost:${server.PORT}`, username: 'user', password: 'secret' }
});
const page = await context.newPage();
@ -166,7 +151,7 @@ it('should authenticate', async ({contextOptions, server}) => {
await context.close();
});
it('should authenticate with empty password', async ({contextOptions, server}) => {
it('should authenticate with empty password', async ({contextFactory, server}) => {
server.setRoute('/target.html', async (req, res) => {
const auth = req.headers['proxy-authorization'];
if (!auth) {
@ -178,8 +163,7 @@ it('should authenticate with empty password', async ({contextOptions, server}) =
res.end(`<html><title>${auth}</title></html>`);
}
});
const context = await browser.newContext({
...contextOptions,
const context = await contextFactory({
proxy: { server: `localhost:${server.PORT}`, username: 'user', password: '' }
});
const page = await context.newPage();
@ -188,8 +172,7 @@ it('should authenticate with empty password', async ({contextOptions, server}) =
await context.close();
});
it('should isolate proxy credentials between contexts', async ({contextOptions, server, browserName}) => {
it('should isolate proxy credentials between contexts', async ({contextFactory, server, browserName}) => {
it.fixme(browserName === 'firefox', 'Credentials from the first context stick around');
server.setRoute('/target.html', async (req, res) => {
@ -204,8 +187,7 @@ it('should isolate proxy credentials between contexts', async ({contextOptions,
}
});
{
const context = await browser.newContext({
...contextOptions,
const context = await contextFactory({
proxy: { server: `localhost:${server.PORT}`, username: 'user1', password: 'secret1' }
});
const page = await context.newPage();
@ -214,8 +196,7 @@ it('should isolate proxy credentials between contexts', async ({contextOptions,
await context.close();
}
{
const context = await browser.newContext({
...contextOptions,
const context = await contextFactory({
proxy: { server: `localhost:${server.PORT}`, username: 'user2', password: 'secret2' }
});
const page = await context.newPage();
@ -225,7 +206,7 @@ it('should isolate proxy credentials between contexts', async ({contextOptions,
}
});
it('should exclude patterns', async ({contextOptions, server, browserName, headful}) => {
it('should exclude patterns', async ({contextFactory, server, browserName, headful}) => {
it.fixme(browserName === 'chromium' && headful, 'Chromium headful crashes with CHECK(!in_frame_tree_) in RenderFrameImpl::OnDeleteFrame.');
server.setRoute('/target.html', async (req, res) => {
@ -235,8 +216,7 @@ it('should exclude patterns', async ({contextOptions, server, browserName, headf
// that resolves everything to some weird search results page.
//
// @see https://gist.github.com/CollinChaffin/24f6c9652efb3d6d5ef2f5502720ef00
const context = await browser.newContext({
...contextOptions,
const context = await contextFactory({
proxy: { server: `localhost:${server.PORT}`, bypass: '1.non.existent.domain.for.the.test, 2.non.existent.domain.for.the.test, .another.test' }
});
@ -267,9 +247,8 @@ it('should exclude patterns', async ({contextOptions, server, browserName, headf
await context.close();
});
it('should use socks proxy', async ({ contextOptions, socksPort }) => {
const context = await browser.newContext({
...contextOptions,
it('should use socks proxy', async ({ contextFactory, socksPort }) => {
const context = await contextFactory({
proxy: { server: `socks5://localhost:${socksPort}` }
});
const page = await context.newPage();
@ -278,9 +257,8 @@ it('should use socks proxy', async ({ contextOptions, socksPort }) => {
await context.close();
});
it('should use socks proxy in second page', async ({ contextOptions, socksPort }) => {
const context = await browser.newContext({
...contextOptions,
it('should use socks proxy in second page', async ({ contextFactory, socksPort }) => {
const context = await contextFactory({
proxy: { server: `socks5://localhost:${socksPort}` }
});
@ -295,9 +273,8 @@ it('should use socks proxy in second page', async ({ contextOptions, socksPort }
await context.close();
});
it('does launch without a port', async ({ contextOptions }) => {
const context = await browser.newContext({
...contextOptions,
it('does launch without a port', async ({ contextFactory }) => {
const context = await contextFactory({
proxy: { server: 'http://localhost' }
});
await context.close();

View File

@ -56,11 +56,11 @@ class PlaywrightEnv {
async beforeAll(args: CommonArgs & PlaywrightEnvOptions, workerInfo: folio.WorkerInfo): Promise<PlaywrightWorkerArgs> {
this._browserType = args.playwright[args.browserName];
this._browserOptions = {
...args.launchOptions,
_traceDir: args.traceDir,
channel: args.browserChannel,
headless: !args.headful,
handleSIGINT: false,
...args.launchOptions,
} as any;
return {
browserType: this._browserType,
@ -126,21 +126,30 @@ type BrowserTestArgs = {
contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
};
type BrowserTestOptions = {
contextOptions?: BrowserContextOptions;
};
class BrowserEnv {
private _browser: Browser | undefined;
private _contexts: BrowserContext[] = [];
protected _browserVersion: string;
hasBeforeAllOptions(options: BrowserTestOptions) {
return false;
}
async beforeAll(args: PlaywrightWorkerArgs, workerInfo: folio.WorkerInfo) {
this._browser = await args.browserType.launch(args.browserOptions);
this._browserVersion = this._browser.version();
}
async beforeEach(options: CommonArgs, testInfo: folio.TestInfo): Promise<BrowserTestArgs> {
async beforeEach(options: CommonArgs & BrowserTestOptions, testInfo: folio.TestInfo): Promise<BrowserTestArgs> {
const debugName = path.relative(testInfo.project.outputDir, testInfo.outputDir).replace(/[\/\\]/g, '-');
const contextOptions = {
recordVideo: options.video ? { dir: testInfo.outputPath('') } : undefined,
_debugName: debugName,
...options.contextOptions,
} as BrowserContextOptions;
testInfo.data.browserVersion = this._browserVersion;

View File

@ -14,39 +14,41 @@
* limitations under the License.
*/
import { contextTest as it, expect } from './config/browserTest';
import { contextTest, expect } from './config/browserTest';
import { InMemorySnapshotter } from '../lib/server/snapshot/inMemorySnapshotter';
import { HttpServer } from '../lib/utils/httpServer';
import { SnapshotServer } from '../lib/server/snapshot/snapshotServer';
it.describe('snapshots', () => {
let snapshotter: any;
let httpServer: any;
let snapshotPort: number;
it.skip(({ mode }) => mode !== 'default');
it.beforeEach(async ({ toImpl, context }, testInfo) => {
snapshotter = new InMemorySnapshotter(toImpl(context));
const it = contextTest.extend({
async beforeEach({ context, toImpl, mode }, testInfo) {
testInfo.skip(mode !== 'default');
const snapshotter = new InMemorySnapshotter(toImpl(context));
await snapshotter.initialize();
httpServer = new HttpServer();
new SnapshotServer(httpServer, snapshotter);
snapshotPort = 11000 + testInfo.workerIndex;
httpServer.start(snapshotPort);
});
this.httpServer = new HttpServer();
new SnapshotServer(this.httpServer, snapshotter);
const snapshotPort = 11000 + testInfo.workerIndex;
await this.httpServer.start(snapshotPort);
this.snapshotter = snapshotter;
return {
snapshotter,
snapshotPort,
};
},
it.afterEach(async () => {
await snapshotter.dispose();
httpServer.stop();
});
async afterEach() {
await this.snapshotter.dispose();
await this.httpServer.stop();
},
});
it('should collect snapshot', async ({ page, toImpl }) => {
it.describe('snapshots', () => {
it('should collect snapshot', async ({ page, toImpl, snapshotter }) => {
await page.setContent('<button>Hello</button>');
const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot');
expect(distillSnapshot(snapshot)).toBe('<BUTTON>Hello</BUTTON>');
});
it('should capture resources', async ({ page, toImpl, server }) => {
it('should capture resources', async ({ page, toImpl, server, snapshotter }) => {
await page.goto(server.EMPTY_PAGE);
await page.route('**/style.css', route => {
route.fulfill({ body: 'button { color: red; }', }).catch(() => {});
@ -58,7 +60,7 @@ it.describe('snapshots', () => {
expect(resources[cssHref]).toBeTruthy();
});
it('should collect multiple', async ({ page, toImpl }) => {
it('should collect multiple', async ({ page, toImpl, snapshotter }) => {
await page.setContent('<button>Hello</button>');
const snapshots = [];
snapshotter.on('snapshot', snapshot => snapshots.push(snapshot));
@ -67,7 +69,7 @@ it.describe('snapshots', () => {
expect(snapshots.length).toBe(2);
});
it('should respect inline CSSOM change', async ({ page, toImpl }) => {
it('should respect inline CSSOM change', async ({ page, toImpl, snapshotter }) => {
await page.setContent('<style>button { color: red; }</style><button>Hello</button>');
const snapshot1 = await snapshotter.captureSnapshot(toImpl(page), 'snapshot1');
expect(distillSnapshot(snapshot1)).toBe('<style>button { color: red; }</style><BUTTON>Hello</BUTTON>');
@ -77,7 +79,7 @@ it.describe('snapshots', () => {
expect(distillSnapshot(snapshot2)).toBe('<style>button { color: blue; }</style><BUTTON>Hello</BUTTON>');
});
it('should respect subresource CSSOM change', async ({ page, server, toImpl }) => {
it('should respect subresource CSSOM change', async ({ page, server, toImpl, snapshotter }) => {
await page.goto(server.EMPTY_PAGE);
await page.route('**/style.css', route => {
route.fulfill({ body: 'button { color: red; }', }).catch(() => {});
@ -95,7 +97,7 @@ it.describe('snapshots', () => {
expect(snapshotter.resourceContent(sha1).toString()).toBe('button { color: blue; }');
});
it('should capture iframe', async ({ page, contextFactory, server, toImpl, browserName }) => {
it('should capture iframe', async ({ page, contextFactory, server, toImpl, browserName, snapshotter, snapshotPort }) => {
it.skip(browserName === 'firefox');
await page.route('**/empty.html', route => {
@ -136,7 +138,7 @@ it.describe('snapshots', () => {
expect(await button.textContent()).toBe('Hello iframe');
});
it('should capture snapshot target', async ({ page, toImpl }) => {
it('should capture snapshot target', async ({ page, toImpl, snapshotter }) => {
await page.setContent('<button>Hello</button><button>World</button>');
{
const handle = await page.$('text=Hello');
@ -150,7 +152,7 @@ it.describe('snapshots', () => {
}
});
it('should collect on attribute change', async ({ page, toImpl }) => {
it('should collect on attribute change', async ({ page, toImpl, snapshotter }) => {
await page.setContent('<button>Hello</button>');
{
const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot');

View File

@ -14,19 +14,11 @@
* limitations under the License.
*/
import { browserTest, expect } from './config/browserTest';
import { contextTest as it, expect } from './config/browserTest';
import { ElementHandle } from '../index';
import type { ServerResponse } from 'http';
const it = browserTest.extend({
async beforeEach({ browser }) {
this.page = await browser.newPage({ hasTouch: true });
return { page: this.page };
},
async afterEach() {
await this.page.close();
}
});
it.useOptions({ contextOptions: { hasTouch: true } });
it('should send all of the correct events', async ({ page }) => {
await page.setContent(`