참고소스 수정본

This commit is contained in:
LASTA_DEV01\lasta
2026-05-12 19:40:31 +09:00
parent 0f34a451fc
commit 2e9204243d
8708 changed files with 3259488 additions and 869 deletions

View File

@@ -0,0 +1,58 @@
/**
* Copyright 2020 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 net from 'net';
import { androidTest as test, expect } from './androidTest';
// Force a separate worker to avoid messing up with `androidDevice` fixture.
test.use({ launchOptions: [async ({ launchOptions }, use) => use(launchOptions), { scope: 'worker' }] });
test('androidDevice.close', async function({ playwright }) {
const devices = await playwright._android.devices();
expect(devices.length).toBe(1);
const device = devices[0];
const events: string[] = [];
device.on('close', () => events.push('close'));
await device.close();
await device.close();
expect(events).toEqual(['close']);
});
test('should be able to use a custom port', async function({ playwright }) {
const proxyPort = 5038;
let countOfIncomingConnections = 0;
let countOfConnections = 0;
const server = net.createServer(socket => {
++countOfIncomingConnections;
++countOfConnections;
socket.on('close', () => countOfConnections--);
const client = net.connect(5037, '127.0.0.1');
socket.pipe(client).pipe(socket);
});
await new Promise<void>(resolve => server.listen(proxyPort, resolve));
const devices = await playwright._android.devices({ port: proxyPort });
expect(countOfIncomingConnections).toBeGreaterThanOrEqual(1);
expect(devices).toHaveLength(1);
const device = devices[0];
const value = await device.shell('echo foobar');
expect(value.toString()).toBe('foobar\n');
await device.close();
await new Promise(resolve => server.close(resolve));
expect(countOfIncomingConnections).toBeGreaterThanOrEqual(1);
expect(countOfConnections).toBe(0);
});

View File

@@ -0,0 +1,88 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 { baseTest } from '../config/baseTest';
import type { PageTestFixtures, PageWorkerFixtures } from '../page/pageTestApi';
import type { AndroidDevice, BrowserContext } from 'playwright-core';
export { expect } from '@playwright/test';
type AndroidTestFixtures = {
androidDevice: AndroidDevice;
};
type AndroidWorkerFixtures = PageWorkerFixtures & {
androidDeviceWorker: AndroidDevice;
androidContext: BrowserContext;
};
async function closeAllActivities(device: AndroidDevice) {
await device.shell('am force-stop com.google.android.googlequicksearchbox');
await device.shell('am force-stop org.chromium.webview_shell');
await device.shell('am force-stop com.android.chrome');
}
export const androidTest = baseTest.extend<PageTestFixtures & AndroidTestFixtures, AndroidWorkerFixtures>({
androidDeviceWorker: [async ({ playwright }, run) => {
const device = (await playwright._android.devices())[0];
await closeAllActivities(device);
device.setDefaultTimeout(90000);
await run(device);
await device.close();
}, { scope: 'worker' }],
browserVersion: [async ({ androidDeviceWorker }, run) => {
const browserVersion = (await androidDeviceWorker.shell('dumpsys package com.android.chrome'))
.toString('utf8')
.split('\n')
.find(line => line.includes('versionName='))!
.trim()
.split('=')[1];
await run(browserVersion);
}, { scope: 'worker' }],
browserMajorVersion: [async ({ browserVersion }, run) => {
await run(Number(browserVersion.split('.')[0]));
}, { scope: 'worker' }],
isBidi: [false, { scope: 'worker' }],
isAndroid: [true, { scope: 'worker' }],
isElectron: [false, { scope: 'worker' }],
electronMajorVersion: [0, { scope: 'worker' }],
isHeadlessShell: [false, { scope: 'worker' }],
isFrozenWebkit: [false, { scope: 'worker' }],
androidDevice: async ({ androidDeviceWorker }, use) => {
await closeAllActivities(androidDeviceWorker);
await use(androidDeviceWorker);
await closeAllActivities(androidDeviceWorker);
},
androidContext: [async ({ androidDeviceWorker }, run) => {
const context = await androidDeviceWorker.launchBrowser();
const [page] = context.pages();
await page.goto('data:text/html,Default page');
await run(context);
}, { scope: 'worker' }],
page: async ({ androidContext }, run) => {
// Retain default page, otherwise Clank will re-create it.
while (androidContext.pages().length > 1)
await androidContext.pages()[1].close();
const page = await androidContext.newPage();
await run(page);
await androidContext.clearCookies();
},
});

View File

@@ -0,0 +1,170 @@
/**
* Copyright 2020 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 fs from 'fs';
import { androidTest as test, expect } from './androidTest';
test('androidDevice.model', async function({ androidDevice }) {
expect(androidDevice.model()).toContain('sdk_gphone');
expect(androidDevice.model()).toContain('x86_64');
});
test('androidDevice.launchBrowser', async function({ androidDevice }) {
const context = await androidDevice.launchBrowser();
const [page] = context.pages();
await page.goto('data:text/html,<title>Hello world!</title>');
expect(await page.title()).toBe('Hello world!');
await context.close();
});
test('androidDevice.launchBrowser should treat args correctly', async ({ androidDevice }) => {
for (const arg of [
"--user-agent='I am Foo'",
'--user-agent="I am Foo"',
]) {
await test.step(`arg: ${arg}`, async () => {
const context = await androidDevice.launchBrowser({ args: [arg] });
const page = await context.newPage();
const userAgent = await page.evaluate(() => navigator.userAgent);
await context.close();
expect(userAgent).toBe('I am Foo');
});
}
});
test('androidDevice.launchBrowser should throw for bad proxy server value', async ({ androidDevice }) => {
const error = await androidDevice.launchBrowser({
// @ts-expect-error server must be a string
proxy: { server: 123 }
}).catch(e => e);
expect(error.message).toContain('proxy.server: expected string, got number');
});
test('androidDevice.launchBrowser should pass proxy config', async ({ androidDevice, server, mode, loopback }) => {
server.setRoute('/target.html', async (req, res) => {
res.end('<html><title>Served by the proxy</title></html>');
});
const context = await androidDevice.launchBrowser({ proxy: { server: `${loopback}:${server.PORT}` } });
const page = await context.newPage();
await page.goto('http://non-existent.com/target.html');
expect(await page.title()).toBe('Served by the proxy');
await context.close();
});
test('should create new page', async function({ androidDevice }) {
const context = await androidDevice.launchBrowser();
const page = await context.newPage();
await page.goto('data:text/html,<title>Hello world!</title>');
expect(await page.title()).toBe('Hello world!');
await page.close();
await context.close();
});
test('should check', async function({ androidDevice }) {
const context = await androidDevice.launchBrowser();
const [page] = context.pages();
await page.setContent(`<input id='checkbox' type='checkbox'></input>`);
await page.check('input');
expect(await page.evaluate(() => window['checkbox'].checked)).toBe(true);
await page.close();
await context.close();
});
test('should take page screenshot', async function({ androidDevice }) {
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/26342' });
test.fixme(true, 'Sometimes fails with Protocol error (Page.captureScreenshot): Unable to capture screenshot');
test.fixme(true, 'Regular screenshot has an extra pixel border');
test.fixme(true, 'Full page screenshot has repeated content');
const context = await androidDevice.launchBrowser();
const [page] = context.pages();
await page.setContent(`
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<style>
* { margin: 0; padding: 0; }
div {
width: 200px;
height: 250px;
}
</style>
<div style="background: red"></div>
<div style="background: green"></div>
<div style="background: red"></div>
<div style="background: green"></div>
<div style="background: red"></div>
<div style="background: green"></div>
</body>
</html>
`);
const screenshot = await page.screenshot({ fullPage: false, scale: 'css' });
const fullPageScreenshot = await page.screenshot({ fullPage: true, scale: 'css' });
expect(screenshot).toMatchSnapshot('page-screenshot.png');
expect(fullPageScreenshot).toMatchSnapshot('fullpage-screenshot.png');
await context.close();
});
test('should be able to send CDP messages', async ({ androidDevice }) => {
const context = await androidDevice.launchBrowser();
const [page] = context.pages();
const client = await context.newCDPSession(page);
await client.send('Runtime.enable');
const evalResponse = await client.send('Runtime.evaluate', { expression: '1 + 2', returnByValue: true });
expect(evalResponse.result.value).toBe(3);
await context.close();
});
test('should be able to pass context options', async ({ androidDevice, httpsServer }) => {
const context = await androidDevice.launchBrowser({
colorScheme: 'dark',
geolocation: { longitude: 10, latitude: 10 },
permissions: ['geolocation'],
ignoreHTTPSErrors: true,
baseURL: httpsServer.PREFIX,
});
const [page] = context.pages();
await page.goto('./empty.html');
expect(page.url()).toBe(httpsServer.PREFIX + '/empty.html');
expect(await page.evaluate(() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => {
resolve({ latitude: position.coords.latitude, longitude: position.coords.longitude });
})))).toEqual({ latitude: 10, longitude: 10 });
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(false);
await context.close();
});
test('should record har', async ({ androidDevice }) => {
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/28015' });
const harPath = test.info().outputPath('test.har');
const context = await androidDevice.launchBrowser({
recordHar: { path: harPath }
});
const [page] = context.pages();
await page.goto('data:text/html,<title>Hello</title>');
await page.waitForLoadState('domcontentloaded');
await context.close();
const log = JSON.parse(fs.readFileSync(harPath).toString())['log'];
expect(log.pages[0].title).toBe('Hello');
});

View File

@@ -0,0 +1,60 @@
/**
* Copyright 2020 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 fs from 'fs';
import { PNG } from 'playwright-core/lib/utilsBundle';
import { androidTest as test, expect } from './androidTest';
test('androidDevice.shell', async function({ androidDevice }) {
const output = await androidDevice.shell('echo 123');
expect(output.toString()).toBe('123\n');
});
test('androidDevice.open', async function({ androidDevice }) {
const socket = await androidDevice.open('shell:/bin/cat');
await socket.write(Buffer.from('321\n'));
const output = await new Promise(resolve => socket.on('data', resolve));
expect(output!.toString()).toBe('321\n');
const closedPromise = new Promise<void>(resolve => socket.on('close', resolve));
await socket.close();
await closedPromise;
});
test('androidDevice.screenshot', async function({ androidDevice }, testInfo) {
const path = testInfo.outputPath('screenshot.png');
const result = await androidDevice.screenshot({ path });
const buffer = fs.readFileSync(path);
expect(result.length).toBe(buffer.length);
const { width, height } = PNG.sync.read(result);
expect(width).toBe(1080);
expect(height).toBe(1920);
});
test('androidDevice.push', async function({ androidDevice }) {
try {
await androidDevice.push(Buffer.from('hello world'), '/data/local/tmp/hello-world');
const data = await androidDevice.shell('cat /data/local/tmp/hello-world');
expect(data).toEqual(Buffer.from('hello world'));
} finally {
await androidDevice.shell('rm /data/local/tmp/hello-world');
}
});
test('androidDevice.fill', async function({ androidDevice }) {
await androidDevice.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
await androidDevice.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'Hello', { timeout: test.info().timeout });
expect((await androidDevice.info({ res: 'org.chromium.webview_shell:id/url_field' })).text).toBe('Hello');
});

View File

@@ -0,0 +1,168 @@
/**
* Copyright 2020 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 { WebSocket, WebSocketServer, type AddressInfo } from 'ws';
import { androidTest as test, expect } from './androidTest';
import { kTargetClosedErrorMessage } from '../config/errors';
// Force a separate worker to avoid messing up with `androidDevice` fixture.
test.use({ launchOptions: [async ({ launchOptions }, use) => use(launchOptions), { scope: 'worker' }] });
test('android.launchServer should connect to a device', async ({ playwright }) => {
const browserServer = await playwright._android.launchServer();
const device = await playwright._android.connect(browserServer.wsEndpoint());
const output = await device.shell('echo 123');
expect(output.toString()).toBe('123\n');
await device.close();
await browserServer.close();
});
test('android.launchServer should work with host', async ({ playwright }) => {
const host = '0.0.0.0';
const browserServer = await playwright._android.launchServer({ host });
expect(browserServer.wsEndpoint()).toContain(String(host));
const device = await playwright._android.connect(browserServer.wsEndpoint());
const output = await device.shell('echo 123');
expect(output.toString()).toBe('123\n');
await device.close();
await browserServer.close();
});
test('android.launchServer should handle close event correctly', async ({ playwright }) => {
const receivedEvents: string[] = [];
const browserServer = await playwright._android.launchServer();
const device = await playwright._android.connect(browserServer.wsEndpoint());
device.on('close', () => receivedEvents.push('device'));
browserServer.on('close', () => receivedEvents.push('browserServer'));
{
const waitForDeviceClose = new Promise(f => device.on('close', f));
await device.close();
await waitForDeviceClose;
}
expect(receivedEvents).toEqual(['device']);
await device.close();
expect(receivedEvents).toEqual(['device']);
await browserServer.close();
expect(receivedEvents).toEqual(['device', 'browserServer']);
await browserServer.close();
expect(receivedEvents).toEqual(['device', 'browserServer']);
await device.close();
expect(receivedEvents).toEqual(['device', 'browserServer']);
});
test('android.launchServer should be able to reconnect to a device', async ({ playwright }) => {
const browserServer = await playwright._android.launchServer();
try {
{
const device = await playwright._android.connect(browserServer.wsEndpoint());
await device.push(Buffer.from('hello world'), '/data/local/tmp/hello-world');
await device.close();
}
{
const device = await playwright._android.connect(browserServer.wsEndpoint());
const data = await device.shell('cat /data/local/tmp/hello-world');
expect(data).toEqual(Buffer.from('hello world'));
await device.close();
}
} finally {
// Cleanup
const device = await playwright._android.connect(browserServer.wsEndpoint());
await device.shell('rm /data/local/tmp/hello-world');
await device.close();
await browserServer.close();
}
});
test('android.launchServer should throw if there is no device with a specified serial number', async ({ playwright }) => {
await expect(playwright._android.launchServer({
deviceSerialNumber: 'does-not-exist',
})).rejects.toThrow(`No device with serial number 'does-not-exist'`);
});
test('android.launchServer should not allow multiple connections', async ({ playwright }) => {
const browserServer = await playwright._android.launchServer();
try {
await playwright._android.connect(browserServer.wsEndpoint());
await expect(playwright._android.connect(browserServer.wsEndpoint(), { timeout: 2_000 })).rejects.toThrow('android.connect: Timeout 2000ms exceeded');
} finally {
await browserServer.close();
}
});
test('android.launchServer BrowserServer.close() will disconnect the device', async ({ playwright }) => {
const browserServer = await playwright._android.launchServer();
try {
const device = await playwright._android.connect(browserServer.wsEndpoint());
await browserServer.close();
await expect(device.shell('echo 123')).rejects.toThrow('androidDevice.shell: ' + kTargetClosedErrorMessage);
} finally {
await browserServer.close();
}
});
test('android.launchServer BrowserServer.kill() will disconnect the device', async ({ playwright }) => {
const browserServer = await playwright._android.launchServer();
try {
const device = await playwright._android.connect(browserServer.wsEndpoint());
await browserServer.kill();
await expect(device.shell('echo 123')).rejects.toThrow('androidDevice.shell: ' + kTargetClosedErrorMessage);
} finally {
await browserServer.close();
}
});
test('android.launchServer should terminate WS connection when device gets disconnected', async ({ playwright }) => {
const browserServer = await playwright._android.launchServer();
const forwardingServer = new WebSocketServer({ port: 0, path: '/connect' });
let receivedConnection: WebSocket | undefined;
forwardingServer.on('connection', connection => {
// Pause the connection until we establish the actual connection to the browser server.
// Someone is using non-existing api
(connection as any).pause();
receivedConnection = connection;
const actualConnection = new WebSocket(browserServer.wsEndpoint());
// We need to wait for the actual connection to be established before resuming
actualConnection.on('open', () => (connection as any).resume());
actualConnection.on('message', message => connection.send(message));
connection.on('message', message => actualConnection.send(message));
connection.on('close', () => actualConnection.close());
actualConnection.on('close', () => connection.close());
});
try {
const device = await playwright._android.connect(`ws://localhost:${(forwardingServer.address() as AddressInfo).port}/connect`);
expect((await device.shell('echo 123')).toString()).toBe('123\n');
expect(receivedConnection!.readyState).toBe(WebSocket.OPEN);
const waitToClose = new Promise(f => receivedConnection!.on('close', f));
await device.close();
await waitToClose;
expect(receivedConnection!.readyState).toBe(WebSocket.CLOSED);
} finally {
await browserServer.close();
await new Promise(f => forwardingServer.close(f));
}
});
test('android.launchServer should be able to launch browser', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/36911' } }, async ({ playwright }) => {
const browserServer = await playwright._android.launchServer();
const device = await playwright._android.connect(browserServer.wsEndpoint());
const context = await device.launchBrowser();
const [page] = context.pages();
await page.goto('data:text/html,<title>Hello world!</title>');
expect(await page.title()).toBe('Hello world!');
await context.close();
await device.close();
await browserServer.close();
});

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) Microsoft Corporation.
*
* 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 { config as loadEnv } from 'dotenv';
loadEnv({ path: path.join(__dirname, '..', '..', '.env') });
process.env.PWTEST_UNDER_TEST = '1';
import type { Config, PlaywrightTestOptions, PlaywrightWorkerOptions } from '@playwright/test';
import * as path from 'path';
import type { ServerWorkerOptions } from '../config/serverFixtures';
process.env.PWPAGE_IMPL = 'android';
const outputDir = path.join(__dirname, '..', '..', 'test-results');
const testDir = path.join(__dirname, '..');
const config: Config<ServerWorkerOptions & PlaywrightWorkerOptions & PlaywrightTestOptions> = {
testDir,
outputDir,
expect: {
timeout: 10000,
},
timeout: 120000,
globalTimeout: 7200000,
workers: 1,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 1 : 0,
reporter: process.env.CI ? [
['dot'],
['json', { outputFile: path.join(outputDir, 'report.json') }],
] : 'line',
projects: [],
};
const metadata = {
platform: 'Android',
headless: 'headless',
browserName: 'chromium',
channel: 'chrome',
mode: 'default',
video: false,
};
config.projects!.push({
name: 'android-native',
use: {
loopback: '10.0.2.2',
browserName: 'chromium',
},
snapshotPathTemplate: '{testDir}/{testFileDir}/{testFileName}-snapshots/{arg}-android{ext}',
testDir: path.join(testDir, 'android'),
metadata,
});
config.projects!.push({
name: 'android-page',
use: {
loopback: '10.0.2.2',
browserName: 'chromium',
},
snapshotPathTemplate: '{testDir}/{testFileDir}/{testFileName}-snapshots/{arg}-android{ext}',
testDir: path.join(testDir, 'page'),
metadata,
});
export default config;

View File

@@ -0,0 +1,106 @@
/**
* Copyright 2020 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 { androidTest as test, expect } from './androidTest';
test('androidDevice.webView', async function({ androidDevice }) {
expect(androidDevice.webViews().length).toBe(0);
await androidDevice.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
const webview = await androidDevice.webView({ pkg: 'org.chromium.webview_shell' });
expect(webview.pkg()).toBe('org.chromium.webview_shell');
expect(androidDevice.webViews().length).toBe(1);
});
test('webView.page', async function({ androidDevice }) {
expect(androidDevice.webViews().length).toBe(0);
await androidDevice.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
const webview = await androidDevice.webView({ pkg: 'org.chromium.webview_shell' });
const page = await webview.page();
expect(page.url()).toBe('about:blank');
});
test('should navigate page internally', async function({ androidDevice }) {
expect(androidDevice.webViews().length).toBe(0);
await androidDevice.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
const webview = await androidDevice.webView({ pkg: 'org.chromium.webview_shell' });
const page = await webview.page();
await page.goto('data:text/html,<title>Hello world!</title>');
expect(await page.title()).toBe('Hello world!');
});
test('should navigate page externally', async function({ androidDevice }) {
expect(androidDevice.webViews().length).toBe(0);
await androidDevice.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
const webview = await androidDevice.webView({ pkg: 'org.chromium.webview_shell' });
const page = await webview.page();
await androidDevice.fill({ res: 'org.chromium.webview_shell:id/url_field' }, 'data:text/html,<title>Hello world!</title>', { timeout: test.info().timeout });
await Promise.all([
page.waitForNavigation(),
androidDevice.press({ res: 'org.chromium.webview_shell:id/url_field' }, 'Enter')
]);
expect(await page.title()).toBe('Hello world!');
});
test('select webview from socketName', async function({ androidDevice }) {
const context = await androidDevice.launchBrowser();
const newPage = await context.newPage();
await newPage.goto('about:blank');
const webview = await androidDevice.webView({ socketName: 'webview_devtools_remote_playwright_test' });
expect(webview.pkg()).toBe('');
expect(webview.pid()).toBe(-1);
const page = await webview.page();
expect(page.url()).toBe('about:blank');
await newPage.close();
await context.close();
});
// Requires a newer WebView version with
// https://chromium-review.googlesource.com/c/chromium/src/+/6411892
test.fail('should be able to receive webView cookies', {
annotation: {
type: 'issue',
description: 'https://github.com/microsoft/playwright/issues/35392',
}
}, async function({ androidDevice, server }) {
expect(androidDevice.webViews().length).toBe(0);
server.setRoute('/cookies', (req, res) => {
res.setHeader('Set-Cookie', 'cookie1=value1; Path=/; HttpOnly');
res.setHeader('Content-Type', 'text/html');
res.end('<html><body>hello world</body></html>');
});
await androidDevice.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity');
const webview = await androidDevice.webView({ pkg: 'org.chromium.webview_shell' });
const page = await webview.page();
await page.goto(server.CROSS_PROCESS_PREFIX + '/cookies');
const cookies = await page.context().cookies();
expect(cookies.length).toBe(1);
expect(cookies).toEqual([
{
name: 'cookie1',
value: 'value1',
domain: new URL(server.CROSS_PROCESS_PREFIX).hostname,
path: '/',
expires: -1,
httpOnly: true,
secure: false,
sameSite: 'Lax'
}
]);
await page.context().clearCookies();
});

View File

@@ -0,0 +1,362 @@
Mozilla Public License, version 2.0
1. Definitions
1.1. "Contributor"
means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.
1.5. "Incompatible With Secondary Licenses"
means
a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or
b. that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the terms of
a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in a
separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible, whether
at the time of the initial grant or subsequently, any and all of the
rights conveyed by this License.
1.10. "Modifications"
means any of the following:
a. any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered Software; or
b. any new file in Source Code Form that contains any Covered Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the License,
by the making, using, selling, offering for sale, having made, import,
or transfer of either its Contributions or its Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, "control" means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
a. for any code that a Contributor has removed from Covered Software; or
b. for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
c. under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights to
grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and
b. You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter the
recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty, or
limitations of liability) contained within the Source Code Form of the
Covered Software, except that You may alter any license notices to the
extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute,
judicial order, or regulation then You must: (a) comply with the terms of
this License to the maximum extent possible; and (b) describe the
limitations and the code they affect. Such description must be placed in a
text file included with all distributions of the Covered Software under
this License. Except to the extent prohibited by statute or regulation,
such description must be sufficiently detailed for a recipient of ordinary
skill to be able to understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing
basis, if such Contributor fails to notify You of the non-compliance by
some reasonable means prior to 60 days after You have come back into
compliance. Moreover, Your grants from a particular Contributor are
reinstated on an ongoing basis if such Contributor notifies You of the
non-compliance by some reasonable means, this is the first time You have
received notice of non-compliance with this License from such
Contributor, and You become compliant prior to 30 days after Your receipt
of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.
6. Disclaimer of Warranty
Covered Software is provided under this License on an "as is" basis,
without warranty of any kind, either expressed, implied, or statutory,
including, without limitation, warranties that the Covered Software is free
of defects, merchantable, fit for a particular purpose or non-infringing.
The entire risk as to the quality and performance of the Covered Software
is with You. Should any Covered Software prove defective in any respect,
You (not any Contributor) assume the cost of any necessary servicing,
repair, or correction. This disclaimer of warranty constitutes an essential
part of this License. No use of any Covered Software is authorized under
this License except under this disclaimer.
7. Limitation of Liability
Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from
such party's negligence to the extent applicable law prohibits such
limitation. Some jurisdictions do not allow the exclusion or limitation of
incidental or consequential damages, so this exclusion and limitation may
not apply to You.
8. Litigation
Any litigation relating to this License may be brought only in the courts
of a jurisdiction where the defendant maintains its principal place of
business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions. Nothing
in this Section shall prevent a party's ability to bring cross-claims or
counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides that
the language of a contract shall be construed against the drafter shall not
be used to construe this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses If You choose to distribute Source Code Form that is
Incompatible With Secondary Licenses under the terms of this version of
the License, the notice described in Exhibit B of this License must be
attached.
Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file,
then You may include the notice in a location (such as a LICENSE file in a
relevant directory) where a recipient would be likely to look for such a
notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
This Source Code Form is "Incompatible
With Secondary Licenses", as defined by
the Mozilla Public License, v. 2.0.

View File

@@ -0,0 +1,8 @@
Tests derived from axe-core test suite: https://github.com/dequelabs/axe-core/tree/develop/test.
Includes:
- `LICENSE`
Modified:
- `implicit-role.js` contains test cases extracted from `/test/commons/aria/implicit-role.js`
- `accessible-text.js` contains test cases extracted from `/test/commons/aria/accessible-text.js`

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,530 @@
module.exports = [
{
html: '<button id="target"></button>',
target: '#target',
role: 'button',
},
{
html: '<div id="target"></div>',
target: '#target',
role: null,
},
{
html: '<canvas id="target" aria-label="hello"></canvas>',
target: '#target',
role: null,
},
{
html: '<a id="target" href>link</a>',
target: '#target',
role: 'link',
},
{
html: '<a id="target">link</a>',
target: '#target',
role: null,
},
{
html: '<area id="target" href>link</area>',
target: '#target',
role: 'link',
},
{
html: '<area id="target">link</area>',
target: '#target',
role: null,
},
{
html: '<footer id="target"></footer>',
target: '#target',
role: 'contentinfo',
},
{
html: '<article><footer id="target"></footer></article>',
target: '#target',
role: null,
},
{
html: '<aside><footer id="target"></footer></aside>',
target: '#target',
role: null,
},
{
html: '<main><footer id="target"></footer></main>',
target: '#target',
role: null,
},
{
html: '<nav><footer id="target"></footer></nav>',
target: '#target',
role: null,
},
{
html: '<section><footer id="target"></footer></section>',
target: '#target',
role: null,
},
{
html: '<div role="article"><footer id="target"></footer></div>',
target: '#target',
role: null,
},
{
html: '<div role="complementary"><footer id="target"></footer></div>',
target: '#target',
role: null,
},
{
html: '<div role="main"><footer id="target"></footer></div>',
target: '#target',
role: null,
},
{
html: '<div role="navigation"><footer id="target"></footer></div>',
target: '#target',
role: null,
},
{
html: '<div role="region"><footer id="target"></footer></div>',
target: '#target',
role: null,
},
{
html: '<form id="target" aria-label="foo"></form>',
target: '#target',
role: 'form',
},
{
html: '<div id="foo">foo</div><form id="target" aria-labelledby="foo"></form>',
target: '#target',
role: 'form',
},
{
html: '<form id="target" title="foo"></form>',
target: '#target',
role: null,
},
{
html: '<form id="target"></form>',
target: '#target',
role: null,
},
{
html: '<header id="target"></header>',
target: '#target',
role: 'banner',
},
{
html: '<article><header id="target"></header></article>',
target: '#target',
role: null,
},
{
html: '<aside><header id="target"></header></aside>',
target: '#target',
role: null,
},
{
html: '<main><header id="target"></header></main>',
target: '#target',
role: null,
},
{
html: '<nav><header id="target"></header></nav>',
target: '#target',
role: null,
},
{
html: '<section><header id="target"></header></section>',
target: '#target',
role: null,
},
{
html: '<div role="article"><header id="target"></header></div>',
target: '#target',
role: null,
},
{
html: '<div role="complementary"><header id="target"></header></div>',
target: '#target',
role: null,
},
{
html: '<div role="main"><header id="target"></header></div>',
target: '#target',
role: null,
},
{
html: '<div role="navigation"><header id="target"></header></div>',
target: '#target',
role: null,
},
{
html: '<div role="region"><header id="target"></header></div>',
target: '#target',
role: null,
},
{
html: '<img id="target" alt="value"></img>',
target: '#target',
role: 'img',
},
{
html: '<img id="target"></img>',
target: '#target',
role: 'img',
},
{
html: '<img id="target" alt=""></img>',
target: '#target',
role: 'presentation',
},
{
html: '<img id="target" alt="" aria-label></img>',
target: '#target',
role: 'img',
},
{
html: '<img id="target" alt="" tabindex="0"></img>',
target: '#target',
role: 'img',
},
{
html: '<input id="target" type="button"/>',
target: '#target',
role: 'button',
},
{
html: '<input id="target" type="image"/>',
target: '#target',
role: 'button',
},
{
html: '<input id="target" type="reset"/>',
target: '#target',
role: 'button',
},
{
html: '<input id="target" type="submit"/>',
target: '#target',
role: 'button',
},
{
html: '<input id="target" type="checkbox"/>',
target: '#target',
role: 'checkbox',
},
{
html: '<input id="target" type="email"/>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target" type="tel"/>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target" type="text"/>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target" type="url"/>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target" type="password"/>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target" type="time"/>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target" type="date"/>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target"/>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target" list="list"/><datalist id="list"></datalist>',
target: '#target',
role: 'combobox',
},
{
html: '<input id="target" list="list"/><div id="list"></div>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target" type="password" list="list"/><datalist id="list"></datalist>',
target: '#target',
role: 'textbox',
},
{
html: '<input id="target" type="number"/>',
target: '#target',
role: 'spinbutton',
},
{
html: '<input id="target" type="radio"/>',
target: '#target',
role: 'radio',
},
{
html: '<input id="target" type="range"/>',
target: '#target',
role: 'slider',
},
{
html: '<input id="target" type="search"/>',
target: '#target',
role: 'searchbox',
},
{
html: '<input id="target" type="search" list="list"/><datalist id="list"></datalist>',
target: '#target',
role: 'combobox',
},
{
html: '<input id="target" type="invalid"/>',
target: '#target',
role: 'textbox',
},
{
html: '<section id="target" aria-label="foo"></section>',
target: '#target',
role: 'region',
},
{
html: '<div id="foo">foo</div><section id="target" aria-labelledby="foo"></section>',
target: '#target',
role: 'region',
},
{
html: '<section id="target" title="foo"></section>',
target: '#target',
role: null,
},
{
html: '<section id="target"></section>',
target: '#target',
role: null,
},
{
html: '<select id="target" multiple></select>',
target: '#target',
role: 'listbox',
},
{
html: '<select id="target" size="3"></select>',
target: '#target',
role: 'listbox',
},
{
html: '<select id="target" size="1"></select>',
target: '#target',
role: 'combobox',
},
{
html: '<select id="target"></select>',
target: '#target',
role: 'combobox',
},
// ---------- Table related cases ----------
{
html: '<table><td id="target"></td></table>',
target: '#target',
role: 'cell',
},
{
html: '<table role="grid"><td id="target"></td></table>',
target: '#target',
role: 'gridcell',
},
{
html: '<table role="treegrid"><td id="target"></td></table>',
target: '#target',
role: 'gridcell',
},
{
html: '<table><th id="target" scope="row"></th></table>',
target: '#target',
role: 'rowheader',
},
{
html: '<table><th id="target" scope="col"></th></table>',
target: '#target',
role: 'columnheader',
},
// All TH in thead row -> columnheader
{
html: '<table><thead><tr><th id="target">A</th><th>B</th></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>',
target: '#target',
role: 'columnheader',
},
{
html: '<table><thead><tr><th>A</th><th id="target">B</th></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>',
target: '#target',
role: 'columnheader',
},
// TH with TD sibling in same row -> rowheader
{
html: '<table><thead><tr><th id="target">A</th><td>B</td></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>',
target: '#target',
role: 'rowheader',
},
// TH in tbody with TD sibling -> rowheader
{
html: '<table><thead><tr><th>A</th><th>B</th></thead><tbody><tr><th id="target">1</th><td>2</td></tr><tr><td>3</td><td>4</td></tr></tbody></table>',
target: '#target',
role: 'rowheader',
},
// TH in tbody, second row, with TD sibling -> rowheader
{
html: '<table><thead><tr><th>A</th><th>B</th></thead><tbody><tr><th>1</th><td>2</td></tr><tr><th id="target">3</th><td>4</td></tr></tbody></table>',
target: '#target',
role: 'rowheader',
},
// TH with TD above and below in same column -> rowheader
{
html: '<table><thead><tr><th>A</th><th>B</th></thead><tbody><tr><td>5</td><td>6</td></tr><tr><th id="target">1</th><td>2</td></tr><tr><td>3</td><td>4</td></tr></tbody></table>',
target: '#target',
role: 'rowheader',
},
// TH only cell in row -> no role
{
html: '<table><tr><th id="target">Only</th></tr></table>',
target: '#target',
role: null,
},
// TH only cell in row, but table has multiple rows -> columnheader
{
html: '<table><tr><th id="target">Header</th></tr><tr><td>Data</td></tr></table>',
target: '#target',
role: 'columnheader',
},
// TH surrounded by other TH -> columnheader
{
html: '<table><tr><th>A</th><th id="target">B</th><th>C</th></tr></table>',
target: '#target',
role: 'columnheader',
},
// Row with first cell as TD -> rowheader
{
html: '<table><tr><td>A</td><th id="target">B</th><th>C</th></tr></table>',
target: '#target',
role: 'rowheader',
},
// Row with last cell as TD -> rowheader
{
html: '<table><tr><th>A</th><th id="target">B</th><td>C</td></tr></table>',
target: '#target',
role: 'rowheader',
},
// scope="col" -> columnheader
{
html: '<table><tr><th id="target" scope="col">A</th><td>B</td></tr></table>',
target: '#target',
role: 'columnheader',
},
// scope="row" -> rowheader
{
html: '<table><tr><th id="target" scope="row">A</th><th>B</th></tr></table>',
target: '#target',
role: 'rowheader',
},
// scope="colgroup" -> columnheader
{
html: '<table><tr><th id="target" scope="colgroup">A</th><td>B</td></tr></table>',
target: '#target',
role: 'columnheader',
},
// scope="rowgroup" -> rowheader
{
html: '<table><tr><th id="target" scope="rowgroup">A</th><th>B</th></tr></table>',
target: '#target',
role: 'rowheader',
},
];

View File

@@ -0,0 +1,10 @@
<html>
<script>
function changeBackground() {
const color = location.hash.substr(1);
document.body.style.backgroundColor = color;
}
</script>
<body onload='changeBackground()'>
</body>
</html>

View File

@@ -0,0 +1,10 @@
<div>beforeunload demo.</div>
<script>
window.addEventListener('beforeunload', event => {
// Chromium & WebKit way.
event.returnValue = 'Leave?';
// Firefox way.
event.preventDefault();
});
</script>

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,39 @@
<style>
* {
padding: 0;
margin: 0;
}
iframe {
position: absolute;
top: 0;
left: 0;
width: 500px;
height: 500px;
}
button {
position: absolute;
top: 150px;
left: 150px;
width: 200px;
height: 200px;
}
</style>
<script>
window.addEventListener('DOMContentLoaded', () => {
const iframe = document.createElement('iframe');
const url = new URL(location.href);
url.hostname = url.hostname === 'localhost' ? '127.0.0.1' : 'localhost';
url.pathname = '/grid.html';
iframe.src = url.toString();
document.body.append(iframe);
const button = document.createElement('button');
button.textContent = 'CLICK ME';
button.addEventListener('click', () => {
window.BUTTON_CLICKED = true;
}, false);
document.body.append(button);
}, false);
</script>

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<link rel='stylesheet' href='./one-style.css'>
<div>BFCached</div>
<script>
window.didShow = new Promise(f => window.addEventListener('pageshow', event => {
console.log(event);
window._persisted = !!event.persisted;
window._event = event;
f({ persisted: !!event.persisted });
}));
</script>

View File

@@ -0,0 +1,3 @@
body {
background-color: pink;
}

View File

@@ -0,0 +1,2 @@
<link rel='stylesheet' href='./one-style.css'>
<div>hello, world!</div>

View File

@@ -0,0 +1,5 @@
function callme(cb) {
return cb();
}
module.exports = callme;

View File

@@ -0,0 +1,43 @@
<html>
<script>
function changeBackground() {
const color = location.hash.substr(1);
document.body.style.backgroundColor = color;
}
</script>
<style>
body {
margin: 0;
}
.container {
display: grid;
background-color: rgb(0, 0, 0);
grid-template-columns: auto auto;
width: 100%;
height: 100%;
}
.cell {
border: none;
font-size: 30px;
text-align: center;
}
.cell.grey {
background-color: rgb(100, 100, 100);
}
.cell.red {
background-color: rgb(255, 0, 0);
}
</style>
<body>
<div class="container">
<div class="cell red"></div>
<div class="cell grey"></div>
<div class="cell grey"></div>
<div class="cell red"></div>
</div>
</body>
</html>

Binary file not shown.

View File

@@ -0,0 +1,7 @@
# Client Certificate test-certificates
Regenerate all certificates by running:
```
bash generate.sh
```

View File

@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIEizCCAnMCAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEAuxTIfOTWJzsLSYT/RXu6eUYe95oFA0gMM6pdQAws
U08ufU8S68UzBIAb6zdwDqM6LD5FqLrwaTsUW73dKefb003EgA19L3sZTHSwnSv9
g9+rnKw/8EA+1thFo7h3EfdWkO/nuxnPfEnHu5oxMk/mCu+hdjfgh01mxc00PIO/
wioxZtuhzKNIUu+qQAj70Dwbkzy3Zb1QAnj+02AUYnrVTYhusmP4pjrfYgAWU1x4
WN+XTSI27LnQHE8t8OxuICFwqEEPcJg4pCFNQgmO0gcRDbd4U7JgQ0xMXZ9na9k0
f1GOgtjKsz5IIDrAwLnrIOEXiIYlNaQ/v28BrlWytaOHGFKmDxAbGXHz1WuftmR1
vYQivC5fkXU3+QKWoGPZaLIhA7/ZOMSVgoo+Rv+mS6Mze/6LphatUMcI1oYX4ZBY
FrsVsAeAO/FPZDcwVct0bdPCRRFBQpgl6DxMyItHMexNHwURi4YHwhYiBBe+Njc1
tTh6dniA11MUVC5WmKME7CxgXxHVXE4MYcf/w1x4sOnxHneb1bCa8jOPELRc6byR
8mk23fbBP42EPkrgpCtLhbHgskLKobLFav43xaIiYFn744U7rbINI+5RfJ8BH5Kw
CB5RlAsymPxwDNcPXyyyeHEEUAQmtnJPrGPSGMN/QODgCWRXEvY556NGx0D5riu7
MXkCAwEAAaAyMDAGCSqGSIb3DQEJDjEjMCEwHwYDVR0RBBgwFoIJbG9jYWxob3N0
ggkxMjcuMC4wLjEwDQYJKoZIhvcNAQELBQADggIBAEYqpx28FFRHqXfyumTkkFb/
hrlUD9qKUYSdjpsPLFRUYiLofNlYhCtEFEuHyLkNHqLO5Z6E7yOpm/HvdXY0eBQy
tK0verggKXy8MnpLVtsFOf4DgenTwFRG3NbNk2/KynwiAwJ0iwOdDfAmwrzYFLeR
uXysPE0lGJu277akuo/PDg3QEY44iDJgI4rqtY25sR8J23M9Roa5qN4bdaXl6l10
UJhdugTG90gRFmmUVLLRa21A3j4m7pvWHu7zYJN7ylS/NQ6ZEnpNno7Ie6MLzrm6
h8MOSoxtmrXi0e3aYf7PC3u3YLAjyUzHicgMdXk8SjtUXi6l3U5hU+6WBeOKKmwa
vi+FUpRfnutkWpinNqikmMw0Sqy+bpXwbwgm2oD6driiMneBCT37gW/IyUPWVxzg
dVgeQIt3i8SMwnGUrzfVo/gqjq4qFBpzS3h9jPPrMYQN2LQdmyo13R9UH26cLGE1
cgVmqUKa11kX8353wfA36JuW5yGv2yaK4V1kwFISznMvk5AGdOHONdZOrN4sLIIY
7Npqp5AO1KdoYcNVptCA4n6mN/30fTmA/W1ajsKcfIn5RlmvdgpooKoEgaU/X9RL
d2ydIpijWbQqm+nF9skpO4jIFPfuQj6mMXCPWtsvbpHCoo0iMHHWfVFcpvsXGYN2
6ji5z3opVapp1m5uTmcA
-----END CERTIFICATE REQUEST-----

View File

@@ -0,0 +1 @@
subjectAltName=DNS:localhost,DNS:127.0.0.1

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
DjCwHSmcSUmAmx7IXfoyRQuKLeRw
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFKDCCAxCgAwIBAgIBATANBgkqhkiG9w0BAQsFADA2MRIwEAYDVQQDDAlsb2Nh
bGhvc3QxIDAeBgNVBAoMF0NsaWVudCBDZXJ0aWZpY2F0ZSBEZW1vMB4XDTI1MDcy
MTE1NTYxOVoXDTM1MDcxOTE1NTYxOVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIC
IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuxTIfOTWJzsLSYT/RXu6eUYe
95oFA0gMM6pdQAwsU08ufU8S68UzBIAb6zdwDqM6LD5FqLrwaTsUW73dKefb003E
gA19L3sZTHSwnSv9g9+rnKw/8EA+1thFo7h3EfdWkO/nuxnPfEnHu5oxMk/mCu+h
djfgh01mxc00PIO/wioxZtuhzKNIUu+qQAj70Dwbkzy3Zb1QAnj+02AUYnrVTYhu
smP4pjrfYgAWU1x4WN+XTSI27LnQHE8t8OxuICFwqEEPcJg4pCFNQgmO0gcRDbd4
U7JgQ0xMXZ9na9k0f1GOgtjKsz5IIDrAwLnrIOEXiIYlNaQ/v28BrlWytaOHGFKm
DxAbGXHz1WuftmR1vYQivC5fkXU3+QKWoGPZaLIhA7/ZOMSVgoo+Rv+mS6Mze/6L
phatUMcI1oYX4ZBYFrsVsAeAO/FPZDcwVct0bdPCRRFBQpgl6DxMyItHMexNHwUR
i4YHwhYiBBe+Njc1tTh6dniA11MUVC5WmKME7CxgXxHVXE4MYcf/w1x4sOnxHneb
1bCa8jOPELRc6byR8mk23fbBP42EPkrgpCtLhbHgskLKobLFav43xaIiYFn744U7
rbINI+5RfJ8BH5KwCB5RlAsymPxwDNcPXyyyeHEEUAQmtnJPrGPSGMN/QODgCWRX
EvY556NGx0D5riu7MXkCAwEAAaNjMGEwHwYDVR0RBBgwFoIJbG9jYWxob3N0ggkx
MjcuMC4wLjEwHQYDVR0OBBYEFIE6kbIR0PlzaJuZg52JqXuFFQHBMB8GA1UdIwQY
MBaAFPHaEfjJoIftSkHTb8mwme27LtifMA0GCSqGSIb3DQEBCwUAA4ICAQB7E57H
19qUD4DjLxJGAVpDphD8mZg9aR7bUd6laXZ12VQnn3+OrF+6JjJ2TIr8ssRkkzc6
rMhRqob+DxeB94JqlFQDmwP37wJXnuTtuGj71NHQal15b5ZB28fFdwWgUlYECWyg
sYeMK5HMnNDziniRnjPoKU6f8urmUW2G8N2SOufnRar/StY/8u24IFh/vDTVJKWB
a22pVk/PIx6JcErfMx0OJdoIUZd/C9DT/a7t+Pt+t3EPVNM2fcjs9aMcg6tlU6Tp
YwHMzkFQYmcrp2QEhwy23z2E+wnLbeHTULDsHVOLudUGDcSgkW48bPNTOtZTysQ+
P4mJf+Ju2HC/EwuVrOa14uuay9c+hC1Q1gsGbLZB8NE6jOX5QYN2a7iiUEdCdufo
wWIXEC+2dJiEji3ehwJp0q4jK15X0IOIfxLH4PholORH659DdCfpm7YAjoaPE9nr
28MMd9Lj6zWmfyeb5p0IUDpkreL2huxjXHJkmSm4dcxDxLqsP6KSPlhrPvjAVUqw
5M/jUarDAHaPLNlwqcqWODb891FIyRmc6YHtSRGujMyfJ8LRS2f9rHeyM3m2jMHf
8EahOgyQ8nvSs/a42VS97IHkGl6qufK7ZUq/VMhQRb+KbaIDN5TLtNwEQ1I40Bm9
UOoSX/uP1PstOZvf9gnYto8sf75B+PxO692uYw==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIEyzCCArOgAwIBAgIUUo60oaPj20QM6oeGSn+2CT5j7GYwDQYJKoZIhvcNAQEL
BQAwDjEMMAoGA1UEAwwDQm9iMB4XDTI1MDcyMTE1NTYyMFoXDTM1MDcxOTE1NTYy
MFowDjEMMAoGA1UEAwwDQm9iMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAzQMXYOZz3ILrbF9qpDng2pw2wJf1UFopehwaYyu7riWJ9+ADrhSnCSFBM3Sc
MBc/8dIR6etWwci8QwJ/MtvIU0yx4llq+53G+19Bc1teC6q/b4QCRDIcTGxOZoR+
jfYZVjPODEyJ5y5MZIo34ZP4bu+JnpT4W7+uojm3jOoyNPqXMcc70uAhfSKG+Jfr
wZKteA4T5VKFytVcWgh4v03z8zTYeW3kD4lCsongBz6yu2dn3D6XMROnxiPwi+IR
QqX1pwnJ0UA3CTeOHEw1jA3koxWIIg44PWaPaCj9Udrhf4ew00XLPWVZP8T5rVf8
yUfecWQCR7FueJFqoLhPMMFi17rYmGZUvw3/YkXBjay4Q9e+G2WS3Xk8u+I1sCuV
BJNBRv9DqtMC9D/N9NI8GkLrXwZmk82SXG+cQ0TSkNUHYI/03YKoqsn5H8PsG7Tc
+Y2Ca6TaCWims7lvOg7U0E6lu2h5NGcdWHFPJ9qfe+xho/yfYYwGqEKanGAu1kd5
SbIaX6/YiM5/Pp/96MeRNrB9kLzDnZTNuGtdCawVFgbkWmfX2Z6/a0d6SvZGDzBx
xTVZRB0my01E1FP53MS8YRH98HUjGEwNRVq2e1W+aXldKppgZ85GZD3l2YTeuI0i
PJCDUzQiaWzFtWc8s13YQ1HLCOyOXF7QqMyNCiLGb4xQ56kCAwEAAaMhMB8wHQYD
VR0OBBYEFMqdCDxkZm8HxNI4MLLveAVTdH7UMA0GCSqGSIb3DQEBCwUAA4ICAQAB
MKd3WEJ8zI51FuyeTcMq6L1zk2vmKTFg6T7HZJhNZoD1AYvvsKJ8mrqeSwhxqjlE
0H2FGLY+Z8Fw3+TE1QuvTuz3gwRI+yzBEyqi/fEGCGrhOVcWaXGgLCtWG+BA4Su8
HenK97/n3OnXUnBozRPZMH02IaLrOiEGbpaabXKCCabpm5U1oGq437e3SeAeIL7U
WxuHhHBx0yo9j7ACaCL6mz8xpk8NaRZpPy22MTlrPKwbOK2eYf3Jy5fHa/f6edTs
KqZewI7t4oe/OqKdjyTgGYkjTE3Xcmo2T/fmcAeEP3HJX267kCzBi5J3McwonWxD
N8zz9qKSf5YGQy140eEOTjjESwlPz6zfrTW92YdCIr63k9UCDL2HGQTRSxB6g4BQ
loVzKS9/BKhulGqvSGvEoj6D+qG/PgFlBtJoE71X+vSIxvdbnOVmOi/l+NGNuP1Z
nwnDtZWp4BKshhSKvqeOI+EyNMQ4FL20S4w8T+LR873jKrbd2MEuAsJiygWh+/ZJ
haHTEhFxvH/a4i8gb/SGZlFB6oyPJ+XM5kZo4fcp7PnzxhYrIaEpPq+AR/3657hm
AajXpS5lTCkNJc85QeHHj/0geDsOvfK4XUj2lgaJ0gXpgsoxnSCSq6Xox6ZqAVON
0ra1KkGBTQH+5DxJ2Gp1UBaucrLYZTfXuJ8fPYeeNQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIEUzCCAjsCAQAwDjEMMAoGA1UEAwwDQm9iMIICIjANBgkqhkiG9w0BAQEFAAOC
Ag8AMIICCgKCAgEAzQMXYOZz3ILrbF9qpDng2pw2wJf1UFopehwaYyu7riWJ9+AD
rhSnCSFBM3ScMBc/8dIR6etWwci8QwJ/MtvIU0yx4llq+53G+19Bc1teC6q/b4QC
RDIcTGxOZoR+jfYZVjPODEyJ5y5MZIo34ZP4bu+JnpT4W7+uojm3jOoyNPqXMcc7
0uAhfSKG+JfrwZKteA4T5VKFytVcWgh4v03z8zTYeW3kD4lCsongBz6yu2dn3D6X
MROnxiPwi+IRQqX1pwnJ0UA3CTeOHEw1jA3koxWIIg44PWaPaCj9Udrhf4ew00XL
PWVZP8T5rVf8yUfecWQCR7FueJFqoLhPMMFi17rYmGZUvw3/YkXBjay4Q9e+G2WS
3Xk8u+I1sCuVBJNBRv9DqtMC9D/N9NI8GkLrXwZmk82SXG+cQ0TSkNUHYI/03YKo
qsn5H8PsG7Tc+Y2Ca6TaCWims7lvOg7U0E6lu2h5NGcdWHFPJ9qfe+xho/yfYYwG
qEKanGAu1kd5SbIaX6/YiM5/Pp/96MeRNrB9kLzDnZTNuGtdCawVFgbkWmfX2Z6/
a0d6SvZGDzBxxTVZRB0my01E1FP53MS8YRH98HUjGEwNRVq2e1W+aXldKppgZ85G
ZD3l2YTeuI0iPJCDUzQiaWzFtWc8s13YQ1HLCOyOXF7QqMyNCiLGb4xQ56kCAwEA
AaAAMA0GCSqGSIb3DQEBCwUAA4ICAQAn/ZI7IkBUEfhZHefwtF+QHCyxSEKvqwHq
fSqKVdarBPz8Ik8m3icj8R/DcS3y5jgzx3x8bXQoDpgsAQgeb825NRv2wAQAGoH1
8vh204lTyjqzrgtK7eQeQDc7fjeigIkxQsAK9zk4BaFUWp0wEC0RLVAgvlQTl7vu
n1jSSrhK8tvGy62/cIxZfwD0bAMHlW4m1A4fUuSGWQX2KldgA8tnmT6wx0If/nKb
VB68AMbyMHUeb32v9wEvx2nHlwMjqNFeg7vYyJXOfBdDILUl+OTBoQY1X+jSx5iM
txTzmA8Hcgx0Fq+BnbQuZCLqFpNWEfenAtQtaAFuJwMiKCf6kgbqkDVShJkmt+vC
j3dcsVMZDsdMk4qRpiJhaTQOYmsMGCj4uoDpFGjwPoUwlDkjYgHAAsm9uCkshc+m
WZO7I6Z3Tbi3XskJvAMc3dTWjtc6nApEtr/mn8LcETfOp7RRSfjllj6ijWUrVwUy
BpzU9C/zLTkhFX0DVDCIV+jEefF8JPfzSKLgXyRbInTz1/6/sKXtswXW0NjzqLMI
C9ggMBhOiDv9KJn3G/mY4CqIfo9KMzF+++4t+wdXTir8DWNlMUAn1vlBwxZAgKCM
GonVExBU0VIGCpyTRLkesEHnPMgybP6gLzP3++54x288OS5JwuPPtkDcsBHUjTq8
HxTJvUul/Q==
-----END CERTIFICATE REQUEST-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
v3/WVVAXEcIowL3T4jzJ0RLdf1qE8Bc=
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIFAzCCAuugAwIBAgIBATANBgkqhkiG9w0BAQsFADA2MRIwEAYDVQQDDAlsb2Nh
bGhvc3QxIDAeBgNVBAoMF0NsaWVudCBDZXJ0aWZpY2F0ZSBEZW1vMB4XDTI1MDcy
MTE1NTYxOFoXDTM1MDcxOTE1NTYxOFowEDEOMAwGA1UEAwwFQWxpY2UwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC4ggn74iAHLgOWOiOvB2CPe+Hr7W6S
TYJLZOoqPdh7mv7QGm8cYxfD+26p13aEaW4/qn45losWdEPPy2ZiVIF+kcOP0R4A
qsB0w9UHT4WSzCWtDqs8ywDMJ6tHge0++8S1bTpdutn/m8DPnKtkD9RQUzLFmGDO
+mB08Xu+egTzJvURbHXRJ27E+CXUXLEHbAJd8EKjJiQYXhcj4lzUXOUg+xkpPAGe
1dgQ6BDkv3xq/81S9NTIT5YriHEm6egi9AFJLZbbZtCpRQm1MDMq7zfD7oL6ECLG
rJ/aaxLEM49gMdw2SscYHotVxX2OMAKgN/ytB18L/mIQ4pOWp3HJQ+nks9Zu1V8c
g7Pz5pWwjqoncbyUaBi3vGsitAot3cyLXbN9hH8zQB8QqGyNLvqQnCJOBlYxOPA8
M8NQGDThWKspcix0LhkmnYsWWt3+KEGEpFRcJCEthm/DAd1GImP7/dg1/btT/zOs
IIkIoCyBwznuR4M4XoNTbIBsiTnO/6PjOdTrjLVX7vMueTjdbCgK3VeOuwetbZ7a
Z/hvMJCjJ4wuM3l2ZyfEQlP4gJLJS3Fw2PRsySZJl9JyEzwTqYVosDF5SF8uw0HI
cFaliZCqBbgYfOiQzjIX/GiHZdor1ZrhAbO/MpSxuxGzxF7Em4n+4p816NnC9S2J
bHRetkM9P1adHwIDAQABo0IwQDAdBgNVHQ4EFgQUXhGloOgfXb0tY7HZZGil/d11
bcwwHwYDVR0jBBgwFoAU8doR+Mmgh+1KQdNvybCZ7bsu2J8wDQYJKoZIhvcNAQEL
BQADggIBADNVu8YodDjB0474ztGSjV8WO0x984WQpGG6VPIt9xnnswNM8aOZVMNC
AS12BjgviutSBUbL40xYNlytnqP0KtlgZSNpPVTGMAOoGttbgV7w46+hyBgV4hYs
PsYrxMU1/4hTW/aGnNXpWJ4VwOESknSqUudzfy1mNVaEuPoL97SCvPrlKPU6El1a
Wmove/QTKsbsjWaahqE59uClQ6CBcWbxpN5CLyIVM4c/UrsoXdwRewgXl19YFRzR
l6LXBPid4UPQqdE6XIxgsNpoTDwAyxSRMPydlulJD5sSTaXHB7h63DsT9mEydjR3
jPjhNZL5ADtDes3/UhfpXDbb8MudXdbdsHNswEl5ewAOdRXAuoaJuQ2TOnhz+cO0
oaq9X3YaWjl8SwdvZrLIHLG3jEAQYEXDR+dEtT6vs7HmReMrYhGGoCEVrjSZAaeO
9bQoSe0m8xbuSV19e5A+LZv3bcPcVOe91x/wnjVb98KRQcSQXCBE3yT5Oav/OLKZ
TrdRkKe1yyPMHJiicn3pffdXuG6mIJC8HgYhvJEX/wkWf1BiyRd44dD1cgI1Ttt1
pQoapJCmjA0XHtr15o4TW6hmnrmOOYTOVCCug8h1bWscBedMgdR5Qm+umbUiuC3N
N6mxD49Sc40NCeDboX87rDiObhOXAAFsiE9o39z/tPToVa3TsJsA
-----END CERTIFICATE-----

View File

@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIEVTCCAj0CAQAwEDEOMAwGA1UEAwwFQWxpY2UwggIiMA0GCSqGSIb3DQEBAQUA
A4ICDwAwggIKAoICAQC4ggn74iAHLgOWOiOvB2CPe+Hr7W6STYJLZOoqPdh7mv7Q
Gm8cYxfD+26p13aEaW4/qn45losWdEPPy2ZiVIF+kcOP0R4AqsB0w9UHT4WSzCWt
Dqs8ywDMJ6tHge0++8S1bTpdutn/m8DPnKtkD9RQUzLFmGDO+mB08Xu+egTzJvUR
bHXRJ27E+CXUXLEHbAJd8EKjJiQYXhcj4lzUXOUg+xkpPAGe1dgQ6BDkv3xq/81S
9NTIT5YriHEm6egi9AFJLZbbZtCpRQm1MDMq7zfD7oL6ECLGrJ/aaxLEM49gMdw2
SscYHotVxX2OMAKgN/ytB18L/mIQ4pOWp3HJQ+nks9Zu1V8cg7Pz5pWwjqoncbyU
aBi3vGsitAot3cyLXbN9hH8zQB8QqGyNLvqQnCJOBlYxOPA8M8NQGDThWKspcix0
LhkmnYsWWt3+KEGEpFRcJCEthm/DAd1GImP7/dg1/btT/zOsIIkIoCyBwznuR4M4
XoNTbIBsiTnO/6PjOdTrjLVX7vMueTjdbCgK3VeOuwetbZ7aZ/hvMJCjJ4wuM3l2
ZyfEQlP4gJLJS3Fw2PRsySZJl9JyEzwTqYVosDF5SF8uw0HIcFaliZCqBbgYfOiQ
zjIX/GiHZdor1ZrhAbO/MpSxuxGzxF7Em4n+4p816NnC9S2JbHRetkM9P1adHwID
AQABoAAwDQYJKoZIhvcNAQELBQADggIBACpScaAoLAs9DuTcI5Y4dbHf7LwF4Zxx
UgPNzE1HB1Pr6NaHRiOWrlCtDEB5UwHrr0oZuRTqSEGg3Pe5Z2QtPG/sdFgfm4BP
29o6qo0CXiEVBwU7/K0/lL2/0a7uSbD0Tkw9d6Bgik7/Z5rzXZIi2vtUcrOtHskP
C+Z9w3vH9a+RnUeo52mCnRi4SaiSEnD5jvhmgaI9iF+k5pYBiMrKRj5W/F1QCkf4
7OuSK97xN0eG/I4Oxgzi/qt51ySCYZbqoh7dIpwi/a4UsK8kdzDDI1M3J7bU07cO
CJRfr0EETqCQw/gAKoag3tRFNvWQB6Z9G3Ev5jeaCLpcc32NlpN5xH3VW8A0Zb81
dn5BXkPSxjwJaD0a3cLFkfgrasoe7ZMmHrVpQDw+9USuGCYXMPzNZLEeTFbrRkUn
sqi30e28E1H69zVWj+OKzCWEH/azVlfaoVbwM+njUJDe5V09KvFtI7aZYmvLxbUX
4ifoRUVoKedyKnueVmoIG57lF2VzeEhX5YjCngxIg+YuE99HkMQAZSlS6uJcVM92
tsC/+pYECBk8ukenbxmKXROl3u4p2M1iCSL/8EOVROuyjnuzCXJZOpNptdpX4ZgL
kHP1erq7/U8ZU8HviUsfMoisagx8dA8uj/4fk0jfNxOJqlZL9eJhpgBfYHqmAz3h
m+PQVw96eeoK
-----END CERTIFICATE REQUEST-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
21eLmxOuln98Q3na7ftpAWQdyjcE6Q==
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,86 @@
# Client Certificate test-certificates
cd "$(dirname "$0")"
## Server
openssl req \
-x509 \
-newkey rsa:4096 \
-keyout server/server_key.pem \
-out server/server_cert.pem \
-nodes \
-days 3650 \
-subj "/CN=localhost/O=Client\ Certificate\ Demo" \
-addext "subjectAltName=DNS:localhost,DNS:local.playwright"
## Trusted client-certificate (server signed/valid)
mkdir -p client/trusted
# generate server-signed (valid) certificate
openssl req \
-newkey rsa:4096 \
-keyout client/trusted/key.pem \
-out client/trusted/csr.pem \
-nodes \
-days 3650 \
-subj "/CN=Alice"
# sign with server_cert.pem
openssl x509 \
-req \
-in client/trusted/csr.pem \
-CA server/server_cert.pem \
-CAkey server/server_key.pem \
-out client/trusted/cert.pem \
-set_serial 01 \
-days 3650
# create pfx
openssl pkcs12 -export -out client/trusted/cert.pfx -inkey client/trusted/key.pem -in client/trusted/cert.pem -passout pass:secure
## Trusted certificate for localhost (server signed/valid)
mkdir -p client/localhost
# generate server-signed (valid) certificate
openssl req \
-newkey rsa:4096 \
-keyout client/localhost/localhost.key \
-out client/localhost/localhost.csr \
-nodes \
-days 3650 \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,DNS:127.0.0.1"
# put extensions
echo "subjectAltName=DNS:localhost,DNS:127.0.0.1" > client/localhost/localhost.ext
# sign with server_cert.pem
openssl x509 \
-req \
-in client/localhost/localhost.csr \
-CA server/server_cert.pem \
-CAkey server/server_key.pem \
-set_serial 01 \
-out client/localhost/localhost.pem \
-days 3650 \
-extfile client/localhost/localhost.ext
## Self-signed certificate (invalid)
mkdir -p client/self-signed
openssl req \
-newkey rsa:4096 \
-keyout client/self-signed/key.pem \
-out client/self-signed/csr.pem \
-nodes \
-days 3650 \
-subj "/CN=Bob"
# sign with self-signed/key.pem
openssl x509 \
-req \
-in client/self-signed/csr.pem \
-signkey client/self-signed/key.pem \
-out client/self-signed/cert.pem \
-days 3650

View File

@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFdTCCA12gAwIBAgIUFhAlW/DnHoHOFg2CXKBAvwYN4BIwDQYJKoZIhvcNAQEL
BQAwNjESMBAGA1UEAwwJbG9jYWxob3N0MSAwHgYDVQQKDBdDbGllbnQgQ2VydGlm
aWNhdGUgRGVtbzAeFw0yNTA3MjExNTU2MThaFw0zNTA3MTkxNTU2MThaMDYxEjAQ
BgNVBAMMCWxvY2FsaG9zdDEgMB4GA1UECgwXQ2xpZW50IENlcnRpZmljYXRlIERl
bW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDYDbBlM8ILtq2xKLFU
ZwU4n7+0VHsO0skCfyNwpSZndbArjJUd/ZgFyCy5RK5Cg23KtXSMgkU6QlXOWvIr
WJ/1wAkH9tuef/JDo9NJ00jBeua7HjdudNAsz6WwXSZC+a6DhA7nVHNwuyqq1SyH
g5tuSP294EwfbEhXhaDyfXyBa4PaEmyjD2+O1NHSZ1AuUhblcUelKkZbykMvwCb7
gJVXxlm/SN0K4vOVq80dBknr785562hDFGoXFX9hd2uPCQKbWGdMca+MmRWwNM2B
CuxVoUl/Ooqmr7AdZ62lhpcqCd+todWC5GzrxwZjcIwt5P7MDvd+Ktmc8ePcZhp3
L3ddlxXNgfi+c9OnZaz1QVgEn1YlDAmHvQtj9H+v2mmawyyRycjmhIpV/eaXaJvW
A2wq+O2OERl056IjjzcXHrD6DOk7IjlTwQ87AMU4mNrCzW1LLd428OxQdGv2I4/b
nq+0snOJOrTk65upybJYMGKUuTRqfEQgv5d/923VUISC69uTq+0zVFxG3pyMJR2D
O+6xinBkp0Gk+ft9L4aaBAYXyUmi+PRSfdTfUk3yQkYefC55QTDDRK2rb7JiQqzr
xhJ2vBar0TqXShQKKlMaOWHd+1U2ZjuyzboDDPeACoAmUVY2IHs+P8Dem0fwuKNd
TF4jZkVQIWWLfTzzghOelmy9mwIDAQABo3sweTAdBgNVHQ4EFgQU8doR+Mmgh+1K
QdNvybCZ7bsu2J8wHwYDVR0jBBgwFoAU8doR+Mmgh+1KQdNvybCZ7bsu2J8wDwYD
VR0TAQH/BAUwAwEB/zAmBgNVHREEHzAdgglsb2NhbGhvc3SCEGxvY2FsLnBsYXl3
cmlnaHQwDQYJKoZIhvcNAQELBQADggIBAH1/6Sp4dW96yvwi9ptgVRYfRSRWfYYy
2nU6kJ1DPOW7hTPf2wLf6Z2KqiJXn8tECHfM4pnPSgDhtZHDDHAu9l7Diqzk/NIl
AblRs++4vSKdnCx1uh3EFLjIMmHa/cRUzfuR+oGfri3v7jgTBV6UJJQ0pMqIDk/P
VEOWWukllru40M8Rwy4F6LmpwIWMtNDxmhtXSbQJ6TZn+isNSoaWgHjQmayrVyXZ
OcNYuR8M/ECvnufuIOW53+hhwG1X0jEoBdXqqXbTKcGjA+yLHp008AAB5DNQblYm
FJ4N0v6eYLhOO0u3n0b/ZsqUkZx2h38tlZoAdJNqy+d4TE3WbGRNgNJrTjAOzpPL
cQ5RNr3dDsUDFPnCoK3LUf9BWerARoDt+bbrM/VqvWH/0uqaU0/vo8IchSyQ9wGv
SwrWLJU32HQUJ2VQP/m4ADf3X2Ozj+e8bBf7XPPD8KDyL4aR0KuYzrsOnhFlBkHD
PtNjc7SgiE7AZe1WOEmhBQcr+vI6S8qFTurTntCBkvrFgYBAIIhK2XwFN5sFtByr
GCB67NQMp37g2qFNYi8EmKQvPLpAcC3Je5PvHFSj2y9Z14FclGoxjU50SlH9/A5I
iHGcIVjCv9NhNDFAwakF/sTnrpT/FIS7tm9GwoJGWCdYg4pl72WYCW6hJBG+XY7G
t3jt9TP8623D
-----END CERTIFICATE-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
dvQgA6dBjtYg5cQMHNbnfT3j3WzyQg==
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,596 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
@font-face {
font-family: "codicon";
src: url("codicon.ttf") format("truetype");
}
.codicon {
font: normal normal normal 16px/1 codicon;
flex: none;
display: inline-block;
text-decoration: none;
text-rendering: auto;
text-align: center;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.codicon-add:before { content: '\ea60'; }
.codicon-plus:before { content: '\ea60'; }
.codicon-gist-new:before { content: '\ea60'; }
.codicon-repo-create:before { content: '\ea60'; }
.codicon-lightbulb:before { content: '\ea61'; }
.codicon-light-bulb:before { content: '\ea61'; }
.codicon-repo:before { content: '\ea62'; }
.codicon-repo-delete:before { content: '\ea62'; }
.codicon-gist-fork:before { content: '\ea63'; }
.codicon-repo-forked:before { content: '\ea63'; }
.codicon-git-pull-request:before { content: '\ea64'; }
.codicon-git-pull-request-abandoned:before { content: '\ea64'; }
.codicon-record-keys:before { content: '\ea65'; }
.codicon-keyboard:before { content: '\ea65'; }
.codicon-tag:before { content: '\ea66'; }
.codicon-git-pull-request-label:before { content: '\ea66'; }
.codicon-tag-add:before { content: '\ea66'; }
.codicon-tag-remove:before { content: '\ea66'; }
.codicon-person:before { content: '\ea67'; }
.codicon-person-follow:before { content: '\ea67'; }
.codicon-person-outline:before { content: '\ea67'; }
.codicon-person-filled:before { content: '\ea67'; }
.codicon-git-branch:before { content: '\ea68'; }
.codicon-git-branch-create:before { content: '\ea68'; }
.codicon-git-branch-delete:before { content: '\ea68'; }
.codicon-source-control:before { content: '\ea68'; }
.codicon-mirror:before { content: '\ea69'; }
.codicon-mirror-public:before { content: '\ea69'; }
.codicon-star:before { content: '\ea6a'; }
.codicon-star-add:before { content: '\ea6a'; }
.codicon-star-delete:before { content: '\ea6a'; }
.codicon-star-empty:before { content: '\ea6a'; }
.codicon-comment:before { content: '\ea6b'; }
.codicon-comment-add:before { content: '\ea6b'; }
.codicon-alert:before { content: '\ea6c'; }
.codicon-warning:before { content: '\ea6c'; }
.codicon-search:before { content: '\ea6d'; }
.codicon-search-save:before { content: '\ea6d'; }
.codicon-log-out:before { content: '\ea6e'; }
.codicon-sign-out:before { content: '\ea6e'; }
.codicon-log-in:before { content: '\ea6f'; }
.codicon-sign-in:before { content: '\ea6f'; }
.codicon-eye:before { content: '\ea70'; }
.codicon-eye-unwatch:before { content: '\ea70'; }
.codicon-eye-watch:before { content: '\ea70'; }
.codicon-circle-filled:before { content: '\ea71'; }
.codicon-primitive-dot:before { content: '\ea71'; }
.codicon-close-dirty:before { content: '\ea71'; }
.codicon-debug-breakpoint:before { content: '\ea71'; }
.codicon-debug-breakpoint-disabled:before { content: '\ea71'; }
.codicon-debug-hint:before { content: '\ea71'; }
.codicon-terminal-decoration-success:before { content: '\ea71'; }
.codicon-primitive-square:before { content: '\ea72'; }
.codicon-edit:before { content: '\ea73'; }
.codicon-pencil:before { content: '\ea73'; }
.codicon-info:before { content: '\ea74'; }
.codicon-issue-opened:before { content: '\ea74'; }
.codicon-gist-private:before { content: '\ea75'; }
.codicon-git-fork-private:before { content: '\ea75'; }
.codicon-lock:before { content: '\ea75'; }
.codicon-mirror-private:before { content: '\ea75'; }
.codicon-close:before { content: '\ea76'; }
.codicon-remove-close:before { content: '\ea76'; }
.codicon-x:before { content: '\ea76'; }
.codicon-repo-sync:before { content: '\ea77'; }
.codicon-sync:before { content: '\ea77'; }
.codicon-clone:before { content: '\ea78'; }
.codicon-desktop-download:before { content: '\ea78'; }
.codicon-beaker:before { content: '\ea79'; }
.codicon-microscope:before { content: '\ea79'; }
.codicon-vm:before { content: '\ea7a'; }
.codicon-device-desktop:before { content: '\ea7a'; }
.codicon-file:before { content: '\ea7b'; }
.codicon-file-text:before { content: '\ea7b'; }
.codicon-more:before { content: '\ea7c'; }
.codicon-ellipsis:before { content: '\ea7c'; }
.codicon-kebab-horizontal:before { content: '\ea7c'; }
.codicon-mail-reply:before { content: '\ea7d'; }
.codicon-reply:before { content: '\ea7d'; }
.codicon-organization:before { content: '\ea7e'; }
.codicon-organization-filled:before { content: '\ea7e'; }
.codicon-organization-outline:before { content: '\ea7e'; }
.codicon-new-file:before { content: '\ea7f'; }
.codicon-file-add:before { content: '\ea7f'; }
.codicon-new-folder:before { content: '\ea80'; }
.codicon-file-directory-create:before { content: '\ea80'; }
.codicon-trash:before { content: '\ea81'; }
.codicon-trashcan:before { content: '\ea81'; }
.codicon-history:before { content: '\ea82'; }
.codicon-clock:before { content: '\ea82'; }
.codicon-folder:before { content: '\ea83'; }
.codicon-file-directory:before { content: '\ea83'; }
.codicon-symbol-folder:before { content: '\ea83'; }
.codicon-logo-github:before { content: '\ea84'; }
.codicon-mark-github:before { content: '\ea84'; }
.codicon-github:before { content: '\ea84'; }
.codicon-terminal:before { content: '\ea85'; }
.codicon-console:before { content: '\ea85'; }
.codicon-repl:before { content: '\ea85'; }
.codicon-zap:before { content: '\ea86'; }
.codicon-symbol-event:before { content: '\ea86'; }
.codicon-error:before { content: '\ea87'; }
.codicon-stop:before { content: '\ea87'; }
.codicon-variable:before { content: '\ea88'; }
.codicon-symbol-variable:before { content: '\ea88'; }
.codicon-array:before { content: '\ea8a'; }
.codicon-symbol-array:before { content: '\ea8a'; }
.codicon-symbol-module:before { content: '\ea8b'; }
.codicon-symbol-package:before { content: '\ea8b'; }
.codicon-symbol-namespace:before { content: '\ea8b'; }
.codicon-symbol-object:before { content: '\ea8b'; }
.codicon-symbol-method:before { content: '\ea8c'; }
.codicon-symbol-function:before { content: '\ea8c'; }
.codicon-symbol-constructor:before { content: '\ea8c'; }
.codicon-symbol-boolean:before { content: '\ea8f'; }
.codicon-symbol-null:before { content: '\ea8f'; }
.codicon-symbol-numeric:before { content: '\ea90'; }
.codicon-symbol-number:before { content: '\ea90'; }
.codicon-symbol-structure:before { content: '\ea91'; }
.codicon-symbol-struct:before { content: '\ea91'; }
.codicon-symbol-parameter:before { content: '\ea92'; }
.codicon-symbol-type-parameter:before { content: '\ea92'; }
.codicon-symbol-key:before { content: '\ea93'; }
.codicon-symbol-text:before { content: '\ea93'; }
.codicon-symbol-reference:before { content: '\ea94'; }
.codicon-go-to-file:before { content: '\ea94'; }
.codicon-symbol-enum:before { content: '\ea95'; }
.codicon-symbol-value:before { content: '\ea95'; }
.codicon-symbol-ruler:before { content: '\ea96'; }
.codicon-symbol-unit:before { content: '\ea96'; }
.codicon-activate-breakpoints:before { content: '\ea97'; }
.codicon-archive:before { content: '\ea98'; }
.codicon-arrow-both:before { content: '\ea99'; }
.codicon-arrow-down:before { content: '\ea9a'; }
.codicon-arrow-left:before { content: '\ea9b'; }
.codicon-arrow-right:before { content: '\ea9c'; }
.codicon-arrow-small-down:before { content: '\ea9d'; }
.codicon-arrow-small-left:before { content: '\ea9e'; }
.codicon-arrow-small-right:before { content: '\ea9f'; }
.codicon-arrow-small-up:before { content: '\eaa0'; }
.codicon-arrow-up:before { content: '\eaa1'; }
.codicon-bell:before { content: '\eaa2'; }
.codicon-bold:before { content: '\eaa3'; }
.codicon-book:before { content: '\eaa4'; }
.codicon-bookmark:before { content: '\eaa5'; }
.codicon-debug-breakpoint-conditional-unverified:before { content: '\eaa6'; }
.codicon-debug-breakpoint-conditional:before { content: '\eaa7'; }
.codicon-debug-breakpoint-conditional-disabled:before { content: '\eaa7'; }
.codicon-debug-breakpoint-data-unverified:before { content: '\eaa8'; }
.codicon-debug-breakpoint-data:before { content: '\eaa9'; }
.codicon-debug-breakpoint-data-disabled:before { content: '\eaa9'; }
.codicon-debug-breakpoint-log-unverified:before { content: '\eaaa'; }
.codicon-debug-breakpoint-log:before { content: '\eaab'; }
.codicon-debug-breakpoint-log-disabled:before { content: '\eaab'; }
.codicon-briefcase:before { content: '\eaac'; }
.codicon-broadcast:before { content: '\eaad'; }
.codicon-browser:before { content: '\eaae'; }
.codicon-bug:before { content: '\eaaf'; }
.codicon-calendar:before { content: '\eab0'; }
.codicon-case-sensitive:before { content: '\eab1'; }
.codicon-check:before { content: '\eab2'; }
.codicon-checklist:before { content: '\eab3'; }
.codicon-chevron-down:before { content: '\eab4'; }
.codicon-chevron-left:before { content: '\eab5'; }
.codicon-chevron-right:before { content: '\eab6'; }
.codicon-chevron-up:before { content: '\eab7'; }
.codicon-chrome-close:before { content: '\eab8'; }
.codicon-chrome-maximize:before { content: '\eab9'; }
.codicon-chrome-minimize:before { content: '\eaba'; }
.codicon-chrome-restore:before { content: '\eabb'; }
.codicon-circle-outline:before { content: '\eabc'; }
.codicon-circle:before { content: '\eabc'; }
.codicon-debug-breakpoint-unverified:before { content: '\eabc'; }
.codicon-terminal-decoration-incomplete:before { content: '\eabc'; }
.codicon-circle-slash:before { content: '\eabd'; }
.codicon-circuit-board:before { content: '\eabe'; }
.codicon-clear-all:before { content: '\eabf'; }
.codicon-clippy:before { content: '\eac0'; }
.codicon-close-all:before { content: '\eac1'; }
.codicon-cloud-download:before { content: '\eac2'; }
.codicon-cloud-upload:before { content: '\eac3'; }
.codicon-code:before { content: '\eac4'; }
.codicon-collapse-all:before { content: '\eac5'; }
.codicon-color-mode:before { content: '\eac6'; }
.codicon-comment-discussion:before { content: '\eac7'; }
.codicon-credit-card:before { content: '\eac9'; }
.codicon-dash:before { content: '\eacc'; }
.codicon-dashboard:before { content: '\eacd'; }
.codicon-database:before { content: '\eace'; }
.codicon-debug-continue:before { content: '\eacf'; }
.codicon-debug-disconnect:before { content: '\ead0'; }
.codicon-debug-pause:before { content: '\ead1'; }
.codicon-debug-restart:before { content: '\ead2'; }
.codicon-debug-start:before { content: '\ead3'; }
.codicon-debug-step-into:before { content: '\ead4'; }
.codicon-debug-step-out:before { content: '\ead5'; }
.codicon-debug-step-over:before { content: '\ead6'; }
.codicon-debug-stop:before { content: '\ead7'; }
.codicon-debug:before { content: '\ead8'; }
.codicon-device-camera-video:before { content: '\ead9'; }
.codicon-device-camera:before { content: '\eada'; }
.codicon-device-mobile:before { content: '\eadb'; }
.codicon-diff-added:before { content: '\eadc'; }
.codicon-diff-ignored:before { content: '\eadd'; }
.codicon-diff-modified:before { content: '\eade'; }
.codicon-diff-removed:before { content: '\eadf'; }
.codicon-diff-renamed:before { content: '\eae0'; }
.codicon-diff:before { content: '\eae1'; }
.codicon-diff-sidebyside:before { content: '\eae1'; }
.codicon-discard:before { content: '\eae2'; }
.codicon-editor-layout:before { content: '\eae3'; }
.codicon-empty-window:before { content: '\eae4'; }
.codicon-exclude:before { content: '\eae5'; }
.codicon-extensions:before { content: '\eae6'; }
.codicon-eye-closed:before { content: '\eae7'; }
.codicon-file-binary:before { content: '\eae8'; }
.codicon-file-code:before { content: '\eae9'; }
.codicon-file-media:before { content: '\eaea'; }
.codicon-file-pdf:before { content: '\eaeb'; }
.codicon-file-submodule:before { content: '\eaec'; }
.codicon-file-symlink-directory:before { content: '\eaed'; }
.codicon-file-symlink-file:before { content: '\eaee'; }
.codicon-file-zip:before { content: '\eaef'; }
.codicon-files:before { content: '\eaf0'; }
.codicon-filter:before { content: '\eaf1'; }
.codicon-flame:before { content: '\eaf2'; }
.codicon-fold-down:before { content: '\eaf3'; }
.codicon-fold-up:before { content: '\eaf4'; }
.codicon-fold:before { content: '\eaf5'; }
.codicon-folder-active:before { content: '\eaf6'; }
.codicon-folder-opened:before { content: '\eaf7'; }
.codicon-gear:before { content: '\eaf8'; }
.codicon-gift:before { content: '\eaf9'; }
.codicon-gist-secret:before { content: '\eafa'; }
.codicon-gist:before { content: '\eafb'; }
.codicon-git-commit:before { content: '\eafc'; }
.codicon-git-compare:before { content: '\eafd'; }
.codicon-compare-changes:before { content: '\eafd'; }
.codicon-git-merge:before { content: '\eafe'; }
.codicon-github-action:before { content: '\eaff'; }
.codicon-github-alt:before { content: '\eb00'; }
.codicon-globe:before { content: '\eb01'; }
.codicon-grabber:before { content: '\eb02'; }
.codicon-graph:before { content: '\eb03'; }
.codicon-gripper:before { content: '\eb04'; }
.codicon-heart:before { content: '\eb05'; }
.codicon-home:before { content: '\eb06'; }
.codicon-horizontal-rule:before { content: '\eb07'; }
.codicon-hubot:before { content: '\eb08'; }
.codicon-inbox:before { content: '\eb09'; }
.codicon-issue-reopened:before { content: '\eb0b'; }
.codicon-issues:before { content: '\eb0c'; }
.codicon-italic:before { content: '\eb0d'; }
.codicon-jersey:before { content: '\eb0e'; }
.codicon-json:before { content: '\eb0f'; }
.codicon-kebab-vertical:before { content: '\eb10'; }
.codicon-key:before { content: '\eb11'; }
.codicon-law:before { content: '\eb12'; }
.codicon-lightbulb-autofix:before { content: '\eb13'; }
.codicon-link-external:before { content: '\eb14'; }
.codicon-link:before { content: '\eb15'; }
.codicon-list-ordered:before { content: '\eb16'; }
.codicon-list-unordered:before { content: '\eb17'; }
.codicon-live-share:before { content: '\eb18'; }
.codicon-loading:before { content: '\eb19'; }
.codicon-location:before { content: '\eb1a'; }
.codicon-mail-read:before { content: '\eb1b'; }
.codicon-mail:before { content: '\eb1c'; }
.codicon-markdown:before { content: '\eb1d'; }
.codicon-megaphone:before { content: '\eb1e'; }
.codicon-mention:before { content: '\eb1f'; }
.codicon-milestone:before { content: '\eb20'; }
.codicon-git-pull-request-milestone:before { content: '\eb20'; }
.codicon-mortar-board:before { content: '\eb21'; }
.codicon-move:before { content: '\eb22'; }
.codicon-multiple-windows:before { content: '\eb23'; }
.codicon-mute:before { content: '\eb24'; }
.codicon-no-newline:before { content: '\eb25'; }
.codicon-note:before { content: '\eb26'; }
.codicon-octoface:before { content: '\eb27'; }
.codicon-open-preview:before { content: '\eb28'; }
.codicon-package:before { content: '\eb29'; }
.codicon-paintcan:before { content: '\eb2a'; }
.codicon-pin:before { content: '\eb2b'; }
.codicon-play:before { content: '\eb2c'; }
.codicon-run:before { content: '\eb2c'; }
.codicon-plug:before { content: '\eb2d'; }
.codicon-preserve-case:before { content: '\eb2e'; }
.codicon-preview:before { content: '\eb2f'; }
.codicon-project:before { content: '\eb30'; }
.codicon-pulse:before { content: '\eb31'; }
.codicon-question:before { content: '\eb32'; }
.codicon-quote:before { content: '\eb33'; }
.codicon-radio-tower:before { content: '\eb34'; }
.codicon-reactions:before { content: '\eb35'; }
.codicon-references:before { content: '\eb36'; }
.codicon-refresh:before { content: '\eb37'; }
.codicon-regex:before { content: '\eb38'; }
.codicon-remote-explorer:before { content: '\eb39'; }
.codicon-remote:before { content: '\eb3a'; }
.codicon-remove:before { content: '\eb3b'; }
.codicon-replace-all:before { content: '\eb3c'; }
.codicon-replace:before { content: '\eb3d'; }
.codicon-repo-clone:before { content: '\eb3e'; }
.codicon-repo-force-push:before { content: '\eb3f'; }
.codicon-repo-pull:before { content: '\eb40'; }
.codicon-repo-push:before { content: '\eb41'; }
.codicon-report:before { content: '\eb42'; }
.codicon-request-changes:before { content: '\eb43'; }
.codicon-rocket:before { content: '\eb44'; }
.codicon-root-folder-opened:before { content: '\eb45'; }
.codicon-root-folder:before { content: '\eb46'; }
.codicon-rss:before { content: '\eb47'; }
.codicon-ruby:before { content: '\eb48'; }
.codicon-save-all:before { content: '\eb49'; }
.codicon-save-as:before { content: '\eb4a'; }
.codicon-save:before { content: '\eb4b'; }
.codicon-screen-full:before { content: '\eb4c'; }
.codicon-screen-normal:before { content: '\eb4d'; }
.codicon-search-stop:before { content: '\eb4e'; }
.codicon-server:before { content: '\eb50'; }
.codicon-settings-gear:before { content: '\eb51'; }
.codicon-settings:before { content: '\eb52'; }
.codicon-shield:before { content: '\eb53'; }
.codicon-smiley:before { content: '\eb54'; }
.codicon-sort-precedence:before { content: '\eb55'; }
.codicon-split-horizontal:before { content: '\eb56'; }
.codicon-split-vertical:before { content: '\eb57'; }
.codicon-squirrel:before { content: '\eb58'; }
.codicon-star-full:before { content: '\eb59'; }
.codicon-star-half:before { content: '\eb5a'; }
.codicon-symbol-class:before { content: '\eb5b'; }
.codicon-symbol-color:before { content: '\eb5c'; }
.codicon-symbol-constant:before { content: '\eb5d'; }
.codicon-symbol-enum-member:before { content: '\eb5e'; }
.codicon-symbol-field:before { content: '\eb5f'; }
.codicon-symbol-file:before { content: '\eb60'; }
.codicon-symbol-interface:before { content: '\eb61'; }
.codicon-symbol-keyword:before { content: '\eb62'; }
.codicon-symbol-misc:before { content: '\eb63'; }
.codicon-symbol-operator:before { content: '\eb64'; }
.codicon-symbol-property:before { content: '\eb65'; }
.codicon-wrench:before { content: '\eb65'; }
.codicon-wrench-subaction:before { content: '\eb65'; }
.codicon-symbol-snippet:before { content: '\eb66'; }
.codicon-tasklist:before { content: '\eb67'; }
.codicon-telescope:before { content: '\eb68'; }
.codicon-text-size:before { content: '\eb69'; }
.codicon-three-bars:before { content: '\eb6a'; }
.codicon-thumbsdown:before { content: '\eb6b'; }
.codicon-thumbsup:before { content: '\eb6c'; }
.codicon-tools:before { content: '\eb6d'; }
.codicon-triangle-down:before { content: '\eb6e'; }
.codicon-triangle-left:before { content: '\eb6f'; }
.codicon-triangle-right:before { content: '\eb70'; }
.codicon-triangle-up:before { content: '\eb71'; }
.codicon-twitter:before { content: '\eb72'; }
.codicon-unfold:before { content: '\eb73'; }
.codicon-unlock:before { content: '\eb74'; }
.codicon-unmute:before { content: '\eb75'; }
.codicon-unverified:before { content: '\eb76'; }
.codicon-verified:before { content: '\eb77'; }
.codicon-versions:before { content: '\eb78'; }
.codicon-vm-active:before { content: '\eb79'; }
.codicon-vm-outline:before { content: '\eb7a'; }
.codicon-vm-running:before { content: '\eb7b'; }
.codicon-watch:before { content: '\eb7c'; }
.codicon-whitespace:before { content: '\eb7d'; }
.codicon-whole-word:before { content: '\eb7e'; }
.codicon-window:before { content: '\eb7f'; }
.codicon-word-wrap:before { content: '\eb80'; }
.codicon-zoom-in:before { content: '\eb81'; }
.codicon-zoom-out:before { content: '\eb82'; }
.codicon-list-filter:before { content: '\eb83'; }
.codicon-list-flat:before { content: '\eb84'; }
.codicon-list-selection:before { content: '\eb85'; }
.codicon-selection:before { content: '\eb85'; }
.codicon-list-tree:before { content: '\eb86'; }
.codicon-debug-breakpoint-function-unverified:before { content: '\eb87'; }
.codicon-debug-breakpoint-function:before { content: '\eb88'; }
.codicon-debug-breakpoint-function-disabled:before { content: '\eb88'; }
.codicon-debug-stackframe-active:before { content: '\eb89'; }
.codicon-circle-small-filled:before { content: '\eb8a'; }
.codicon-debug-stackframe-dot:before { content: '\eb8a'; }
.codicon-terminal-decoration-mark:before { content: '\eb8a'; }
.codicon-debug-stackframe:before { content: '\eb8b'; }
.codicon-debug-stackframe-focused:before { content: '\eb8b'; }
.codicon-debug-breakpoint-unsupported:before { content: '\eb8c'; }
.codicon-symbol-string:before { content: '\eb8d'; }
.codicon-debug-reverse-continue:before { content: '\eb8e'; }
.codicon-debug-step-back:before { content: '\eb8f'; }
.codicon-debug-restart-frame:before { content: '\eb90'; }
.codicon-debug-alt:before { content: '\eb91'; }
.codicon-call-incoming:before { content: '\eb92'; }
.codicon-call-outgoing:before { content: '\eb93'; }
.codicon-menu:before { content: '\eb94'; }
.codicon-expand-all:before { content: '\eb95'; }
.codicon-feedback:before { content: '\eb96'; }
.codicon-git-pull-request-reviewer:before { content: '\eb96'; }
.codicon-group-by-ref-type:before { content: '\eb97'; }
.codicon-ungroup-by-ref-type:before { content: '\eb98'; }
.codicon-account:before { content: '\eb99'; }
.codicon-git-pull-request-assignee:before { content: '\eb99'; }
.codicon-bell-dot:before { content: '\eb9a'; }
.codicon-debug-console:before { content: '\eb9b'; }
.codicon-library:before { content: '\eb9c'; }
.codicon-output:before { content: '\eb9d'; }
.codicon-run-all:before { content: '\eb9e'; }
.codicon-sync-ignored:before { content: '\eb9f'; }
.codicon-pinned:before { content: '\eba0'; }
.codicon-github-inverted:before { content: '\eba1'; }
.codicon-server-process:before { content: '\eba2'; }
.codicon-server-environment:before { content: '\eba3'; }
.codicon-pass:before { content: '\eba4'; }
.codicon-issue-closed:before { content: '\eba4'; }
.codicon-stop-circle:before { content: '\eba5'; }
.codicon-play-circle:before { content: '\eba6'; }
.codicon-record:before { content: '\eba7'; }
.codicon-debug-alt-small:before { content: '\eba8'; }
.codicon-vm-connect:before { content: '\eba9'; }
.codicon-cloud:before { content: '\ebaa'; }
.codicon-merge:before { content: '\ebab'; }
.codicon-export:before { content: '\ebac'; }
.codicon-graph-left:before { content: '\ebad'; }
.codicon-magnet:before { content: '\ebae'; }
.codicon-notebook:before { content: '\ebaf'; }
.codicon-redo:before { content: '\ebb0'; }
.codicon-check-all:before { content: '\ebb1'; }
.codicon-pinned-dirty:before { content: '\ebb2'; }
.codicon-pass-filled:before { content: '\ebb3'; }
.codicon-circle-large-filled:before { content: '\ebb4'; }
.codicon-circle-large:before { content: '\ebb5'; }
.codicon-circle-large-outline:before { content: '\ebb5'; }
.codicon-combine:before { content: '\ebb6'; }
.codicon-gather:before { content: '\ebb6'; }
.codicon-table:before { content: '\ebb7'; }
.codicon-variable-group:before { content: '\ebb8'; }
.codicon-type-hierarchy:before { content: '\ebb9'; }
.codicon-type-hierarchy-sub:before { content: '\ebba'; }
.codicon-type-hierarchy-super:before { content: '\ebbb'; }
.codicon-git-pull-request-create:before { content: '\ebbc'; }
.codicon-run-above:before { content: '\ebbd'; }
.codicon-run-below:before { content: '\ebbe'; }
.codicon-notebook-template:before { content: '\ebbf'; }
.codicon-debug-rerun:before { content: '\ebc0'; }
.codicon-workspace-trusted:before { content: '\ebc1'; }
.codicon-workspace-untrusted:before { content: '\ebc2'; }
.codicon-workspace-unknown:before { content: '\ebc3'; }
.codicon-terminal-cmd:before { content: '\ebc4'; }
.codicon-terminal-debian:before { content: '\ebc5'; }
.codicon-terminal-linux:before { content: '\ebc6'; }
.codicon-terminal-powershell:before { content: '\ebc7'; }
.codicon-terminal-tmux:before { content: '\ebc8'; }
.codicon-terminal-ubuntu:before { content: '\ebc9'; }
.codicon-terminal-bash:before { content: '\ebca'; }
.codicon-arrow-swap:before { content: '\ebcb'; }
.codicon-copy:before { content: '\ebcc'; }
.codicon-person-add:before { content: '\ebcd'; }
.codicon-filter-filled:before { content: '\ebce'; }
.codicon-wand:before { content: '\ebcf'; }
.codicon-debug-line-by-line:before { content: '\ebd0'; }
.codicon-inspect:before { content: '\ebd1'; }
.codicon-layers:before { content: '\ebd2'; }
.codicon-layers-dot:before { content: '\ebd3'; }
.codicon-layers-active:before { content: '\ebd4'; }
.codicon-compass:before { content: '\ebd5'; }
.codicon-compass-dot:before { content: '\ebd6'; }
.codicon-compass-active:before { content: '\ebd7'; }
.codicon-azure:before { content: '\ebd8'; }
.codicon-issue-draft:before { content: '\ebd9'; }
.codicon-git-pull-request-closed:before { content: '\ebda'; }
.codicon-git-pull-request-draft:before { content: '\ebdb'; }
.codicon-debug-all:before { content: '\ebdc'; }
.codicon-debug-coverage:before { content: '\ebdd'; }
.codicon-run-errors:before { content: '\ebde'; }
.codicon-folder-library:before { content: '\ebdf'; }
.codicon-debug-continue-small:before { content: '\ebe0'; }
.codicon-beaker-stop:before { content: '\ebe1'; }
.codicon-graph-line:before { content: '\ebe2'; }
.codicon-graph-scatter:before { content: '\ebe3'; }
.codicon-pie-chart:before { content: '\ebe4'; }
.codicon-bracket:before { content: '\eb0f'; }
.codicon-bracket-dot:before { content: '\ebe5'; }
.codicon-bracket-error:before { content: '\ebe6'; }
.codicon-lock-small:before { content: '\ebe7'; }
.codicon-azure-devops:before { content: '\ebe8'; }
.codicon-verified-filled:before { content: '\ebe9'; }
.codicon-newline:before { content: '\ebea'; }
.codicon-layout:before { content: '\ebeb'; }
.codicon-layout-activitybar-left:before { content: '\ebec'; }
.codicon-layout-activitybar-right:before { content: '\ebed'; }
.codicon-layout-panel-left:before { content: '\ebee'; }
.codicon-layout-panel-center:before { content: '\ebef'; }
.codicon-layout-panel-justify:before { content: '\ebf0'; }
.codicon-layout-panel-right:before { content: '\ebf1'; }
.codicon-layout-panel:before { content: '\ebf2'; }
.codicon-layout-sidebar-left:before { content: '\ebf3'; }
.codicon-layout-sidebar-right:before { content: '\ebf4'; }
.codicon-layout-statusbar:before { content: '\ebf5'; }
.codicon-layout-menubar:before { content: '\ebf6'; }
.codicon-layout-centered:before { content: '\ebf7'; }
.codicon-target:before { content: '\ebf8'; }
.codicon-indent:before { content: '\ebf9'; }
.codicon-record-small:before { content: '\ebfa'; }
.codicon-error-small:before { content: '\ebfb'; }
.codicon-terminal-decoration-error:before { content: '\ebfb'; }
.codicon-arrow-circle-down:before { content: '\ebfc'; }
.codicon-arrow-circle-left:before { content: '\ebfd'; }
.codicon-arrow-circle-right:before { content: '\ebfe'; }
.codicon-arrow-circle-up:before { content: '\ebff'; }
.codicon-layout-sidebar-right-off:before { content: '\ec00'; }
.codicon-layout-panel-off:before { content: '\ec01'; }
.codicon-layout-sidebar-left-off:before { content: '\ec02'; }
.codicon-blank:before { content: '\ec03'; }
.codicon-heart-filled:before { content: '\ec04'; }
.codicon-map:before { content: '\ec05'; }
.codicon-map-horizontal:before { content: '\ec05'; }
.codicon-fold-horizontal:before { content: '\ec05'; }
.codicon-map-filled:before { content: '\ec06'; }
.codicon-map-horizontal-filled:before { content: '\ec06'; }
.codicon-fold-horizontal-filled:before { content: '\ec06'; }
.codicon-circle-small:before { content: '\ec07'; }
.codicon-bell-slash:before { content: '\ec08'; }
.codicon-bell-slash-dot:before { content: '\ec09'; }
.codicon-comment-unresolved:before { content: '\ec0a'; }
.codicon-git-pull-request-go-to-changes:before { content: '\ec0b'; }
.codicon-git-pull-request-new-changes:before { content: '\ec0c'; }
.codicon-search-fuzzy:before { content: '\ec0d'; }
.codicon-comment-draft:before { content: '\ec0e'; }
.codicon-send:before { content: '\ec0f'; }
.codicon-sparkle:before { content: '\ec10'; }
.codicon-insert:before { content: '\ec11'; }
.codicon-mic:before { content: '\ec12'; }
.codicon-thumbsdown-filled:before { content: '\ec13'; }
.codicon-thumbsup-filled:before { content: '\ec14'; }
.codicon-coffee:before { content: '\ec15'; }
.codicon-snake:before { content: '\ec16'; }
.codicon-game:before { content: '\ec17'; }
.codicon-vr:before { content: '\ec18'; }
.codicon-chip:before { content: '\ec19'; }
.codicon-piano:before { content: '\ec1a'; }
.codicon-music:before { content: '\ec1b'; }
.codicon-mic-filled:before { content: '\ec1c'; }
.codicon-repo-fetch:before { content: '\ec1d'; }
.codicon-copilot:before { content: '\ec1e'; }
.codicon-lightbulb-sparkle:before { content: '\ec1f'; }
.codicon-robot:before { content: '\ec20'; }
.codicon-sparkle-filled:before { content: '\ec21'; }
.codicon-diff-single:before { content: '\ec22'; }
.codicon-diff-multiple:before { content: '\ec23'; }
.codicon-surround-with:before { content: '\ec24'; }
.codicon-share:before { content: '\ec25'; }
.codicon-git-stash:before { content: '\ec26'; }
.codicon-git-stash-apply:before { content: '\ec27'; }
.codicon-git-stash-pop:before { content: '\ec28'; }
.codicon-vscode:before { content: '\ec29'; }
.codicon-vscode-insiders:before { content: '\ec2a'; }
.codicon-code-oss:before { content: '\ec2b'; }
.codicon-run-coverage:before { content: '\ec2c'; }
.codicon-run-all-coverage:before { content: '\ec2d'; }
.codicon-coverage:before { content: '\ec2e'; }
.codicon-github-project:before { content: '\ec2f'; }
.codicon-map-vertical:before { content: '\ec30'; }
.codicon-fold-vertical:before { content: '\ec30'; }
.codicon-map-vertical-filled:before { content: '\ec31'; }
.codicon-fold-vertical-filled:before { content: '\ec31'; }
.codicon-go-to-search:before { content: '\ec32'; }
.codicon-percentage:before { content: '\ec33'; }
.codicon-sort-percentage:before { content: '\ec33'; }
.codicon-attach:before { content: '\ec34'; }
.codicon-git-fetch:before { content: '\f101'; }

Binary file not shown.

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>console.log test</title>
</head>
<body>
<script>
console.log('here:' + location.href)
</script>
</body>
</html>

View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<button>increment</button>
<h1>count: 0</h1>
<script>
window.count = 0;
document.querySelector('button').addEventListener('click', () => {
++window.count;
document.querySelector('h1').textContent = `count: ${window.count}`;
});
</script>

View File

@@ -0,0 +1,2 @@
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
<script type='text/javascript'>window.__inlineScriptValue = 42;</script>";

View File

@@ -0,0 +1,21 @@
<!DOCTYPE HTML>
<style>
div {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 100px;
background-color: red;
transition: all 10s;
}
.transition {
transform: rotate(360deg);
}
</style>
<div></div>
<script>
window.addEventListener('load', () => {
document.querySelector('div').classList.add('transition');
}, false);
</script>

View File

@@ -0,0 +1,95 @@
Copyright (c) 2011, Edgar Tolentino and Pablo Impallari (www.impallari.com|impallari@gmail.com),
Copyright (c) 2011, Igino Marini. (www.ikern.com|mail@iginomarini.com),
with Reserved Font Names "Dosis".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@@ -0,0 +1,26 @@
<style>
@charset "utf-8";
@namespace svg url(http://www.w3.org/2000/svg);
@font-face {
font-family: "Example Font";
src: url("./Dosis-Regular.ttf");
}
#fluffy {
border: 1px solid black;
z-index: 1;
/* -webkit-disabled-property: rgb(1, 2, 3) */
-lol-cats: "dogs" /* non-existing property */
}
@media (min-width: 1px) {
span {
-webkit-border-radius: 10px;
font-family: "Example Font";
animation: 1s identifier;
}
}
</style>
<div id="fluffy">woof!</div>
<span>fancy text</span>

