Skip to content

Instantly share code, notes, and snippets.

@ccpu
Forked from Friss/custom-code-coverage.js
Created April 16, 2020 05:45
Show Gist options
  • Select an option

  • Save ccpu/28a5679d1fca50bd5b6e1f2a4f9ec937 to your computer and use it in GitHub Desktop.

Select an option

Save ccpu/28a5679d1fca50bd5b6e1f2a4f9ec937 to your computer and use it in GitHub Desktop.

Revisions

  1. @Friss Friss revised this gist Apr 25, 2019. 1 changed file with 27 additions and 0 deletions.
    27 changes: 27 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,27 @@
    {
    "name": "puppeteer-tests",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
    "coverage": "nyc report --reporter=html --reporter=text",
    "instrument": "nyc instrument",
    "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "",
    "license": "ISC",
    "devDependencies": {
    "istanbul-api": "^2.1.5",
    "istanbul-lib-coverage": "^2.0.4",
    "istanbul-lib-report": "^2.0.7",
    "istanbul-lib-source-maps": "^3.0.5",
    "istanbul-reports": "^2.2.3",
    "nyc": "^13.3.0",
    "puppeteer": "^1.14.0",
    "puppeteer-to-istanbul": "^1.2.2",
    "node-fetch": "^2.3.0",
    "source-map": "^0.7.3",
    "source-map-support": "^0.5.11"
    },
    "dependencies": {}
    }
  2. @Friss Friss created this gist Apr 25, 2019.
    82 changes: 82 additions & 0 deletions custom-code-coverage.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,82 @@
    /* This uses a modified version of puppeteer-to-istanbul and v8-to-istanbul */

    // There are a lot of diffs here but most of it is just prettier changes :(

    // https://github.com/istanbuljs/puppeteer-to-istanbul/compare/master...Friss:master
    // Mostly just converting it to handle the new async v8-to-istanbul code. Also fetches sourcemaps if availabile.

    // https://github.com/istanbuljs/v8-to-istanbul/compare/source-maps...Friss:source-maps
    // Tweaks to parse the path out to webpack files that I recreated based on the source maps.

    const fetch = require('node-fetch');
    const sourceMap = require('source-map');
    const fs = require('fs');
    const pti = require('./puppeteer-to-istanbul/index.js');
    const puppeteer = require('puppeteer');

    (async () => {
    const browser = await puppeteer.launch({ headless: true });
    const page = await browser.newPage();

    // Enable both JavaScript and CSS coverage
    await Promise.all([
    page.coverage.startJSCoverage(),
    page.coverage.startCSSCoverage(),
    ]);
    // Navigate to page
    await page.goto('https://app.hubspot.com/login');

    // TODO Make sure the page actually loaded successfully.

    // Disable both JavaScript and CSS coverage
    const [jsCoverage, cssCoverage] = await Promise.all([
    page.coverage.stopJSCoverage(),
    page.coverage.stopCSSCoverage(),
    ]);
    let totalBytes = 0;
    let usedBytes = 0;
    const coverage = [...jsCoverage, ...cssCoverage];
    for (const entry of coverage) {
    totalBytes += entry.text.length;
    for (const range of entry.ranges) usedBytes += range.end - range.start - 1;
    }
    console.log(`Bytes used: ${(usedBytes / totalBytes) * 100}%`);

    await browser.close();

    // We only care about hubspot JS coverage currently so filter out any other scripts.
    const hubspotUrls = jsCoverage.filter(entry => {
    return (
    entry.url.indexOf('hsappstatic.net') > -1 ||
    entry.url.indexOf('hubspot') > -1
    );
    });

    // Fetch the source map
    const rawSourceMap = await fetch(
    'https://static.hsappstatic.net/LoginUI/static-1.2758/bundles/project.js.map'
    ).then(res => res.text());

    // Write out all the source files based on the source map.
    await sourceMap.SourceMapConsumer.with(rawSourceMap, null, consumer => {
    consumer.sources.forEach(src => {
    const srcCode = consumer.sourceContentFor(src, true);
    if (srcCode) {
    const outputFilePath = `./.nyc_output/js/${src}`.replace(
    'webpack:///',
    'webpack:/'
    );
    const outputDir = outputFilePath.split('/');
    outputDir.pop();
    fs.mkdirSync(outputDir.join('/'), { recursive: true });
    fs.writeFileSync(outputFilePath, srcCode);
    }
    });
    });

    // Convert the Chrome Coverage to istanbul coverage.
    // This uses the special patched versions of the packages included in the repo.
    await pti.write(hubspotUrls);

    console.log('Done');
    })();
    98 changes: 98 additions & 0 deletions franken-code-coverage.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,98 @@
    /* Franken script attempt at mapping code coverage back to istanbul */

    // This creates a report that looks like https://i.imgur.com/EKjSmiR.png which has all the files but the coverage is all broken.

    const fetch = require('node-fetch');
    const sourceMap = require('source-map');
    const sourceMapLib = require('istanbul-lib-source-maps');
    const libCoverage = require('istanbul-lib-coverage');
    const libReport = require('istanbul-lib-report');
    const reports = require('istanbul-reports');
    const mkdirp = require('mkdirp');
    const fs = require('fs');
    (async () => {
    const pti = require('puppeteer-to-istanbul');
    const puppeteer = require('puppeteer');
    const browser = await puppeteer.launch({ headless: true });
    const page = await browser.newPage();

    // Enable both JavaScript and CSS coverage
    await Promise.all([
    page.coverage.startJSCoverage(),
    page.coverage.startCSSCoverage(),
    ]);
    // Navigate to page
    await page.goto('https://app.hubspot.com/login');
    // Disable both JavaScript and CSS coverage
    const [jsCoverage, cssCoverage] = await Promise.all([
    page.coverage.stopJSCoverage(),
    page.coverage.stopCSSCoverage(),
    ]);
    let totalBytes = 0;
    let usedBytes = 0;
    const coverage = [...jsCoverage, ...cssCoverage];
    for (const entry of coverage) {
    totalBytes += entry.text.length;
    for (const range of entry.ranges) usedBytes += range.end - range.start - 1;
    }
    console.log(`Bytes used: ${(usedBytes / totalBytes) * 100}%`);
    await browser.close();

    const hubspotUrls = jsCoverage.filter(entry => {
    return (
    entry.url.indexOf('hsappstatic.net') > -1 ||
    entry.url.indexOf('hubspot') > -1
    );
    });

    const rawSourceMap = await fetch(
    'https://static.hsappstatic.net/LoginUI/static-1.2758/bundles/project.js.map'
    ).then(res => res.text());

    await sourceMap.SourceMapConsumer.with(rawSourceMap, null, consumer => {
    consumer.sources.forEach(src => {
    const srcCode = consumer.sourceContentFor(src, true);
    if (srcCode) {
    const outputFilePath = `./.nyc_output/js/${src}`.replace(
    'webpack:///',
    'webpack:/'
    );
    const outputDir = outputFilePath.split('/');
    outputDir.pop();
    fs.mkdirSync(outputDir.join('/'), { recursive: true });
    fs.writeFileSync(outputFilePath, srcCode);
    } else {
    console.log(src);
    }
    });
    });

    await pti.write(hubspotUrls);

    const store = sourceMapLib.createSourceMapStore({});
    const unmappedCoverage = fs.readFileSync('.nyc_output/out.json').toString();

    const converage = JSON.parse(unmappedCoverage);

    converage[
    '/Users/zfriss/src/puppeteer-tests/.nyc_output/js/project.js'
    ].inputSourceMap = JSON.parse(rawSourceMap);

    const coverageMap = libCoverage.createCoverageMap(converage);

    const transformed = store.transformCoverage(coverageMap);

    const output = {};

    Object.keys(transformed.map.data).forEach(key => {
    const value = transformed.map.data[key];
    if (value.data) {
    output[key] = value.data;
    } else {
    output[key] = value;
    }
    });

    fs.writeFileSync('.nyc_output/out.json', JSON.stringify(output), 'utf8');
    fs.writeFileSync('out_transform.json', JSON.stringify(transformed), 'utf8');
    fs.writeFileSync('out_backup.json', unmappedCoverage, 'utf8');