mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat: support npx playwright install msedge
(#6861)
This commit is contained in:
parent
46a0213769
commit
cfd49b5c01
27
.github/workflows/tests_secondary.yml
vendored
27
.github/workflows/tests_secondary.yml
vendored
@ -333,6 +333,31 @@ jobs:
|
|||||||
name: firefox-stable-mac-test-results
|
name: firefox-stable-mac-test-results
|
||||||
path: test-results
|
path: test-results
|
||||||
|
|
||||||
|
edge_stable_mac:
|
||||||
|
name: "Edge Stable (Mac)"
|
||||||
|
runs-on: macos-10.15
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 12
|
||||||
|
- run: npm ci
|
||||||
|
env:
|
||||||
|
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||||
|
- run: npm run build
|
||||||
|
- run: node lib/cli/cli install msedge
|
||||||
|
- run: npm run ctest
|
||||||
|
env:
|
||||||
|
PWTEST_CHANNEL: msedge
|
||||||
|
- run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json
|
||||||
|
if: always()
|
||||||
|
- uses: actions/upload-artifact@v1
|
||||||
|
if: ${{ always() }}
|
||||||
|
with:
|
||||||
|
name: msedge-stable-mac-test-results
|
||||||
|
path: test-results
|
||||||
|
|
||||||
|
|
||||||
edge_stable_win:
|
edge_stable_win:
|
||||||
name: "Edge Stable (Win)"
|
name: "Edge Stable (Win)"
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
@ -345,7 +370,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- run: node lib/cli/cli install ffmpeg
|
- run: node lib/cli/cli install msedge
|
||||||
- run: npm run ctest
|
- run: npm run ctest
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
|
@ -13,3 +13,4 @@ wget https://dl.google.com/linux/direct/google-chrome-beta_current_amd64.deb
|
|||||||
sudo apt-get install -y ./google-chrome-beta_current_amd64.deb
|
sudo apt-get install -y ./google-chrome-beta_current_amd64.deb
|
||||||
rm -rf ./google-chrome-beta_current_amd64.deb
|
rm -rf ./google-chrome-beta_current_amd64.deb
|
||||||
cd -
|
cd -
|
||||||
|
google-chrome-beta --version
|
||||||
|
@ -8,3 +8,6 @@ curl -o ./googlechromebeta.dmg -k https://dl.google.com/chrome/mac/beta/googlech
|
|||||||
hdiutil attach -nobrowse -quiet -noautofsck -noautoopen -mountpoint /Volumes/googlechromebeta.dmg ./googlechromebeta.dmg
|
hdiutil attach -nobrowse -quiet -noautofsck -noautoopen -mountpoint /Volumes/googlechromebeta.dmg ./googlechromebeta.dmg
|
||||||
cp -rf "/Volumes/googlechromebeta.dmg/Google Chrome Beta.app" /Applications
|
cp -rf "/Volumes/googlechromebeta.dmg/Google Chrome Beta.app" /Applications
|
||||||
hdiutil detach /Volumes/googlechromebeta.dmg
|
hdiutil detach /Volumes/googlechromebeta.dmg
|
||||||
|
rm -rf /tmp/googlechromebeta.dmg
|
||||||
|
|
||||||
|
/Applications/Google\ Chrome\ Beta.app/Contents/MacOS/Google\ Chrome\ Beta --version
|
||||||
|
@ -4,17 +4,22 @@ if ([Environment]::Is64BitProcess) {
|
|||||||
$url = 'https://dl.google.com/tag/s/dl/chrome/install/beta/googlechromebetastandaloneenterprise64.msi'
|
$url = 'https://dl.google.com/tag/s/dl/chrome/install/beta/googlechromebetastandaloneenterprise64.msi'
|
||||||
}
|
}
|
||||||
|
|
||||||
$app = Get-WmiObject -Class Win32_Product | Where-Object {
|
Write-Host "Downloading Google Chrome Beta"
|
||||||
$_.Name -match "Google Chrome Beta"
|
|
||||||
}
|
|
||||||
if ($app) {
|
|
||||||
$app.Uninstall()
|
|
||||||
}
|
|
||||||
|
|
||||||
$wc = New-Object net.webclient
|
$wc = New-Object net.webclient
|
||||||
$msiInstaller = "$env:temp\google-chrome-beta.msi"
|
$msiInstaller = "$env:temp\google-chrome-beta.msi"
|
||||||
Remove-Item $msiInstaller
|
|
||||||
$wc.Downloadfile($url, $msiInstaller)
|
$wc.Downloadfile($url, $msiInstaller)
|
||||||
|
|
||||||
|
Write-Host "Installing Google Chrome Beta"
|
||||||
$arguments = "/i `"$msiInstaller`" /quiet"
|
$arguments = "/i `"$msiInstaller`" /quiet"
|
||||||
Start-Process msiexec.exe -ArgumentList $arguments -Wait
|
Start-Process msiexec.exe -ArgumentList $arguments -Wait
|
||||||
|
Remove-Item $msiInstaller
|
||||||
|
|
||||||
|
$suffix = "\\Google\\Chrome Beta\\Application\\chrome.exe"
|
||||||
|
if (Test-Path "${env:ProgramFiles(x86)}$suffix") {
|
||||||
|
(Get-Item "${env:ProgramFiles(x86)}$suffix").VersionInfo
|
||||||
|
} elseif (Test-Path "${env:ProgramFiles}$suffix") {
|
||||||
|
(Get-Item "${env:ProgramFiles}$suffix").VersionInfo
|
||||||
|
} else {
|
||||||
|
write-host "ERROR: failed to install Google Chrome Beta"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
@ -14,3 +14,4 @@ wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
|||||||
sudo apt-get install -y ./google-chrome-stable_current_amd64.deb
|
sudo apt-get install -y ./google-chrome-stable_current_amd64.deb
|
||||||
rm -rf ./google-chrome-stable_current_amd64.deb
|
rm -rf ./google-chrome-stable_current_amd64.deb
|
||||||
cd -
|
cd -
|
||||||
|
google-chrome --version
|
||||||
|
@ -4,7 +4,9 @@ set -x
|
|||||||
|
|
||||||
rm -rf "/Applications/Google Chrome.app"
|
rm -rf "/Applications/Google Chrome.app"
|
||||||
cd /tmp
|
cd /tmp
|
||||||
curl -o ./googlechrome.dmg -k https://dl.google.com/chrome/mac/beta/googlechrome.dmg
|
curl -o ./googlechrome.dmg -k https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg
|
||||||
hdiutil attach -nobrowse -quiet -noautofsck -noautoopen -mountpoint /Volumes/googlechrome.dmg ./googlechrome.dmg
|
hdiutil attach -nobrowse -quiet -noautofsck -noautoopen -mountpoint /Volumes/googlechrome.dmg ./googlechrome.dmg
|
||||||
cp -rf "/Volumes/googlechrome.dmg/Google Chrome.app" /Applications
|
cp -rf "/Volumes/googlechrome.dmg/Google Chrome.app" /Applications
|
||||||
hdiutil detach /Volumes/googlechrome.dmg
|
hdiutil detach /Volumes/googlechrome.dmg
|
||||||
|
rm -rf /tmp/googlechrome.dmg
|
||||||
|
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
|
||||||
|
@ -1,20 +1,26 @@
|
|||||||
$url = 'https://dl.google.com/tag/s/dl/chrome/install/beta/googlechromestandaloneenterprise.msi';
|
$url = 'https://dl.google.com/tag/s/dl/chrome/install/googlechromestandaloneenterprise.msi';
|
||||||
|
|
||||||
if ([Environment]::Is64BitProcess) {
|
if ([Environment]::Is64BitProcess) {
|
||||||
$url = 'https://dl.google.com/tag/s/dl/chrome/install/beta/googlechromestandaloneenterprise64.msi'
|
$url = 'https://dl.google.com/tag/s/dl/chrome/install/googlechromestandaloneenterprise64.msi'
|
||||||
}
|
|
||||||
|
|
||||||
$app = Get-WmiObject -Class Win32_Product | Where-Object {
|
|
||||||
$_.Name -eq "Google Chrome"
|
|
||||||
}
|
|
||||||
if ($app) {
|
|
||||||
$app.Uninstall()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$wc = New-Object net.webclient
|
$wc = New-Object net.webclient
|
||||||
$msiInstaller = "$env:temp\google-chrome.msi"
|
$msiInstaller = "$env:temp\google-chrome.msi"
|
||||||
Remove-Item $msiInstaller
|
Write-Host "Downloading Google Chrome"
|
||||||
$wc.Downloadfile($url, $msiInstaller)
|
$wc.Downloadfile($url, $msiInstaller)
|
||||||
|
|
||||||
|
Write-Host "Installing Google Chrome"
|
||||||
$arguments = "/i `"$msiInstaller`" /quiet"
|
$arguments = "/i `"$msiInstaller`" /quiet"
|
||||||
Start-Process msiexec.exe -ArgumentList $arguments -Wait
|
Start-Process msiexec.exe -ArgumentList $arguments -Wait
|
||||||
|
Remove-Item $msiInstaller
|
||||||
|
|
||||||
|
|
||||||
|
$suffix = "\\Google\\Chrome\\Application\\chrome.exe"
|
||||||
|
if (Test-Path "${env:ProgramFiles(x86)}$suffix") {
|
||||||
|
(Get-Item "${env:ProgramFiles(x86)}$suffix").VersionInfo
|
||||||
|
} elseif (Test-Path "${env:ProgramFiles}$suffix") {
|
||||||
|
(Get-Item "${env:ProgramFiles}$suffix").VersionInfo
|
||||||
|
} else {
|
||||||
|
write-host "ERROR: failed to install Google Chrome"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
11
bin/reinstall_msedge_stable_mac.sh
Executable file
11
bin/reinstall_msedge_stable_mac.sh
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
cd /tmp
|
||||||
|
curl -o ./msedge_stable.pkg -k "$1"
|
||||||
|
# Note: there's no way to uninstall previously installed MSEdge.
|
||||||
|
# However, running PKG again seems to update installation.
|
||||||
|
sudo installer -pkg /tmp/msedge_stable.pkg -target /
|
||||||
|
rm -rf /tmp/msedge_stable.pkg
|
||||||
|
/Applications/Microsoft\ Edge.app/Contents/MacOS/Microsoft\ Edge --version
|
21
bin/reinstall_msedge_stable_win.ps1
Normal file
21
bin/reinstall_msedge_stable_win.ps1
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
$url = $args[0]
|
||||||
|
|
||||||
|
Write-Host "Downloading Microsoft Edge"
|
||||||
|
$wc = New-Object net.webclient
|
||||||
|
$msiInstaller = "$env:temp\microsoft-edge-stable.msi"
|
||||||
|
$wc.Downloadfile($url, $msiInstaller)
|
||||||
|
|
||||||
|
Write-Host "Installing Microsoft Edge"
|
||||||
|
$arguments = "/i `"$msiInstaller`" /quiet"
|
||||||
|
Start-Process msiexec.exe -ArgumentList $arguments -Wait
|
||||||
|
Remove-Item $msiInstaller
|
||||||
|
|
||||||
|
$suffix = "\\Microsoft\\Edge\\Application\\msedge.exe"
|
||||||
|
if (Test-Path "${env:ProgramFiles(x86)}$suffix") {
|
||||||
|
(Get-Item "${env:ProgramFiles(x86)}$suffix").VersionInfo
|
||||||
|
} elseif (Test-Path "${env:ProgramFiles}$suffix") {
|
||||||
|
(Get-Item "${env:ProgramFiles}$suffix").VersionInfo
|
||||||
|
} else {
|
||||||
|
write-host "ERROR: failed to install Microsoft Edge"
|
||||||
|
exit 1
|
||||||
|
}
|
@ -39,10 +39,34 @@ import * as utils from '../utils/utils';
|
|||||||
|
|
||||||
const SCRIPTS_DIRECTORY = path.join(__dirname, '..', '..', 'bin');
|
const SCRIPTS_DIRECTORY = path.join(__dirname, '..', '..', 'bin');
|
||||||
|
|
||||||
type BrowserChannel = 'chrome-beta'|'chrome';
|
|
||||||
const allBrowserChannels: Set<BrowserChannel> = new Set(['chrome-beta', 'chrome']);
|
type BrowserChannel = 'chrome-beta'|'chrome'|'msedge';
|
||||||
|
const allBrowserChannels: Set<BrowserChannel> = new Set(['chrome-beta', 'chrome', 'msedge']);
|
||||||
const packageJSON = require('../../package.json');
|
const packageJSON = require('../../package.json');
|
||||||
|
|
||||||
|
const ChannelName = {
|
||||||
|
'chrome-beta': 'Google Chrome Beta',
|
||||||
|
'chrome': 'Google Chrome',
|
||||||
|
'msedge': 'Microsoft Edge',
|
||||||
|
};
|
||||||
|
|
||||||
|
const InstallationScriptName = {
|
||||||
|
'chrome-beta': {
|
||||||
|
'linux': 'reinstall_chrome_beta_linux.sh',
|
||||||
|
'darwin': 'reinstall_chrome_beta_mac.sh',
|
||||||
|
'win32': 'reinstall_chrome_beta_win.ps1',
|
||||||
|
},
|
||||||
|
'chrome': {
|
||||||
|
'linux': 'reinstall_chrome_stable_linux.sh',
|
||||||
|
'darwin': 'reinstall_chrome_stable_mac.sh',
|
||||||
|
'win32': 'reinstall_chrome_stable_win.ps1',
|
||||||
|
},
|
||||||
|
'msedge': {
|
||||||
|
'darwin': 'reinstall_msedge_stable_mac.sh',
|
||||||
|
'win32': 'reinstall_msedge_stable_win.ps1',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
program
|
program
|
||||||
.version('Version ' + packageJSON.version)
|
.version('Version ' + packageJSON.version)
|
||||||
.name(process.env.PW_CLI_NAME || 'npx playwright');
|
.name(process.env.PW_CLI_NAME || 'npx playwright');
|
||||||
@ -107,47 +131,46 @@ program
|
|||||||
console.log(`Invalid installation targets: ${faultyArguments.map(name => `'${name}'`).join(', ')}. Expecting one of: ${[...allBrowserNames, ...allBrowserChannels].map(name => `'${name}'`).join(', ')}`);
|
console.log(`Invalid installation targets: ${faultyArguments.map(name => `'${name}'`).join(', ')}. Expecting one of: ${[...allBrowserNames, ...allBrowserChannels].map(name => `'${name}'`).join(', ')}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (browserNames.has('chromium') || browserChannels.has('chrome-beta') || browserChannels.has('chrome'))
|
if (browserNames.has('chromium') || browserChannels.has('chrome-beta') || browserChannels.has('chrome') || browserChannels.has('msedge'))
|
||||||
browserNames.add('ffmpeg');
|
browserNames.add('ffmpeg');
|
||||||
if (browserNames.size)
|
if (browserNames.size)
|
||||||
await installBrowsers([...browserNames]);
|
await installBrowsers([...browserNames]);
|
||||||
for (const browserChannel of browserChannels) {
|
for (const browserChannel of browserChannels)
|
||||||
if (browserChannel === 'chrome-beta' || browserChannel === 'chrome')
|
await installBrowserChannel(browserChannel);
|
||||||
await installChromeChannel(browserChannel);
|
|
||||||
else
|
|
||||||
throw new Error(`ERROR: no installation instructions for '${browserChannel}' channel.`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`Failed to install browsers\n${e}`);
|
console.log(`Failed to install browsers\n${e}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function installChromeChannel(channel: string) {
|
async function installBrowserChannel(channel: BrowserChannel) {
|
||||||
const platform: string = os.platform();
|
const platform = os.platform();
|
||||||
const shell: (string|undefined) = {
|
const scriptName: (string|undefined) = (InstallationScriptName[channel] as any)[platform];
|
||||||
'linux': 'bash',
|
if (!scriptName)
|
||||||
'darwin': 'bash',
|
throw new Error(`Cannot install ${ChannelName[channel]} on ${platform}`);
|
||||||
'win32': 'powershell.exe',
|
|
||||||
}[platform];
|
|
||||||
const scriptName: (string|undefined) = ({
|
|
||||||
'chrome-beta': {
|
|
||||||
'linux': 'reinstall_chrome_beta_linux.sh',
|
|
||||||
'darwin': 'reinstall_chrome_beta_mac.sh',
|
|
||||||
'win32': 'reinstall_chrome_beta_win.ps1',
|
|
||||||
},
|
|
||||||
'chrome': {
|
|
||||||
'linux': 'reinstall_chrome_stable_linux.sh',
|
|
||||||
'darwin': 'reinstall_chrome_stable_mac.sh',
|
|
||||||
'win32': 'reinstall_chrome_stable_win.ps1',
|
|
||||||
},
|
|
||||||
}[channel] as any)[platform];
|
|
||||||
if (!shell || !scriptName)
|
|
||||||
throw new Error(`Cannot install chrome-beta on ${platform}`);
|
|
||||||
|
|
||||||
const {code} = await utils.spawnAsync(shell, [path.join(SCRIPTS_DIRECTORY, scriptName)], { cwd: SCRIPTS_DIRECTORY, stdio: 'inherit' });
|
const scriptArgs = [];
|
||||||
|
if (channel === 'msedge') {
|
||||||
|
const products = JSON.parse(await utils.fetchData('https://edgeupdates.microsoft.com/api/products'));
|
||||||
|
const stable = products.find((product: any) => product.Product === 'Stable');
|
||||||
|
if (platform === 'win32') {
|
||||||
|
const arch = os.arch() === 'x64' ? 'x64' : 'x86';
|
||||||
|
const release = stable.Releases.find((release: any) => release.Platform === 'Windows' && release.Architecture === arch);
|
||||||
|
const artifact = release.Artifacts.find((artifact: any) => artifact.ArtifactName === 'msi');
|
||||||
|
scriptArgs.push(artifact.Location /* url */);
|
||||||
|
} else if (platform === 'darwin') {
|
||||||
|
const release = stable.Releases.find((release: any) => release.Platform === 'MacOS' && release.Architecture === 'universal');
|
||||||
|
const artifact = release.Artifacts.find((artifact: any) => artifact.ArtifactName === 'pkg');
|
||||||
|
scriptArgs.push(artifact.Location /* url */);
|
||||||
|
} else {
|
||||||
|
throw new Error(`Cannot install ${ChannelName[channel]} on ${platform}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const shell = scriptName.endsWith('.ps1') ? 'powershell.exe' : 'bash';
|
||||||
|
const {code} = await utils.spawnAsync(shell, [path.join(SCRIPTS_DIRECTORY, scriptName), ...scriptArgs], { cwd: SCRIPTS_DIRECTORY, stdio: 'inherit' });
|
||||||
if (code !== 0)
|
if (code !== 0)
|
||||||
throw new Error('Failed to install chrome-beta');
|
throw new Error(`Failed to install ${ChannelName[channel]}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
program
|
program
|
||||||
|
@ -20,24 +20,10 @@ import fs from 'fs';
|
|||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import ProgressBar from 'progress';
|
import ProgressBar from 'progress';
|
||||||
import { getProxyForUrl } from 'proxy-from-env';
|
|
||||||
import * as URL from 'url';
|
|
||||||
import { BrowserName, Registry, hostPlatform } from '../utils/registry';
|
import { BrowserName, Registry, hostPlatform } from '../utils/registry';
|
||||||
|
import { downloadFile, existsAsync } from '../utils/utils';
|
||||||
import { debugLogger } from '../utils/debugLogger';
|
import { debugLogger } from '../utils/debugLogger';
|
||||||
|
|
||||||
// `https-proxy-agent` v5 is written in TypeScript and exposes generated types.
|
|
||||||
// However, as of June 2020, its types are generated with tsconfig that enables
|
|
||||||
// `esModuleInterop` option.
|
|
||||||
//
|
|
||||||
// As a result, we can't depend on the package unless we enable the option
|
|
||||||
// for our codebase. Instead of doing this, we abuse "require" to import module
|
|
||||||
// without types.
|
|
||||||
const ProxyAgent = require('https-proxy-agent');
|
|
||||||
|
|
||||||
const existsAsync = (path: string): Promise<boolean> => new Promise(resolve => fs.stat(path, err => resolve(!err)));
|
|
||||||
|
|
||||||
export type OnProgressCallback = (downloadedBytes: number, totalBytes: number) => void;
|
|
||||||
|
|
||||||
export async function downloadBrowserWithProgressBar(registry: Registry, browserName: BrowserName): Promise<boolean> {
|
export async function downloadBrowserWithProgressBar(registry: Registry, browserName: BrowserName): Promise<boolean> {
|
||||||
const browserDirectory = registry.browserDirectory(browserName);
|
const browserDirectory = registry.browserDirectory(browserName);
|
||||||
const progressBarName = `${browserName} v${registry.revision(browserName)}`;
|
const progressBarName = `${browserName} v${registry.revision(browserName)}`;
|
||||||
@ -71,7 +57,7 @@ export async function downloadBrowserWithProgressBar(registry: Registry, browser
|
|||||||
try {
|
try {
|
||||||
for (let attempt = 1, N = 3; attempt <= N; ++attempt) {
|
for (let attempt = 1, N = 3; attempt <= N; ++attempt) {
|
||||||
debugLogger.log('install', `downloading ${progressBarName} - attempt #${attempt}`);
|
debugLogger.log('install', `downloading ${progressBarName} - attempt #${attempt}`);
|
||||||
const {error} = await downloadFile(url, zipPath, progress);
|
const {error} = await downloadFile(url, zipPath, {progressCallback: progress, log: debugLogger.log.bind(debugLogger, 'install')});
|
||||||
if (!error) {
|
if (!error) {
|
||||||
debugLogger.log('install', `SUCCESS downloading ${progressBarName}`);
|
debugLogger.log('install', `SUCCESS downloading ${progressBarName}`);
|
||||||
break;
|
break;
|
||||||
@ -111,77 +97,6 @@ function toMegabytes(bytes: number) {
|
|||||||
return `${Math.round(mb * 10) / 10} Mb`;
|
return `${Math.round(mb * 10) / 10} Mb`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadFile(url: string, destinationPath: string, progressCallback: OnProgressCallback | undefined): Promise<{error: any}> {
|
|
||||||
debugLogger.log('install', `running download:`);
|
|
||||||
debugLogger.log('install', `-- from url: ${url}`);
|
|
||||||
debugLogger.log('install', `-- to location: ${destinationPath}`);
|
|
||||||
let fulfill: ({error}: {error: any}) => void = ({error}) => {};
|
|
||||||
let downloadedBytes = 0;
|
|
||||||
let totalBytes = 0;
|
|
||||||
|
|
||||||
const promise: Promise<{error: any}> = new Promise(x => { fulfill = x; });
|
|
||||||
|
|
||||||
const request = httpRequest(url, 'GET', response => {
|
|
||||||
if (response.statusCode !== 200) {
|
|
||||||
const error = new Error(`Download failed: server returned code ${response.statusCode}. URL: ${url}`);
|
|
||||||
// consume response data to free up memory
|
|
||||||
response.resume();
|
|
||||||
fulfill({error});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const file = fs.createWriteStream(destinationPath);
|
|
||||||
file.on('finish', () => fulfill({error: null}));
|
|
||||||
file.on('error', error => fulfill({error}));
|
|
||||||
response.pipe(file);
|
|
||||||
totalBytes = parseInt(response.headers['content-length'], 10);
|
|
||||||
debugLogger.log('install', `-- total bytes: ${totalBytes}`);
|
|
||||||
if (progressCallback)
|
|
||||||
response.on('data', onData);
|
|
||||||
});
|
|
||||||
request.on('error', (error: any) => fulfill({error}));
|
|
||||||
return promise;
|
|
||||||
|
|
||||||
function onData(chunk: string) {
|
|
||||||
downloadedBytes += chunk.length;
|
|
||||||
progressCallback!(downloadedBytes, totalBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function httpRequest(url: string, method: string, response: (r: any) => void) {
|
|
||||||
let options: any = URL.parse(url);
|
|
||||||
options.method = method;
|
|
||||||
|
|
||||||
const proxyURL = getProxyForUrl(url);
|
|
||||||
if (proxyURL) {
|
|
||||||
if (url.startsWith('http:')) {
|
|
||||||
const proxy = URL.parse(proxyURL);
|
|
||||||
options = {
|
|
||||||
path: options.href,
|
|
||||||
host: proxy.hostname,
|
|
||||||
port: proxy.port,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const parsedProxyURL: any = URL.parse(proxyURL);
|
|
||||||
parsedProxyURL.secureProxy = parsedProxyURL.protocol === 'https:';
|
|
||||||
|
|
||||||
options.agent = new ProxyAgent(parsedProxyURL);
|
|
||||||
options.rejectUnauthorized = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestCallback = (res: any) => {
|
|
||||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location)
|
|
||||||
httpRequest(res.headers.location, method, response);
|
|
||||||
else
|
|
||||||
response(res);
|
|
||||||
};
|
|
||||||
const request = options.protocol === 'https:' ?
|
|
||||||
require('https').request(options, requestCallback) :
|
|
||||||
require('http').request(options, requestCallback);
|
|
||||||
request.end();
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logPolitely(toBeLogged: string) {
|
export function logPolitely(toBeLogged: string) {
|
||||||
const logLevel = process.env.npm_config_loglevel;
|
const logLevel = process.env.npm_config_loglevel;
|
||||||
const logLevelDisplay = ['silent', 'error', 'warn'].indexOf(logLevel || '') > -1;
|
const logLevelDisplay = ['silent', 'error', 'warn'].indexOf(logLevel || '') > -1;
|
||||||
|
@ -27,12 +27,11 @@ import { Progress, ProgressController } from './progress';
|
|||||||
import * as types from './types';
|
import * as types from './types';
|
||||||
import { DEFAULT_TIMEOUT, TimeoutSettings } from '../utils/timeoutSettings';
|
import { DEFAULT_TIMEOUT, TimeoutSettings } from '../utils/timeoutSettings';
|
||||||
import { validateHostRequirements } from './validateDependencies';
|
import { validateHostRequirements } from './validateDependencies';
|
||||||
import { debugMode } from '../utils/utils';
|
import { debugMode, existsAsync } from '../utils/utils';
|
||||||
import { helper } from './helper';
|
import { helper } from './helper';
|
||||||
import { RecentLogsCollector } from '../utils/debugLogger';
|
import { RecentLogsCollector } from '../utils/debugLogger';
|
||||||
import { CallMetadata, SdkObject } from './instrumentation';
|
import { CallMetadata, SdkObject } from './instrumentation';
|
||||||
|
|
||||||
const existsAsync = (path: string): Promise<boolean> => new Promise(resolve => fs.stat(path, err => resolve(!err)));
|
|
||||||
const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-');
|
const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-');
|
||||||
|
|
||||||
export abstract class BrowserType extends SdkObject {
|
export abstract class BrowserType extends SdkObject {
|
||||||
|
@ -23,9 +23,7 @@ import { EventEmitter } from 'events';
|
|||||||
import { internalCallMetadata } from '../../instrumentation';
|
import { internalCallMetadata } from '../../instrumentation';
|
||||||
import type { CallLog, EventData, Mode, Source } from './recorderTypes';
|
import type { CallLog, EventData, Mode, Source } from './recorderTypes';
|
||||||
import { BrowserContext } from '../../browserContext';
|
import { BrowserContext } from '../../browserContext';
|
||||||
import { isUnderTest } from '../../../utils/utils';
|
import { existsAsync, isUnderTest } from '../../../utils/utils';
|
||||||
|
|
||||||
const existsAsync = (path: string): Promise<boolean> => new Promise(resolve => fs.stat(path, err => resolve(!err)));
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
@ -20,6 +20,113 @@ import removeFolder from 'rimraf';
|
|||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
|
import { getProxyForUrl } from 'proxy-from-env';
|
||||||
|
import * as URL from 'url';
|
||||||
|
|
||||||
|
// `https-proxy-agent` v5 is written in TypeScript and exposes generated types.
|
||||||
|
// However, as of June 2020, its types are generated with tsconfig that enables
|
||||||
|
// `esModuleInterop` option.
|
||||||
|
//
|
||||||
|
// As a result, we can't depend on the package unless we enable the option
|
||||||
|
// for our codebase. Instead of doing this, we abuse "require" to import module
|
||||||
|
// without types.
|
||||||
|
const ProxyAgent = require('https-proxy-agent');
|
||||||
|
|
||||||
|
export const existsAsync = (path: string): Promise<boolean> => new Promise(resolve => fs.stat(path, err => resolve(!err)));
|
||||||
|
|
||||||
|
function httpRequest(url: string, method: string, response: (r: any) => void) {
|
||||||
|
let options: any = URL.parse(url);
|
||||||
|
options.method = method;
|
||||||
|
|
||||||
|
const proxyURL = getProxyForUrl(url);
|
||||||
|
if (proxyURL) {
|
||||||
|
if (url.startsWith('http:')) {
|
||||||
|
const proxy = URL.parse(proxyURL);
|
||||||
|
options = {
|
||||||
|
path: options.href,
|
||||||
|
host: proxy.hostname,
|
||||||
|
port: proxy.port,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const parsedProxyURL: any = URL.parse(proxyURL);
|
||||||
|
parsedProxyURL.secureProxy = parsedProxyURL.protocol === 'https:';
|
||||||
|
|
||||||
|
options.agent = new ProxyAgent(parsedProxyURL);
|
||||||
|
options.rejectUnauthorized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestCallback = (res: any) => {
|
||||||
|
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location)
|
||||||
|
httpRequest(res.headers.location, method, response);
|
||||||
|
else
|
||||||
|
response(res);
|
||||||
|
};
|
||||||
|
const request = options.protocol === 'https:' ?
|
||||||
|
require('https').request(options, requestCallback) :
|
||||||
|
require('http').request(options, requestCallback);
|
||||||
|
request.end();
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchData(url: string): Promise<string> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
httpRequest(url, 'GET', function(response){
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
reject(new Error(`fetch failed: server returned code ${response.statusCode}. URL: ${url}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let body = '';
|
||||||
|
response.on('data', (chunk: string) => body += chunk);
|
||||||
|
response.on('error', (error: any) => reject(error));
|
||||||
|
response.on('end', () => resolve(body));
|
||||||
|
}).on('error', (error: any) => reject(error));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
type OnProgressCallback = (downloadedBytes: number, totalBytes: number) => void;
|
||||||
|
type DownloadFileLogger = (message: string) => void;
|
||||||
|
|
||||||
|
export function downloadFile(url: string, destinationPath: string, options : {progressCallback?: OnProgressCallback, log?: DownloadFileLogger} = {}): Promise<{error: any}> {
|
||||||
|
const {
|
||||||
|
progressCallback,
|
||||||
|
log = () => {},
|
||||||
|
} = options;
|
||||||
|
log(`running download:`);
|
||||||
|
log(`-- from url: ${url}`);
|
||||||
|
log(`-- to location: ${destinationPath}`);
|
||||||
|
let fulfill: ({error}: {error: any}) => void = ({error}) => {};
|
||||||
|
let downloadedBytes = 0;
|
||||||
|
let totalBytes = 0;
|
||||||
|
|
||||||
|
const promise: Promise<{error: any}> = new Promise(x => { fulfill = x; });
|
||||||
|
|
||||||
|
const request = httpRequest(url, 'GET', response => {
|
||||||
|
log(`-- response status code: ${response.statusCode}`);
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
const error = new Error(`Download failed: server returned code ${response.statusCode}. URL: ${url}`);
|
||||||
|
// consume response data to free up memory
|
||||||
|
response.resume();
|
||||||
|
fulfill({error});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const file = fs.createWriteStream(destinationPath);
|
||||||
|
file.on('finish', () => fulfill({error: null}));
|
||||||
|
file.on('error', error => fulfill({error}));
|
||||||
|
response.pipe(file);
|
||||||
|
totalBytes = parseInt(response.headers['content-length'], 10);
|
||||||
|
log(`-- total bytes: ${totalBytes}`);
|
||||||
|
if (progressCallback)
|
||||||
|
response.on('data', onData);
|
||||||
|
});
|
||||||
|
request.on('error', (error: any) => fulfill({error}));
|
||||||
|
return promise;
|
||||||
|
|
||||||
|
function onData(chunk: string) {
|
||||||
|
downloadedBytes += chunk.length;
|
||||||
|
progressCallback!(downloadedBytes, totalBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function spawnAsync(cmd: string, args: string[], options: any): Promise<{stdout: string, stderr: string, code: number, error?: Error}> {
|
export function spawnAsync(cmd: string, args: string[], options: any): Promise<{stdout: string, stderr: string, code: number, error?: Error}> {
|
||||||
const process = spawn(cmd, args, options);
|
const process = spawn(cmd, args, options);
|
||||||
|
@ -148,6 +148,7 @@ it('Page.bringToFront should work', async ({browserType, browserOptions}) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('focused input should produce the same screenshot', async ({browserType, browserOptions, browserName, platform, channel}, testInfo) => {
|
it('focused input should produce the same screenshot', async ({browserType, browserOptions, browserName, platform, channel}, testInfo) => {
|
||||||
|
it.fail(channel === 'msedge' && platform === 'darwin', 'focus ring is black on MSEdge');
|
||||||
it.fail(browserName === 'firefox' && platform === 'darwin', 'headless has thinner outline');
|
it.fail(browserName === 'firefox' && platform === 'darwin', 'headless has thinner outline');
|
||||||
it.fail(browserName === 'firefox' && platform === 'linux', 'headless has no outline');
|
it.fail(browserName === 'firefox' && platform === 'linux', 'headless has no outline');
|
||||||
it.skip(browserName === 'webkit' && platform === 'linux', 'gtk vs wpe');
|
it.skip(browserName === 'webkit' && platform === 'linux', 'gtk vs wpe');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user