View File

@@ -0,0 +1,4 @@
<style>
@media screen { div { color: green; } } </style>
<div>hello, world</div>

View File

@@ -0,0 +1,8 @@
<link rel="stylesheet" href="stylesheet1.css">
<link rel="stylesheet" href="stylesheet2.css">
<script>
window.addEventListener('DOMContentLoaded', () => {
// Force stylesheets to load.
console.log(window.getComputedStyle(document.body).color);
}, false);
</script>

View File

@@ -0,0 +1,6 @@
<style>
div { color: green; }
a { color: blue; }
</style>
<div>hello, world</div>

View File

@@ -0,0 +1,7 @@
<style>
body {
padding: 10px;
}
/*# sourceURL=nicename.css */
</style>

View File

@@ -0,0 +1,3 @@
body {
color: red;
}

View File

@@ -0,0 +1,4 @@
html {
margin: 0;
padding: 0;
}

View File

@@ -0,0 +1,7 @@
<style>
@media screen {
a { color: green; }
}
/*# sourceURL=unused.css */
</style>

View File

@@ -0,0 +1,36 @@
<script>
window.addEventListener('DOMContentLoaded', () => {
const outer = document.createElement('section');
document.body.appendChild(outer);
const root1 = document.createElement('div');
root1.setAttribute('id', 'root1');
outer.appendChild(root1);
const shadowRoot1 = root1.attachShadow({mode: 'open'});
const span1 = document.createElement('span');
span1.setAttribute('data-testid', 'foo');
span1.textContent = 'Hello from root1';
shadowRoot1.appendChild(span1);
const root2 = document.createElement('div');
shadowRoot1.appendChild(root2);
const shadowRoot2 = root2.attachShadow({mode: 'open'});
const span2 = document.createElement('span');
span2.setAttribute('data-testid', 'foo');
span2.setAttribute('id', 'target');
span2.textContent = 'Hello from root2';
shadowRoot2.appendChild(span2);
const root3 = document.createElement('div');
shadowRoot1.appendChild(root3);
const shadowRoot3 = root3.attachShadow({mode: 'open'});
const span3 = document.createElement('span');
span3.setAttribute('data-testid', 'foo');
span3.textContent = 'Hello from root3';
shadowRoot3.appendChild(span3);
const span4 = document.createElement('span');
span4.textContent = 'Hello from root3 #2';
span4.setAttribute('attr', 'value space');
shadowRoot3.appendChild(span4);
});
</script>

