Skip to content

Commit

Permalink
🏗 Introduction of coverage-map task. (ampproject#29519)
Browse files Browse the repository at this point in the history
* moved script to tasks and added package requirements

* lint fix

* progress on making task

* remove test.json

* additional lint fixes

* fixed according to comments

* several changes in coverage-map

* lint

* clarify description

* change to use async writefile

* review flag

* OK in window.scrollBy()

* lint

* added source-map-explorer to package.json

* Some changes based on feedback

* additional updated based on feedback

* small change

* added separate package.json

* package specific changes

* undo changes in root package.json

* added yarn.lock

* several changes

* revert yarn.lock

* lock file

* delete package-lock.json

* update gulpfile.js

* lazy importing

* revert change

* remove package-lock

* Update package.json

* yarn.lock

* prettify

* excluded coverage-map for getComputedStyle

* additional feedback

Co-authored-by: Derek Tse <[email protected]>
  • Loading branch information
2 people authored and ed-bird committed Dec 10, 2020
1 parent f39aa77 commit cf65fcb
Show file tree
Hide file tree
Showing 5 changed files with 839 additions and 1 deletion.
119 changes: 119 additions & 0 deletions build-system/tasks/coverage-map/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* Copyright 2020 The AMP HTML Authors. 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.
*/
const argv = require('minimist')(process.argv.slice(2));
const fs = require('fs').promises;
const log = require('fancy-log');
const {dist} = require('../dist');
const {installPackages} = require('../../common/utils');
const {startServer, stopServer} = require('../serve');

let puppeteer;
let explore;

const coverageJsonName = argv.json || 'coverage.json';
const testUrl =
argv.url || 'http://localhost:8000/examples/everything.amp.html';
const outHtml = argv.html || 'coverage.html';
const scrollDistance = 100;

async function collectCoverage() {
log(`Opening browser and navigating to ${testUrl}...`);
const browser = await puppeteer.launch({
defaultViewport: {width: 1200, height: 800},
});
const page = await browser.newPage();

// Enable JavaScript coverage
await page.coverage.startJSCoverage();
// Navigate to page
await page.goto(testUrl);
await page.waitFor(
() =>
!!document.querySelector('style[amp-runtime]') &&
!!document.body &&
getComputedStyle(document.body).visibility === 'visible'
);
log('Scrolling to the end of the page...');
await autoScroll(page);
log('Testing completed.');
const jsCoverage = await page.coverage.stopJSCoverage();
const data = JSON.stringify(jsCoverage);
log(`Writing to ${coverageJsonName} in dist/${coverageJsonName}...`);
await fs.writeFile(`dist/${coverageJsonName}`, data, () => {});
await browser.close();
}

// Source: https://github.com/chenxiaochun/blog/issues/38s
async function autoScroll(page) {
await page.evaluate(async () => {
await new Promise((resolve, opt_) => {
let totalHeight = 0;
const distance = scrollDistance;
const timer = setInterval(() => {
const {scrollHeight} = document.body;
window./*OK*/ scrollBy(0, distance);
totalHeight += distance;

if (totalHeight >= scrollHeight) {
clearInterval(timer);
resolve();
}
}, 100);
});
});
}

async function generateMap() {
log(
`Generating heat map in dist/${outHtml}, based on ${coverageJsonName}...`
);
await explore('dist/v0.js', {
output: {format: 'html', filename: `${outHtml}`},
coverage: `dist/${coverageJsonName}`,
onlyMapped: true,
});
}

async function coverageMap() {
installPackages(__dirname);

puppeteer = require('puppeteer');
explore = require('source-map-explorer').explore;

await dist();
await startServer(
{host: 'localhost', port: 8000},
{quiet: true},
{compiled: true}
);
await collectCoverage();
await generateMap();
await stopServer();
}

module.exports = {coverageMap};

coverageMap.description =
'Generates a code coverage "heat map" HTML visualization on v0.js based on code traversed during puppeteer test via source map explorer';

coverageMap.flags = {
json:
' Customize the name of the JSON output from puppeteer (out.json by default).',
url:
' Set the URL for puppeteer testing, starting with "http://localhost:8000..." (http://localhost:8000/examples/everything.amp.html by default).',
html:
' Customize the name of the HTML output from source map explorer (out.html by default).',
};
10 changes: 10 additions & 0 deletions build-system/tasks/coverage-map/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"private": true,
"name": "gulp-coverage-map",
"version": "0.1.0",
"description": "Gulp coverage map.",
"dependencies": {
"puppeteer": "5.2.1",
"source-map-explorer": "2.4.2"
}
}
Loading

0 comments on commit cf65fcb

Please sign in to comment.