mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-05-31 07:11:00 +02:00
Merge pull request #21189 from calixteman/issue21185
Use Istanbul instrumentation for unittestcli code coverage
This commit is contained in:
commit
0c5eaeeac6
40
external/ccov/coverage_format.mjs
vendored
Normal file
40
external/ccov/coverage_format.mjs
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/* Copyright 2026 Mozilla Foundation
|
||||
*
|
||||
* 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 COVERAGE_FORMAT_TO_REPORTER = {
|
||||
info: "lcovonly",
|
||||
html: "html",
|
||||
json: "json",
|
||||
text: "text",
|
||||
cobertura: "cobertura",
|
||||
clover: "clover",
|
||||
};
|
||||
|
||||
function parseCoverageFormats(str) {
|
||||
const formats = new Set();
|
||||
for (const fmt of (str ?? "").split(",")) {
|
||||
const name = fmt.trim();
|
||||
if (name && COVERAGE_FORMAT_TO_REPORTER[name]) {
|
||||
formats.add(name);
|
||||
} else if (name) {
|
||||
console.warn(
|
||||
`### Unknown coverage format "${name}", valid values: ${Object.keys(COVERAGE_FORMAT_TO_REPORTER).join(", ")}`
|
||||
);
|
||||
}
|
||||
}
|
||||
return formats.size > 0 ? formats : new Set(["info"]);
|
||||
}
|
||||
|
||||
export { COVERAGE_FORMAT_TO_REPORTER, parseCoverageFormats };
|
||||
121
gulpfile.mjs
121
gulpfile.mjs
@ -18,6 +18,10 @@ import {
|
||||
babelPluginStripSrcPath,
|
||||
preprocessPDFJSCode,
|
||||
} from "./external/builder/babel-plugin-pdfjs-preprocessor.mjs";
|
||||
import {
|
||||
COVERAGE_FORMAT_TO_REPORTER,
|
||||
parseCoverageFormats,
|
||||
} from "./external/ccov/coverage_format.mjs";
|
||||
import { exec, execSync, spawn, spawnSync } from "child_process";
|
||||
import autoprefixer from "autoprefixer";
|
||||
import babel from "@babel/core";
|
||||
@ -27,7 +31,10 @@ import { finished } from "stream/promises";
|
||||
import fs from "fs";
|
||||
import gulp from "gulp";
|
||||
import hljs from "highlight.js";
|
||||
import istanbulCoverage from "istanbul-lib-coverage";
|
||||
import istanbulReportGenerator from "istanbul-reports";
|
||||
import layouts from "@metalsmith/layouts";
|
||||
import libReport from "istanbul-lib-report";
|
||||
import markdown from "@metalsmith/markdown";
|
||||
import Metalsmith from "metalsmith";
|
||||
import ordered from "ordered-read-streams";
|
||||
@ -788,7 +795,7 @@ function runTests(testsName, { bot = false } = {}) {
|
||||
const result = spawnSync(
|
||||
"node",
|
||||
[
|
||||
path.join(__dirname, "external/coverage_search/coverage_search.mjs"),
|
||||
path.join(__dirname, "external/ccov/coverage_search.mjs"),
|
||||
`--code=${codeArg}`,
|
||||
`--coverage-dir=${coverageDir}`,
|
||||
],
|
||||
@ -948,7 +955,7 @@ gulp.task("coverage_search", function (done) {
|
||||
const result = spawnSync(
|
||||
"node",
|
||||
[
|
||||
path.join(__dirname, "external/coverage_search/coverage_search.mjs"),
|
||||
path.join(__dirname, "external/ccov/coverage_search.mjs"),
|
||||
`--code=${codeArg}`,
|
||||
`--coverage-dir=${coverageDir}`,
|
||||
],
|
||||
@ -1714,6 +1721,7 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) {
|
||||
},
|
||||
};
|
||||
const enableSourceMaps = bundleDefines.TESTING;
|
||||
const enableCoverage = bundleDefines.COVERAGE;
|
||||
|
||||
function preprocessLib(file, _enc, callback) {
|
||||
const skipBabel = bundleDefines.SKIP_BABEL;
|
||||
@ -1733,7 +1741,32 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) {
|
||||
// Calculate relative path from output directory to source file
|
||||
const relativeSourcePath = path.relative(outputFileDir, file.path);
|
||||
|
||||
const plugins = [
|
||||
[babelPluginPDFJSPreprocessor, ctx],
|
||||
[babelPluginStripSrcPath],
|
||||
];
|
||||
if (enableCoverage) {
|
||||
plugins.push([
|
||||
"babel-plugin-istanbul",
|
||||
{
|
||||
cwd: __dirname,
|
||||
include: ["src/**/*.js", "web/**/*.js"],
|
||||
},
|
||||
]);
|
||||
}
|
||||
plugins.push([
|
||||
"add-header-comment",
|
||||
{
|
||||
header: licenseHeader,
|
||||
},
|
||||
]);
|
||||
|
||||
const result = babel.transform(file.contents.toString(), {
|
||||
...(enableCoverage && {
|
||||
filename: file.path,
|
||||
babelrc: false,
|
||||
configFile: false,
|
||||
}),
|
||||
sourceType: "module",
|
||||
presets: skipBabel
|
||||
? undefined
|
||||
@ -1743,16 +1776,7 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) {
|
||||
{ ...BABEL_PRESET_ENV_OPTS, loose: false, modules: false },
|
||||
],
|
||||
],
|
||||
plugins: [
|
||||
[babelPluginPDFJSPreprocessor, ctx],
|
||||
[babelPluginStripSrcPath],
|
||||
[
|
||||
"add-header-comment",
|
||||
{
|
||||
header: licenseHeader,
|
||||
},
|
||||
],
|
||||
],
|
||||
plugins,
|
||||
targets: BABEL_TARGETS,
|
||||
sourceMaps: enableSourceMaps,
|
||||
sourceFileName: relativeSourcePath,
|
||||
@ -1789,6 +1813,10 @@ function buildLib(defines, dir) {
|
||||
BUNDLE_VERSION: versionInfo.version,
|
||||
BUNDLE_BUILD: versionInfo.commit,
|
||||
TESTING: defines.TESTING ?? process.env.TESTING === "true",
|
||||
COVERAGE:
|
||||
defines.COVERAGE ??
|
||||
(process.argv.includes("--coverage") ||
|
||||
process.argv.includes("--coverage-per-test")),
|
||||
DEFAULT_FTL: getDefaultFtl(),
|
||||
};
|
||||
|
||||
@ -2164,40 +2192,63 @@ gulp.task(
|
||||
},
|
||||
function runUnitTestCli(done) {
|
||||
const useCoverage = process.argv.includes("--coverage");
|
||||
const coverageDir =
|
||||
getArgValue("--coverage-output") || BUILD_DIR + "coverage";
|
||||
const coverageFormats = parseCoverageFormats(
|
||||
getArgValue("--coverage-formats")
|
||||
);
|
||||
|
||||
const coverageFile = path.join(
|
||||
__dirname,
|
||||
BUILD_DIR,
|
||||
"tmp",
|
||||
"unittestcli-coverage.json"
|
||||
);
|
||||
const env = { ...process.env };
|
||||
if (useCoverage) {
|
||||
console.log("\n### Running unit tests with code coverage");
|
||||
env.UNITTESTCLI_COVERAGE_FILE = coverageFile;
|
||||
fs.rmSync(coverageFile, { force: true });
|
||||
}
|
||||
|
||||
let jasmineProcess;
|
||||
if (useCoverage) {
|
||||
const options = [
|
||||
"node_modules/c8/bin/c8.js",
|
||||
"node",
|
||||
"--max-http-header-size=80000",
|
||||
"node_modules/jasmine/bin/jasmine",
|
||||
"JASMINE_CONFIG_PATH=test/unit/clitests.json",
|
||||
];
|
||||
jasmineProcess = spawn("node", options, { stdio: "inherit" });
|
||||
} else {
|
||||
const options = [
|
||||
"--enable-source-maps",
|
||||
"node_modules/jasmine/bin/jasmine",
|
||||
"JASMINE_CONFIG_PATH=test/unit/clitests.json",
|
||||
];
|
||||
jasmineProcess = startNode(options, { stdio: "inherit" });
|
||||
}
|
||||
const options = [
|
||||
"--enable-source-maps",
|
||||
"node_modules/jasmine/bin/jasmine",
|
||||
"JASMINE_CONFIG_PATH=test/unit/clitests.json",
|
||||
];
|
||||
const jasmineProcess = startNode(options, { stdio: "inherit", env });
|
||||
|
||||
jasmineProcess.on("close", function (code) {
|
||||
if (useCoverage) {
|
||||
if (fs.existsSync(coverageFile)) {
|
||||
const rawCoverage = JSON.parse(
|
||||
fs.readFileSync(coverageFile, "utf8")
|
||||
);
|
||||
const coverageMap = istanbulCoverage.createCoverageMap(rawCoverage);
|
||||
const context = libReport.createContext({
|
||||
dir: coverageDir,
|
||||
coverageMap,
|
||||
});
|
||||
for (const fmt of coverageFormats) {
|
||||
istanbulReportGenerator
|
||||
.create(COVERAGE_FORMAT_TO_REPORTER[fmt], {
|
||||
projectRoot: __dirname,
|
||||
})
|
||||
.execute(context);
|
||||
}
|
||||
console.log(
|
||||
`\n### Code coverage report generated in ${coverageDir} directory`
|
||||
);
|
||||
} else {
|
||||
console.warn(
|
||||
`\n### No coverage data found at ${coverageFile}. Did the build include 'babel-plugin-istanbul'?`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (code !== 0) {
|
||||
done(new Error("Unit tests failed."));
|
||||
return;
|
||||
}
|
||||
if (useCoverage) {
|
||||
console.log(
|
||||
"\n### Code coverage report generated in ./build/coverage directory"
|
||||
);
|
||||
}
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
82
package-lock.json
generated
82
package-lock.json
generated
@ -22,7 +22,6 @@
|
||||
"babel-loader": "^10.1.1",
|
||||
"babel-plugin-add-header-comment": "^1.0.3",
|
||||
"babel-plugin-istanbul": "^8.0.0",
|
||||
"c8": "^11.0.0",
|
||||
"cached-iterable": "^0.3.0",
|
||||
"caniuse-lite": "^1.0.30001791",
|
||||
"core-js": "^3.49.0",
|
||||
@ -1598,16 +1597,6 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bcoe/v8-coverage": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
|
||||
"integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@cacheable/memory": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.0.8.tgz",
|
||||
@ -2930,13 +2919,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/istanbul-lib-coverage": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
|
||||
"integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
@ -4450,55 +4432,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/c8": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/c8/-/c8-11.0.0.tgz",
|
||||
"integrity": "sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@bcoe/v8-coverage": "^1.0.1",
|
||||
"@istanbuljs/schema": "^0.1.3",
|
||||
"find-up": "^5.0.0",
|
||||
"foreground-child": "^3.1.1",
|
||||
"istanbul-lib-coverage": "^3.2.0",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
"istanbul-reports": "^3.1.6",
|
||||
"test-exclude": "^8.0.0",
|
||||
"v8-to-istanbul": "^9.0.0",
|
||||
"yargs": "^17.7.2",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"c8": "bin/c8.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"monocart-coverage-reports": "^2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"monocart-coverage-reports": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/c8/node_modules/test-exclude": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz",
|
||||
"integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@istanbuljs/schema": "^0.1.2",
|
||||
"glob": "^13.0.6",
|
||||
"minimatch": "^10.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/cacheable": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.3.3.tgz",
|
||||
@ -12224,21 +12157,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/v8-to-istanbul": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
|
||||
"integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.12",
|
||||
"@types/istanbul-lib-coverage": "^2.0.1",
|
||||
"convert-source-map": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/v8flags": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz",
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
"babel-loader": "^10.1.1",
|
||||
"babel-plugin-add-header-comment": "^1.0.3",
|
||||
"babel-plugin-istanbul": "^8.0.0",
|
||||
"c8": "^11.0.0",
|
||||
"cached-iterable": "^0.3.0",
|
||||
"caniuse-lite": "^1.0.30001791",
|
||||
"core-js": "^3.49.0",
|
||||
|
||||
@ -15,6 +15,10 @@
|
||||
/* eslint-disable no-var */
|
||||
|
||||
import { copySubtreeSync, ensureDirSync } from "./testutils.mjs";
|
||||
import {
|
||||
COVERAGE_FORMAT_TO_REPORTER,
|
||||
parseCoverageFormats,
|
||||
} from "../external/ccov/coverage_format.mjs";
|
||||
import {
|
||||
downloadManifestFiles,
|
||||
verifyManifestFiles,
|
||||
@ -1107,30 +1111,6 @@ function getSession(browser) {
|
||||
return sessions.find(session => session.name === browser);
|
||||
}
|
||||
|
||||
const COVERAGE_FORMAT_TO_REPORTER = {
|
||||
info: "lcovonly",
|
||||
html: "html",
|
||||
json: "json",
|
||||
text: "text",
|
||||
cobertura: "cobertura",
|
||||
clover: "clover",
|
||||
};
|
||||
|
||||
function parseCoverageFormats(str) {
|
||||
const formats = new Set();
|
||||
for (const fmt of str.split(",")) {
|
||||
const name = fmt.trim();
|
||||
if (name && COVERAGE_FORMAT_TO_REPORTER[name]) {
|
||||
formats.add(name);
|
||||
} else if (name) {
|
||||
console.warn(
|
||||
`### Unknown coverage format "${name}", valid values: ${Object.keys(COVERAGE_FORMAT_TO_REPORTER).join(", ")}`
|
||||
);
|
||||
}
|
||||
}
|
||||
return formats.size > 0 ? formats : new Set(["info"]);
|
||||
}
|
||||
|
||||
function accumulatePerTestCoverage(testId, counts) {
|
||||
let testIdx = perTestIdMap.get(testId);
|
||||
if (testIdx === undefined) {
|
||||
|
||||
@ -18,6 +18,8 @@ import {
|
||||
setVerbosityLevel,
|
||||
VerbosityLevel,
|
||||
} from "../../src/shared/util.js";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
// Sets longer timeout, similar to `jasmine-boot.js`.
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
|
||||
@ -32,3 +34,13 @@ if (!isNodeJS) {
|
||||
// Reduce the amount of console "spam", by ignoring `info`/`warn` calls,
|
||||
// when running the unit-tests in Node.js/Travis.
|
||||
setVerbosityLevel(VerbosityLevel.ERRORS);
|
||||
|
||||
const coverageFile = process.env.UNITTESTCLI_COVERAGE_FILE;
|
||||
if (coverageFile) {
|
||||
process.on("exit", () => {
|
||||
if (globalThis.__coverage__) {
|
||||
fs.mkdirSync(path.dirname(coverageFile), { recursive: true });
|
||||
fs.writeFileSync(coverageFile, JSON.stringify(globalThis.__coverage__));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user