View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Device motion test</title>
</head>
<body>
<script>
window.result = 'Was not moved';
window.acceleration = undefined;
window.accelerationIncludingGravity = undefined;
window.rotationRate = undefined;
window.interval = undefined;
document.addEventListener('devicemotion', onMotion, false);
function onMotion(event) {
window.result = 'Moved';
window.acceleration = event.acceleration;
window.accelerationIncludingGravity = event.accelerationIncludingGravity;
window.rotationRate = event.rotationRate;
window.interval = event.interval;
}
</script>
</body>
</html>

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Device orientation test</title>
</head>
<body>
<script>
window.result = 'Was not oriented';
window.alpha = undefined;
window.beta = undefined;
window.gamma = undefined;
window.absolute = undefined;
document.addEventListener('deviceorientation', onOrientation, false);
document.addEventListener('deviceorientationabsolute', onOrientation, false);
function onOrientation(event) {
window.result = 'Oriented';
window.alpha = event.alpha;
window.beta = event.beta;
window.gamma = event.gamma;
window.absolute = event.absolute;
}
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

View File

@@ -0,0 +1,5 @@
<div id="outer" name="value"><div id="inner">Text,
more text</div></div><input id="check" type=checkbox checked foo="bar&quot;">
<input id="input"></input>
<textarea id="textarea"></textarea>
<select id="select"><option></option><option value="foo"></option></select>

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>Blob Download Example</title>
</head>
<body>
<script>
const download = (data, filename) => {
const a = document.createElement("a");
a.style = "display: none";
document.body.appendChild(a);
a.style = "display: none";
const blob = new Blob([data], { type: "octet/stream" });
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
};
const downloadIt = () => {
download("Hello world", "example.txt");
}
</script>
<a onclick="javascript:downloadIt();">Download</a>
</body>
</html>

