Skip to content

Commit

Permalink
infra(channel): wire release channel to all tests (#5820)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman committed Mar 15, 2021
1 parent a96d6a7 commit 1dd6bd3
Show file tree
Hide file tree
Showing 28 changed files with 198 additions and 108 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,12 @@ jobs:
- name: Install Chrome Stable
run: sudo apt install google-chrome-stable
- run: npm ci
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: node lib/cli/cli install-deps chromium
# This only created problems, should we move ffmpeg back into npm?
- run: node lib/cli/cli install ffmpeg
- run: mkdir -p coredumps
# Set core dump file name pattern
- run: sudo bash -c 'echo "$(pwd -P)/coredumps/core-pid_%p.dump" > /proc/sys/kernel/core_pattern'
Expand Down
13 changes: 13 additions & 0 deletions docs/src/api/class-browsertype.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,19 @@ Whether to run browser in headless mode. More details for
[Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode). Defaults to `true` unless the
[`option: devtools`] option is `true`.

### option: BrowserType.launchPersistentContext.channel
- `channel` <[string]>

Chromium distribution channel, one of
* chrome
* chrome-beta
* chrome-dev
* chrome-canary
* msedge
* msedge-beta
* msedge-dev
* msedge-canary

### option: BrowserType.launchPersistentContext.executablePath
- `executablePath` <[path]>

Expand Down
7 changes: 6 additions & 1 deletion src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ program
.description('ensure browsers necessary for this version of Playwright are installed')
.action(async function(browserType) {
try {
const allBrowsers = new Set(['chromium', 'firefox', 'webkit']);
const allBrowsers = new Set(['chromium', 'firefox', 'webkit', 'ffmpeg']);
for (const type of browserType) {
if (!allBrowsers.has(type)) {
console.log(`Invalid browser name: '${type}'. Expecting 'chromium', 'firefox' or 'webkit'.`);
Expand Down Expand Up @@ -186,6 +186,7 @@ else

type Options = {
browser: string;
channel?: string;
colorScheme?: string;
device?: string;
geolocation?: string;
Expand All @@ -209,6 +210,9 @@ async function launchContext(options: Options, headless: boolean): Promise<{ bro
validateOptions(options);
const browserType = lookupBrowserType(options);
const launchOptions: LaunchOptions = { headless };
if (options.channel)
launchOptions.channel = options.channel;

const contextOptions: BrowserContextOptions =
// Copy the device descriptor since we have to compare and modify the options.
options.device ? { ...playwright.devices[options.device] } : {};
Expand Down Expand Up @@ -452,6 +456,7 @@ function commandWithOpenOptions(command: string, description: string, options: a
result = result.option(option[0], ...option.slice(1));
return result
.option('-b, --browser <browserType>', 'browser to use, one of cr, chromium, ff, firefox, wk, webkit', 'chromium')
.option('--channel <channel>', 'Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc')
.option('--color-scheme <scheme>', 'emulate preferred color scheme, "light" or "dark"')
.option('--device <deviceName>', 'emulate device, for example "iPhone 11"')
.option('--geolocation <coordinates>', 'specify geolocation coordinates, for example "37.819722,-122.478611"')
Expand Down
1 change: 1 addition & 0 deletions src/client/browserType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel, chann
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
env: options.env ? envObjectToArray(options.env) : undefined,
channel: options.channel,
userDataDir,
};
const result = await channel.launchPersistentContext(persistentParams);
Expand Down
2 changes: 2 additions & 0 deletions src/protocol/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ export type BrowserTypeLaunchResult = {
browser: BrowserChannel,
};
export type BrowserTypeLaunchPersistentContextParams = {
channel?: string,
userDataDir: string,
sdkLanguage: string,
executablePath?: string,
Expand Down Expand Up @@ -333,6 +334,7 @@ export type BrowserTypeLaunchPersistentContextParams = {
},
};
export type BrowserTypeLaunchPersistentContextOptions = {
channel?: string,
executablePath?: string,
args?: string[],
ignoreAllDefaultArgs?: boolean,
Expand Down
1 change: 1 addition & 0 deletions src/protocol/protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ BrowserType:

launchPersistentContext:
parameters:
channel: string?
userDataDir: string
sdkLanguage: string
executablePath: string?
Expand Down
1 change: 1 addition & 0 deletions src/protocol/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
slowMo: tOptional(tNumber),
});
scheme.BrowserTypeLaunchPersistentContextParams = tObject({
channel: tOptional(tString),
userDataDir: tString,
sdkLanguage: tString,
executablePath: tOptional(tString),
Expand Down
1 change: 1 addition & 0 deletions src/server/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export type PlaywrightOptions = {
export type BrowserOptions = PlaywrightOptions & {
name: string,
isChromium: boolean,
channel?: string,
downloadsPath?: string,
headful?: boolean,
persistent?: types.BrowserContextOptions, // Undefined means no persistent context.
Expand Down
3 changes: 2 additions & 1 deletion src/server/browserType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export abstract class BrowserType extends SdkObject {
...this._playwrightOptions,
name: this._name,
isChromium: this._name === 'chromium',
channel: options.channel,
slowMo: options.slowMo,
persistent,
headful: !options.headless,
Expand Down Expand Up @@ -176,7 +177,7 @@ export abstract class BrowserType extends SdkObject {
throw new Error(errorMessageLines.join('\n'));
}

if (!executablePath) {
if (!executable) {
// We can only validate dependencies for bundled browsers.
await validateHostRequirements(this._registry, this._name);
}
Expand Down
4 changes: 4 additions & 0 deletions src/server/chromium/findChromiumChannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import path from 'path';
function darwin(channel: string): string | undefined {
switch (channel) {
case 'chrome': return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
case 'chrome-beta': return '/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta';
case 'chrome-dev': return '/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev';
case 'chrome-canary': return '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary';
case 'msedge': return '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge';
case 'msedge-beta': return '/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta';
Expand All @@ -41,6 +43,8 @@ function win32(channel: string): string | undefined {
let suffix: string | undefined;
switch (channel) {
case 'chrome': suffix = `\\Google\\Chrome\\Application\\chrome.exe`; break;
case 'chrome-beta': suffix = `\\Google\\Chrome Beta\\Application\\chrome.exe`; break;
case 'chrome-dev': suffix = `\\Google\\Chrome Dev\\Application\\chrome.exe`; break;
case 'chrome-canary': suffix = `\\Google\\Chrome SxS\\Application\\chrome.exe`; break;
case 'msedge': suffix = `\\Microsoft\\Edge\\Application\\msedge.exe`; break;
case 'msedge-beta': suffix = `\\Microsoft\\Edge Beta\\Application\\msedge.exe`; break;
Expand Down
10 changes: 4 additions & 6 deletions src/server/supplements/recorder/csharp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
formatter.add(`
await Playwright.InstallAsync();
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.${toPascal(options.browserName)}.LaunchAsync(${formatArgs(options.launchOptions)});
await using var browser = await playwright.${toPascal(options.browserName)}.LaunchAsync(${formatArgs(options.launchOptions)}
);
var context = await browser.NewContextAsync(${formatContextOptions(options.contextOptions, options.deviceName)});`);
return formatter.format();
}
Expand Down Expand Up @@ -178,10 +179,7 @@ function formatArgs(value: any, indent = ' '): string {
const tokens: string[] = [];
for (const key of keys)
tokens.push(`${keys.length !== 1 ? indent : ''}${key}: ${formatObject(value[key], indent, key)}`);
if (keys.length === 1)
return `${tokens.join(`,\n${indent}`)}`;
else
return `\n${indent}${tokens.join(`,\n${indent}`)}`;
return `\n${indent}${tokens.join(`,\n${indent}`)}`;
}
return String(value);
}
Expand Down Expand Up @@ -271,7 +269,7 @@ class CSharpFormatter {
return this._lines.map((line: string) => {
if (line === '')
return line;
if (line.startsWith('}') || line.startsWith(']') || line.includes('});'))
if (line.startsWith('}') || line.startsWith(']') || line.includes('});') || line === ');')
spaces = spaces.substring(this._baseIndent.length);

const extraSpaces = /^(for|while|if).*\(.*\)$/.test(previousLine) ? this._baseIndent : '';
Expand Down
2 changes: 2 additions & 0 deletions src/server/supplements/recorder/java.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ function formatLaunchOptions(options: any): string {
lines.push('new BrowserType.LaunchOptions()');
if (typeof options.headless === 'boolean')
lines.push(` .setHeadless(false)`);
if (options.channel)
lines.push(` .setChannel("${options.channel}")`);
return lines.join('\n');
}

Expand Down
1 change: 1 addition & 0 deletions src/server/supplements/recorder/recorderApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export class RecorderApp extends EventEmitter {
if (isUnderTest())
args.push(`--remote-debugging-port=0`);
const context = await recorderPlaywright.chromium.launchPersistentContext(internalCallMetadata(), '', {
channel: inspectedContext._browser.options.channel,
sdkLanguage: inspectedContext._options.sdkLanguage,
args,
noDefaultViewport: true,
Expand Down
6 changes: 4 additions & 2 deletions test/browsertype-basic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
import fs from 'fs';
import { it, expect } from './fixtures';

it('browserType.executablePath should work', test => {
it('browserType.executablePath should work', (test, { browserChannel }) => {
test.fixme(!!browserChannel, 'Uncomment on roll');
test.skip(Boolean(process.env.CRPATH || process.env.FFPATH || process.env.WKPATH));
}, async ({browserType}) => {
}, async ({ browserType, browserChannel }) => {
// Interesting, unless I use browserChannel in test, filter above does not work!
const executablePath = browserType.executablePath();
expect(fs.existsSync(executablePath)).toBe(true);
});
Expand Down
4 changes: 3 additions & 1 deletion test/browsertype-launch-server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ describe('launch server', (suite, { mode }) => {
await browserServer.close();
});

it('should fire close event', async ({browserType, browserOptions}) => {
it('should fire close event', (test, { browserChannel }) => {
test.fixme(!!browserChannel, 'Uncomment on roll');
}, async ({browserType, browserOptions}) => {
const browserServer = await browserType.launchServer(browserOptions);
const [result] = await Promise.all([
// @ts-expect-error The signal parameter is not documented.
Expand Down
48 changes: 29 additions & 19 deletions test/cli/cli-codegen-csharp.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,28 @@ import { folio } from './cli.fixtures';
const { it, expect } = folio;

const emptyHTML = new URL('file://' + path.join(__dirname, '..', 'assets', 'empty.html')).toString();
const launchOptions = (channel: string) => {
return channel ? `headless: false,\n channel: "${channel}"` : 'headless: false';
};

function capitalize(browserName: string): string {
return browserName[0].toUpperCase() + browserName.slice(1);
}

it('should print the correct imports and context options', async ({ browserName, runCLI }) => {
const cli = runCLI(['codegen', '--target=csharp', emptyHTML]);
it('should print the correct imports and context options', async ({ browserName, browserChannel, runCLI }) => {
const cli = runCLI(['--target=csharp', emptyHTML]);
const expectedResult = `await Playwright.InstallAsync();
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.${capitalize(browserName)}.LaunchAsync(headless: false);
await using var browser = await playwright.${capitalize(browserName)}.LaunchAsync(
${launchOptions(browserChannel)}
);
var context = await browser.NewContextAsync();`;
await cli.waitFor(expectedResult).catch(e => e);
expect(cli.text()).toContain(expectedResult);
});

it('should print the correct context options for custom settings', async ({ browserName, runCLI }) => {
it('should print the correct context options for custom settings', async ({ browserName, browserChannel, runCLI }) => {
const cli = runCLI([
'codegen',
'--color-scheme=dark',
'--geolocation=37.819722,-122.478611',
'--lang=es',
Expand All @@ -51,11 +55,12 @@ it('should print the correct context options for custom settings', async ({ brow
const expectedResult = `await Playwright.InstallAsync();
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.${capitalize(browserName)}.LaunchAsync(
headless: false,
${launchOptions(browserChannel)},
proxy: new ProxySettings
{
Server = "http://myproxy:3128",
});
}
);
var context = await browser.NewContextAsync(
viewport: new ViewportSize
{
Expand All @@ -78,21 +83,22 @@ var context = await browser.NewContextAsync(

it('should print the correct context options when using a device', (test, { browserName }) => {
test.skip(browserName !== 'chromium');
}, async ({ runCLI }) => {
const cli = runCLI(['codegen', '--device=Pixel 2', '--target=csharp', emptyHTML]);
}, async ({ browserChannel, runCLI }) => {
const cli = runCLI(['--device=Pixel 2', '--target=csharp', emptyHTML]);
const expectedResult = `await Playwright.InstallAsync();
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(headless: false);
await using var browser = await playwright.Chromium.LaunchAsync(
${launchOptions(browserChannel)}
);
var context = await browser.NewContextAsync(playwright.Devices["Pixel 2"]);`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});

it('should print the correct context options when using a device and additional options', (test, {browserName}) => {
it('should print the correct context options when using a device and additional options', (test, { browserName }) => {
test.skip(browserName !== 'webkit');
}, async ({ runCLI }) => {
}, async ({ browserChannel, runCLI }) => {
const cli = runCLI([
'codegen',
'--device=iPhone 11',
'--color-scheme=dark',
'--geolocation=37.819722,-122.478611',
Expand All @@ -106,11 +112,12 @@ it('should print the correct context options when using a device and additional
const expectedResult = `await Playwright.InstallAsync();
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Webkit.LaunchAsync(
headless: false,
${launchOptions(browserChannel)},
proxy: new ProxySettings
{
Server = "http://myproxy:3128",
});
}
);
var context = await browser.NewContextAsync(new BrowserContextOptions(playwright.Devices["iPhone 11"])
{
UserAgent = "hardkodemium",
Expand All @@ -134,15 +141,18 @@ var context = await browser.NewContextAsync(new BrowserContextOptions(playwright
expect(cli.text()).toContain(expectedResult);
});

it('should print load/save storageState', async ({ browserName, runCLI, testInfo }) => {
it('should print load/save storageState', async ({ browserName, browserChannel, runCLI, testInfo }) => {
const loadFileName = testInfo.outputPath('load.json');
const saveFileName = testInfo.outputPath('save.json');
await fs.promises.writeFile(loadFileName, JSON.stringify({ cookies: [], origins: [] }), 'utf8');
const cli = runCLI(['codegen', `--load-storage=${loadFileName}`, `--save-storage=${saveFileName}`, '--target=csharp', emptyHTML]);
const cli = runCLI([`--load-storage=${loadFileName}`, `--save-storage=${saveFileName}`, '--target=csharp', emptyHTML]);
const expectedResult1 = `await Playwright.InstallAsync();
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.${capitalize(browserName)}.LaunchAsync(headless: false);
var context = await browser.NewContextAsync(storageState: "${loadFileName}");`;
await using var browser = await playwright.${capitalize(browserName)}.LaunchAsync(
${launchOptions(browserChannel)}
);
var context = await browser.NewContextAsync(
storageState: "${loadFileName}");`;
await cli.waitFor(expectedResult1);

const expectedResult2 = `
Expand Down
17 changes: 10 additions & 7 deletions test/cli/cli-codegen-java.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,27 @@ import { folio } from './cli.fixtures';
const { it, expect } = folio;

const emptyHTML = new URL('file://' + path.join(__dirname, '..', 'assets', 'empty.html')).toString();
const launchOptions = (channel: string) => {
return channel ? `.setHeadless(false)\n .setChannel("${channel}")` : '.setHeadless(false)';
};

it('should print the correct imports and context options', async ({ runCLI, browserName }) => {
const cli = runCLI(['codegen', '--target=java', emptyHTML]);
it('should print the correct imports and context options', async ({ runCLI, browserChannel, browserName }) => {
const cli = runCLI(['--target=java', emptyHTML]);
const expectedResult = `import com.microsoft.playwright.*;
import com.microsoft.playwright.options.*;
public class Example {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.${browserName}().launch(new BrowserType.LaunchOptions()
.setHeadless(false));
${launchOptions(browserChannel)});
BrowserContext context = browser.newContext();`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});

it('should print the correct context options for custom settings', async ({ runCLI, browserName }) => {
const cli = runCLI(['codegen', '--color-scheme=light', '--target=java', emptyHTML]);
const cli = runCLI(['--color-scheme=light', '--target=java', emptyHTML]);
const expectedResult = `BrowserContext context = browser.newContext(new Browser.NewContextOptions()
.setColorScheme(ColorScheme.LIGHT));`;
await cli.waitFor(expectedResult);
Expand All @@ -48,7 +51,7 @@ it('should print the correct context options for custom settings', async ({ runC
it('should print the correct context options when using a device', (test, { browserName }) => {
test.skip(browserName !== 'chromium');
}, async ({ runCLI }) => {
const cli = runCLI(['codegen', '--device=Pixel 2', '--target=java', emptyHTML]);
const cli = runCLI(['--device=Pixel 2', '--target=java', emptyHTML]);
const expectedResult = `BrowserContext context = browser.newContext(new Browser.NewContextOptions()
.setUserAgent("Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36")
.setViewportSize(411, 731)
Expand All @@ -62,7 +65,7 @@ it('should print the correct context options when using a device', (test, { brow
it('should print the correct context options when using a device and additional options', (test, { browserName }) => {
test.skip(browserName !== 'webkit');
}, async ({ runCLI }) => {
const cli = runCLI(['codegen', '--color-scheme=light', '--device=iPhone 11', '--target=java', emptyHTML]);
const cli = runCLI(['--color-scheme=light', '--device=iPhone 11', '--target=java', emptyHTML]);
const expectedResult = `BrowserContext context = browser.newContext(new Browser.NewContextOptions()
.setColorScheme(ColorScheme.LIGHT)
.setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1")
Expand All @@ -78,7 +81,7 @@ it('should print load/save storage_state', async ({ runCLI, browserName, testInf
const loadFileName = testInfo.outputPath('load.json');
const saveFileName = testInfo.outputPath('save.json');
await fs.promises.writeFile(loadFileName, JSON.stringify({ cookies: [], origins: [] }), 'utf8');
const cli = runCLI(['codegen', `--load-storage=${loadFileName}`, `--save-storage=${saveFileName}`, '--target=java', emptyHTML]);
const cli = runCLI([`--load-storage=${loadFileName}`, `--save-storage=${saveFileName}`, '--target=java', emptyHTML]);
const expectedResult1 = `BrowserContext context = browser.newContext(new Browser.NewContextOptions()
.setStorageStatePath(Paths.get("${loadFileName}")));`;
await cli.waitFor(expectedResult1);
Expand Down
Loading

0 comments on commit 1dd6bd3

Please sign in to comment.