-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🏗 Add dev-mode for
amp visual-diff
and split code into modules (#36673
- Loading branch information
1 parent
4b43359
commit 7a44c3f
Showing
28 changed files
with
2,473 additions
and
560 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
'use strict'; | ||
|
||
const argv = require('minimist')(process.argv.slice(2)); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const puppeteer = require('puppeteer'); | ||
const PuppeteerExtraPluginUserPreferences = require('puppeteer-extra-plugin-user-preferences'); | ||
const {addExtra} = require('puppeteer-extra'); | ||
const {cyan, yellow} = require('kleur/colors'); | ||
const {HOST} = require('./consts'); | ||
const {log} = require('./log'); | ||
|
||
// REPEATING TODO(@ampproject/wg-infra): Update this whenever the Percy backend | ||
// starts using a new version of Chrome to render DOM snapshots. | ||
// | ||
// Steps: | ||
// 1. Open a recent Percy build, and click the “ⓘ” icon | ||
// 2. Note the Chrome major version at the bottom | ||
// 3. Look up the full version at https://en.wikipedia.org/wiki/Google_Chrome_version_history | ||
// 4. Open https://omahaproxy.appspot.com in a browser | ||
// 5. Go to "Tools" -> "Version information" | ||
// 6. Paste the full version (add ".0" at the end) in the "Version" field and click "Lookup" | ||
// 7. Copy the value next to "Branch Base Position" and update the line below | ||
const PUPPETEER_CHROMIUM_REVISION = '870763'; // 91.0.4472.0 | ||
|
||
const VIEWPORT_WIDTH = 1400; | ||
const VIEWPORT_HEIGHT = 100000; | ||
|
||
/** | ||
* Launches a Puppeteer controlled browser. | ||
* | ||
* Waits until the browser is up and reachable, and ties its lifecycle to this | ||
* process's lifecycle. | ||
* | ||
* @param {!puppeteer.BrowserFetcher} browserFetcher Puppeteer browser binaries | ||
* manager. | ||
* @return {Promise<!puppeteer.Browser>} a Puppeteer controlled browser. | ||
*/ | ||
async function launchBrowser(browserFetcher) { | ||
const browserOptions = { | ||
args: [ | ||
'--disable-background-media-suspend', | ||
'--disable-background-timer-throttling', | ||
'--disable-backgrounding-occluded-windows', | ||
'--disable-extensions', | ||
'--disable-gpu', | ||
'--disable-renderer-backgrounding', | ||
'--no-sandbox', | ||
'--no-startup-window', | ||
], | ||
dumpio: argv.chrome_debug, | ||
headless: !argv.dev, | ||
executablePath: browserFetcher.revisionInfo(PUPPETEER_CHROMIUM_REVISION) | ||
.executablePath, | ||
waitForInitialPage: false, | ||
}; | ||
|
||
// @ts-ignore type mismatch in puppeteer-extra. | ||
const puppeteerExtra = addExtra(puppeteer); | ||
puppeteerExtra.use( | ||
PuppeteerExtraPluginUserPreferences({ | ||
userPrefs: { | ||
devtools: { | ||
preferences: { | ||
currentDockState: '"undocked"', | ||
}, | ||
}, | ||
}, | ||
}) | ||
); | ||
return await puppeteerExtra.launch(browserOptions); | ||
} | ||
|
||
/** | ||
* Opens a new browser tab, resizes its viewport, and returns a Page handler. | ||
* | ||
* @param {!puppeteer.Browser} browser a Puppeteer controlled browser. | ||
* @param {?puppeteer.Viewport} viewport optional viewport size object with | ||
* numeric fields `width` and `height`. | ||
* @return {Promise<!puppeteer.Page>} | ||
*/ | ||
async function newPage(browser, viewport = null) { | ||
log('verbose', 'Creating new tab'); | ||
|
||
const context = await browser.createIncognitoBrowserContext(); | ||
const page = await context.newPage(); | ||
page.setDefaultNavigationTimeout(0); | ||
await page.setJavaScriptEnabled(true); | ||
await page.setRequestInterception(true); | ||
page.on('request', (interceptedRequest) => { | ||
const requestUrl = new URL(interceptedRequest.url()); | ||
const mockedFilepath = path.join( | ||
path.dirname(__filename), | ||
'network-mocks', | ||
requestUrl.hostname, | ||
encodeURIComponent( | ||
`${requestUrl.pathname.substr(1)}${requestUrl.search}` | ||
).replace(/%2F/g, '/') | ||
); | ||
|
||
if ( | ||
requestUrl.protocol === 'data:' || | ||
requestUrl.hostname === HOST || | ||
requestUrl.hostname.endsWith(`.${HOST}`) | ||
) { | ||
return interceptedRequest.continue(); | ||
} else if (fs.existsSync(mockedFilepath)) { | ||
log( | ||
'verbose', | ||
'Mocked network request for', | ||
yellow(requestUrl.href), | ||
'with file', | ||
cyan(mockedFilepath) | ||
); | ||
return interceptedRequest.respond({ | ||
status: 200, | ||
body: fs.readFileSync(mockedFilepath), | ||
}); | ||
} else { | ||
log( | ||
'verbose', | ||
'Blocked external network request for', | ||
yellow(requestUrl.href) | ||
); | ||
return interceptedRequest.abort('blockedbyclient'); | ||
} | ||
}); | ||
await resetPage(page, viewport); | ||
return page; | ||
} | ||
|
||
/** | ||
* Resets the size of a tab and loads about:blank. | ||
* | ||
* @param {!puppeteer.Page} page a Puppeteer control browser tab/page. | ||
* @param {?puppeteer.Viewport} viewport optional viewport size object with | ||
* numeric fields `width` and `height`. | ||
* @return {Promise<void>} | ||
*/ | ||
async function resetPage(page, viewport = null) { | ||
const width = viewport ? viewport.width : VIEWPORT_WIDTH; | ||
const height = viewport ? viewport.height : VIEWPORT_HEIGHT; | ||
|
||
log( | ||
'verbose', | ||
'Resetting tab to', | ||
yellow('about:blank'), | ||
'with size', | ||
yellow(`${width}×${height}`) | ||
); | ||
|
||
await page.goto('about:blank'); | ||
await page.setViewport({width, height}); | ||
} | ||
|
||
/** | ||
* Loads task-specific dependencies are returns an instance of BrowserFetcher. | ||
* | ||
* @return {Promise<!puppeteer.BrowserFetcher>} | ||
*/ | ||
async function loadBrowserFetcher() { | ||
// @ts-ignore Valid method in Puppeteer's nodejs interface. | ||
// https://github.com/puppeteer/puppeteer/blob/main/src/node/Puppeteer.ts | ||
const browserFetcher = puppeteer.createBrowserFetcher(); | ||
const chromiumRevisions = await browserFetcher.localRevisions(); | ||
if (chromiumRevisions.includes(PUPPETEER_CHROMIUM_REVISION)) { | ||
log( | ||
'info', | ||
'Using Percy-compatible version of Chromium', | ||
cyan(PUPPETEER_CHROMIUM_REVISION) | ||
); | ||
} else { | ||
log( | ||
'info', | ||
'Percy-compatible version of Chromium', | ||
cyan(PUPPETEER_CHROMIUM_REVISION), | ||
'was not found. Downloading...' | ||
); | ||
await browserFetcher.download( | ||
PUPPETEER_CHROMIUM_REVISION, | ||
(/* downloadedBytes, totalBytes */) => { | ||
// TODO(@ampproject/wg-infra): display download progress. | ||
// Logging every call is too verbose. | ||
} | ||
); | ||
} | ||
return browserFetcher; | ||
} | ||
|
||
module.exports = { | ||
PUPPETEER_CHROMIUM_REVISION, | ||
launchBrowser, | ||
loadBrowserFetcher, | ||
newPage, | ||
resetPage, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
'use strict'; | ||
|
||
const {PORT} = require('../serve'); | ||
|
||
const HOST = 'localhost'; | ||
|
||
// Base tests do not run any special code other than loading the page. Use this | ||
// no-op function instead of null for easier type checking. | ||
const BASE_TEST_FUNCTION = async () => {}; | ||
|
||
module.exports = { | ||
BASE_TEST_FUNCTION, | ||
HOST, | ||
PORT, | ||
}; |
Oops, something went wrong.