View File

@@ -0,0 +1,57 @@
<style>
* {
box-sizing: border-box;
}
body, html {
margin: 0;
padding: 0;
}
div:not(.mouse-helper) {
margin: 0;
padding: 0;
}
#source {
color: blue;
border: 1px solid black;
position: absolute;
left: 20px;
top: 20px;
width: 200px;
height: 100px;
}
#target {
border: 1px solid black;
position: absolute;
left: 40px;
top: 200px;
width: 400px;
height: 300px;
}
</style>
<script>
function dragstart_handler(ev) {
ev.currentTarget.style.border = "dashed";
ev.dataTransfer.setData("text/plain", ev.target.id);
}
function dragover_handler(ev) {
ev.preventDefault();
}
function drop_handler(ev) {
console.log("Drop");
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
</script>
<body>
<div>
<p id="source" ondragstart="dragstart_handler(event);" draggable="true">
Select this element, drag it to the Drop Zone and then release the selection to move the element.</p>
</div>
<div id="target" ondrop="drop_handler(event);" ondragover="dragover_handler(event);">Drop Zone</div>
</body>

View File

@@ -0,0 +1,3 @@
#!/usr/bin/env node
process.exit(1);

View File

@@ -0,0 +1,31 @@
<style>
body, html {
margin: 0;
}
iframe {
width: 300px;
height: 300px;
margin: 0;
padding: 0;
border: 0;
}
</style>
<script>
function goLocal() {
document.querySelector('iframe').src = location.href.replace('dynamic-oopif.html', 'grid.html');
}
function goRemote(iframe) {
iframe = iframe || document.querySelector('iframe');
const url = new URL(location.href);
url.hostname = url.hostname === 'localhost' ? '127.0.0.1' : 'localhost';
url.pathname = '/grid.html';
iframe.src = url.toString();
}
window.addEventListener('DOMContentLoaded', () => {
const iframe = document.createElement('iframe');
goRemote(iframe);
document.body.appendChild(iframe);
}, false);
</script>

View File

@@ -0,0 +1 @@
<!DOCTYPE html>

Binary file not shown.

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html> <script>
console.error('Not a JS error');
a();
function a() {
b();
}
function b() {
c();
}
function c() {
throw new Error('Fancy error!');
}
//# sourceURL=myscript.js
</script>

View File

@@ -0,0 +1,2 @@
import num from './es6module.js';
window.__es6injected = num;

View File

@@ -0,0 +1 @@
export default 42;

View File

@@ -0,0 +1,2 @@
import num from './es6/es6module.js';
window.__es6injected = num;

View File

@@ -0,0 +1,369 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Order Confirmation</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background: white;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
padding: 40px;
max-width: 700px;
width: 100%;
}
.success-icon {
text-align: center;
margin-bottom: 20px;
}
.success-icon svg {
width: 80px;
height: 80px;
stroke: #4CAF50;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
}
h1 {
color: #333;
margin-bottom: 10px;
text-align: center;
font-size: 28px;
}
.subtitle {
text-align: center;
color: #666;
margin-bottom: 30px;
font-size: 16px;
}
.order-details {
background: #f8f9fa;
border-radius: 8px;
padding: 25px;
margin-bottom: 25px;
}
.detail-section {
margin-bottom: 20px;
}
.detail-section:last-child {
margin-bottom: 0;
}
.section-title {
font-size: 14px;
font-weight: 600;
color: #888;
text-transform: uppercase;
margin-bottom: 10px;
letter-spacing: 0.5px;
}
.detail-row {
display: flex;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid #e0e0e0;
}
.detail-row:last-child {
border-bottom: none;
}
.detail-label {
color: #555;
font-weight: 500;
}
.detail-value {
color: #333;
font-weight: 400;
text-align: right;
}
.price-section {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 25px;
}
.price-row {
display: flex;
justify-content: space-between;
padding: 8px 0;
}
.total-price {
font-size: 32px;
font-weight: 700;
margin-top: 10px;
}
.delivery-section {
background: #e3f2fd;
border-left: 4px solid #2196F3;
padding: 20px;
border-radius: 5px;
margin-bottom: 25px;
}
.delivery-section h3 {
color: #1976D2;
margin-bottom: 10px;
font-size: 18px;
}
.delivery-info {
color: #555;
line-height: 1.6;
}
.delivery-days {
font-size: 24px;
font-weight: 700;
color: #1976D2;
}
.btn-back {
width: 100%;
padding: 15px;
background: #e0e0e0;
color: #333;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.btn-back:hover {
background: #d0d0d0;
}
.error-message {
background: #ffebee;
color: #c62828;
padding: 20px;
border-radius: 8px;
border-left: 4px solid #c62828;
text-align: center;
}
</style>
</head>
<body>
<div class="container" id="content">
<!-- Content will be generated by JavaScript -->
</div>
<script>
// Product prices in USD
const productPrices = {
'table': 299.99,
'chair': 89.99,
'sofa': 699.99,
'desk': 249.99,
'cabinet': 399.99
};
// Calculate delivery days based on ZIP code
function calculateDeliveryDays(zipCode) {
if (!zipCode) return 7;
// Simple logic: use first digit of ZIP to determine delivery zone
const firstDigit = parseInt(zipCode.toString().charAt(0));
// ZIP codes 0-2: East Coast
// ZIP codes 3-5: Central
// ZIP codes 6-9: West Coast
if (firstDigit >= 0 && firstDigit <= 2) {
return 3;
} else if (firstDigit >= 3 && firstDigit <= 5) {
return 5;
} else if (firstDigit >= 6 && firstDigit <= 9) {
return 7;
}
return 7; // Default
}
// Get URL parameters
function getUrlParams() {
// Handle both URL search params and hash params
let queryString = window.location.search;
if (!queryString && window.location.hash) {
// Extract query string from hash (format: #?param=value)
queryString = window.location.hash.substring(2); // Remove '#?'
}
const params = new URLSearchParams(queryString);
return {
productType: params.get('productType'),
color: params.get('color'),
name: params.get('name'),
email: params.get('email'),
address: params.get('address'),
city: params.get('city'),
state: params.get('state'),
zipCode: params.get('zipCode')
};
}
// Format currency
function formatCurrency(amount) {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(amount);
}
// Capitalize first letter
function capitalize(str) {
if (!str) return '';
return str.charAt(0).toUpperCase() + str.slice(1);
}
// Generate confirmation page
function generateConfirmation() {
const params = getUrlParams();
const container = document.getElementById('content');
// Check if we have required parameters
if (!params.productType || !params.name) {
container.innerHTML = `
<div class="error-message">
<h2>Order Information Missing</h2>
<p>Unable to process order confirmation. Please return to the order form.</p>
<button class="btn-back" onclick="window.history.back()">Go Back</button>
</div>
`;
return;
}
// Calculate price and delivery
const basePrice = productPrices[params.productType] || 0;
const tax = basePrice * 0.08; // 8% tax
const shipping = 29.99;
const totalPrice = basePrice + tax + shipping;
const deliveryDays = calculateDeliveryDays(params.zipCode);
// Generate HTML
container.innerHTML = `
<div class="success-icon">
<svg viewBox="0 0 52 52">
<circle cx="26" cy="26" r="25"/>
<path d="M14.1 27.2l7.1 7.2 16.7-16.8"/>
</svg>
</div>
<h1>Order Confirmed!</h1>
<p class="subtitle">Thank you for your purchase, ${params.name}</p>
<div class="order-details">
<div class="detail-section">
<div class="section-title">Product Details</div>
<div class="detail-row">
<span class="detail-label">Product:</span>
<span class="detail-value">${capitalize(params.productType)}</span>
</div>
<div class="detail-row">
<span class="detail-label">Color:</span>
<span class="detail-value">${capitalize(params.color)}</span>
</div>
</div>
<div class="detail-section">
<div class="section-title">Customer Information</div>
<div class="detail-row">
<span class="detail-label">Name:</span>
<span class="detail-value">${params.name}</span>
</div>
<div class="detail-row">
<span class="detail-label">Email:</span>
<span class="detail-value">${params.email}</span>
</div>
</div>
<div class="detail-section">
<div class="section-title">Shipping Address</div>
<div class="detail-row">
<span class="detail-label">Address:</span>
<span class="detail-value">${params.address}</span>
</div>
<div class="detail-row">
<span class="detail-label">City:</span>
<span class="detail-value">${params.city}</span>
</div>
<div class="detail-row">
<span class="detail-label">State:</span>
<span class="detail-value">${params.state}</span>
</div>
<div class="detail-row">
<span class="detail-label">ZIP Code:</span>
<span class="detail-value">${params.zipCode}</span>
</div>
</div>
</div>
<div class="price-section">
<div class="price-row">
<span>Product Price:</span>
<span>${formatCurrency(basePrice)}</span>
</div>
<div class="price-row">
<span>Tax (8%):</span>
<span>${formatCurrency(tax)}</span>
</div>
<div class="price-row">
<span>Shipping:</span>
<span>${formatCurrency(shipping)}</span>
</div>
<div class="price-row total-price">
<span>Total:</span>
<span>${formatCurrency(totalPrice)}</span>
</div>
</div>
<div class="delivery-section">
<h3>📦 Estimated Delivery</h3>
<div class="delivery-info">
<p>Your order will arrive in approximately <span class="delivery-days">${deliveryDays} days</span></p>
<p style="margin-top: 10px; font-size: 14px;">We'll send tracking information to ${params.email} once your order ships.</p>
</div>
</div>
<button class="btn-back" onclick="window.location.href='./fill-form.html'">Place Another Order</button>
`;
}
// Initialize page
document.addEventListener('DOMContentLoaded', generateConfirmation);
</script>
</body>
</html>

View File

@@ -0,0 +1,186 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Order Form</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background: white;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
padding: 40px;
max-width: 600px;
width: 100%;
}
h1 {
color: #333;
margin-bottom: 30px;
text-align: center;
font-size: 28px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
color: #555;
font-weight: 600;
font-size: 14px;
}
input[type="text"],
input[type="email"],
select,
textarea {
width: 100%;
padding: 12px;
border: 2px solid #e0e0e0;
border-radius: 5px;
font-size: 14px;
transition: border-color 0.3s;
font-family: inherit;
}
input[type="text"]:focus,
input[type="email"]:focus,
select:focus,
textarea:focus {
outline: none;
border-color: #667eea;
}
textarea {
resize: vertical;
min-height: 80px;
}
.btn-order {
width: 100%;
padding: 15px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
margin-top: 10px;
}
.btn-order:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
}
.btn-order:active {
transform: translateY(0);
}
</style>
</head>
<body>
<div class="container">
<h1>Product Order Form</h1>
<form id="orderForm">
<div class="form-group">
<label for="productType">Product Type *</label>
<select id="productType" name="productType" required>
<option value="">Select a product</option>
<option value="chair">Chair</option>
<option value="sofa">Sofa</option>
<option value="desk">Desk</option>
<option value="table">Table</option>
<option value="cabinet">Cabinet</option>
</select>
</div>
<div class="form-group">
<label for="color">Color *</label>
<select id="color" name="color" required>
<option value="">Select a color</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
<option value="black">Black</option>
<option value="white">White</option>
<option value="brown">Brown</option>
</select>
</div>
<div class="form-group">
<label for="name">Full Name *</label>
<input type="text" id="name" name="name" placeholder="Enter your full name" required>
</div>
<div class="form-group">
<label for="email">Email Address *</label>
<input type="email" id="email" name="email" placeholder="your.email@example.com" required>
</div>
<div class="form-group">
<label for="address">Street Address *</label>
<input type="text" id="address" name="address" placeholder="123 Main Street" required>
</div>
<div class="form-group">
<label for="city">City *</label>
<input type="text" id="city" name="city" placeholder="City" required>
</div>
<div class="form-group">
<label for="state">State/Province *</label>
<input type="text" id="state" name="state" placeholder="State" required>
</div>
<div class="form-group">
<label for="zipCode">ZIP/Postal Code *</label>
<input type="text" id="zipCode" name="zipCode" placeholder="12345" required>
</div>
<button type="button" class="btn-order">Order</button>
</form>
</div>
<script>
const form = document.getElementById('orderForm');
const submit = () => {
location.href = './fill-form-submit.html#?' + new URLSearchParams(new FormData(form)).toString();
};
document.querySelector('.btn-order').addEventListener('click', () => {
if (form.checkValidity()) {
if (window.confirm(`Please confirm your order for a ${form.color.value} ${form.productType.value}.`))
submit();
} else {
form.reportValidity();
}
});
form.addEventListener('submit', e => {
e.preventDefault();
submit();
});
</script>
</body>

Binary file not shown.

View File

@@ -0,0 +1,3 @@
console.log('hey from the content-script');
self.thisIsTheContentScript = true;

View File

@@ -0,0 +1,2 @@
// Mock script for background extension
globalThis.MAGIC = 42;

View File

@@ -0,0 +1,14 @@
{
"name": "Simple extension",
"version": "0.1",
"background": {
"service_worker": "index.js"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"css": [],
"js": ["content-script.js"]
}],
"permissions": ["background", "activeTab"],
"manifest_version": 3
}

View File

@@ -0,0 +1,2 @@
// Each time the service worker starts (or restarts), this runs fresh.
globalThis.startTime = Date.now();

View File

@@ -0,0 +1,8 @@
{
"name": "SW Lifecycle Test Extension",
"version": "0.1",
"background": {
"service_worker": "background.js"
},
"manifest_version": 3
}

View File

@@ -0,0 +1,5 @@
console.log("Service worker script loaded");
chrome.runtime.onInstalled.addListener(() => {
console.log("Extension installed");
});

View File

@@ -0,0 +1 @@
console.log("Test console log from a third-party execution context");

View File

@@ -0,0 +1,17 @@
{
"manifest_version": 3,
"name": "Console Log Extension",
"version": "1.0",
"background": {
"service_worker": "background.js"
},
"permissions": [
"tabs"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}

View File

@@ -0,0 +1 @@
contents of the file

View File

@@ -0,0 +1 @@
contents of the file

View File

@@ -0,0 +1 @@
contents of the file

View File

@@ -0,0 +1,4 @@
<script>
window.result = (1000000.50).toLocaleString().replace(/\s/g, ' ');
window.initialNavigatorLanguage = navigator.language;
</script>

View File

@@ -0,0 +1 @@
<iframe src='./redirect-my-parent.html'></iframe>

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<link rel='stylesheet' href='./style.css'>
<script src='./script.js' type='text/javascript'></script>
<script>
fetch('./404');
</script>
<style>
body {
height: 100px;
margin: 8px;
border: 0;
background-color: #555;
}
div {
line-height: 18px;
}
</style>
<div>Hi, I'm frame</div>

View File

@@ -0,0 +1,8 @@
<frameset>
<frameset>
<frame src='./frame.html'></frame>
<frame src='about:blank'></frame>
</frameset>
<frame src='/empty.html'></frame>
<frame></frame>
</frameset>

View File

@@ -0,0 +1,6 @@
<div style="height: 1000px; width: 1000px; background: red">One</div>
<div style="height: 1000px; width: 1000px; background: blue">Two</div>
<div style="height: 1000px; width: 1000px; background: red">Three</div>
<div style="height: 1000px; width: 1000px; background: blue">Four</div>
<div style="height: 1000px; width: 1000px; background: red">Five</div>
<iframe loading="lazy" src='./frame.html'></iframe>

View File

@@ -0,0 +1,30 @@
<style>
body {
display: flex;
height: 500px;
margin: 8px;
}
body iframe {
flex-grow: 1;
flex-shrink: 1;
border: 0;
background-color: green;
}
::-webkit-scrollbar{
display: none;
}
</style>
<script>
async function attachFrame(frameId, url) {
var frame = document.createElement('iframe');
frame.src = url;
frame.id = frameId;
document.body.appendChild(frame);
await new Promise(x => frame.onload = x);
return 'kazakh';
}
</script>
<iframe src='./two-frames.html' name='2frames'></iframe>
<iframe src='./frame.html' name='aframe'></iframe>

View File

@@ -0,0 +1 @@
<iframe src='./frame.html'></iframe>

Some files were not shown because too many files have changed in this diff Show More