@fluid-internal/mocha-test-setup 3.0.2 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mocharc.cjs +19 -0
- package/CHANGELOG.md +8 -0
- package/README.md +9 -13
- package/lib/mocharcCommon.d.ts.map +1 -1
- package/lib/mocharcCommon.js +7 -1
- package/lib/mocharcCommon.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/xunitReporter.d.ts +67 -0
- package/lib/xunitReporter.d.ts.map +1 -0
- package/lib/xunitReporter.js +74 -0
- package/lib/xunitReporter.js.map +1 -0
- package/package.json +16 -7
- package/src/mocharcCommon.ts +8 -1
- package/src/packageVersion.ts +1 -1
- package/src/xunitReporter.ts +113 -0
- package/test-config.json +2 -2
- package/xunit-reporter-cjswrapper.cjs +15 -0
package/.mocharc.cjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
// This package's own self-tests don't use its own `getFluidTestMochaConfig()` (unlike its consumers):
|
|
9
|
+
// that helper wires up `mocha-multi-reporters` and `FluidXunitReporter`'s JUnit-compatible XML output,
|
|
10
|
+
// which these straightforward unit tests don't need, and using it here would mean this package
|
|
11
|
+
// `require`-ing itself as a dependency of its own test run.
|
|
12
|
+
module.exports = {
|
|
13
|
+
require: ["source-map-support/register"],
|
|
14
|
+
recursive: true,
|
|
15
|
+
spec: "lib/test/**/*.spec.js",
|
|
16
|
+
"unhandled-rejections": "strict",
|
|
17
|
+
// Fail the test run if no tests are found/run, consistent with `getFluidTestMochaConfig`'s consumers.
|
|
18
|
+
"fail-zero": true,
|
|
19
|
+
};
|
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# @fluid-internal/mocha-test-setup
|
|
2
2
|
|
|
3
|
-
<!--
|
|
4
|
-
|
|
3
|
+
<!-- markdown-magic:begin {"transform":"library-readme-header","headingLevel":2} -->
|
|
5
4
|
<!-- prettier-ignore-start -->
|
|
6
5
|
<!-- NOTE: This section is automatically generated using @fluid-tools/markdown-magic. Do not update these generated contents directly. -->
|
|
7
6
|
|
|
@@ -10,8 +9,7 @@
|
|
|
10
9
|
**We do not guarantee the stability of this package or its APIs.**
|
|
11
10
|
|
|
12
11
|
<!-- prettier-ignore-end -->
|
|
13
|
-
|
|
14
|
-
<!-- AUTO-GENERATED-CONTENT:END -->
|
|
12
|
+
<!-- markdown-magic:end -->
|
|
15
13
|
|
|
16
14
|
This package has a few main purposes:
|
|
17
15
|
|
|
@@ -187,8 +185,7 @@ to the module with that implementation should **not** be specified with the `--r
|
|
|
187
185
|
This package has logic that needs the custom logger to be imported/executed at a particular time, and we ensure that
|
|
188
186
|
by requiring that the path be provided through that environment variable.
|
|
189
187
|
|
|
190
|
-
<!--
|
|
191
|
-
|
|
188
|
+
<!-- markdown-magic:begin {"transform":"readme-footer","headingLevel":2} -->
|
|
192
189
|
<!-- prettier-ignore-start -->
|
|
193
190
|
<!-- NOTE: This section is automatically generated using @fluid-tools/markdown-magic. Do not update these generated contents directly. -->
|
|
194
191
|
|
|
@@ -196,16 +193,16 @@ by requiring that the path be provided through that environment variable.
|
|
|
196
193
|
|
|
197
194
|
You can [contribute](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md) to Fluid Framework in these ways:
|
|
198
195
|
|
|
199
|
-
-
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
-
|
|
196
|
+
- Answer questions in [GitHub Discussions](https://github.com/microsoft/FluidFramework/discussions).
|
|
197
|
+
- [Submit bug reports](https://github.com/microsoft/FluidFramework/issues) and help verify fixes.
|
|
198
|
+
- Review [source code changes](https://github.com/microsoft/FluidFramework/pulls).
|
|
199
|
+
- [Contribute bug fixes](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md).
|
|
203
200
|
|
|
204
201
|
For detailed instructions, read the [repo documentation](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Home.md).
|
|
205
202
|
|
|
206
203
|
This project follows the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
|
207
204
|
For more information, read the [Code of Conduct frequently asked questions](https://opensource.microsoft.com/codeofconduct/faq/).
|
|
208
|
-
For questions or comments, contact
|
|
205
|
+
For questions or comments, contact <opencode@microsoft.com>.
|
|
209
206
|
|
|
210
207
|
This project may contain Microsoft trademarks or logos for Microsoft projects, products, or services.
|
|
211
208
|
Use of these trademarks or logos must follow Microsoft’s [Trademark & Brand Guidelines](https://www.microsoft.com/trademarks).
|
|
@@ -226,5 +223,4 @@ Use of these trademarks or logos must follow Microsoft's [Trademark & Brand Guid
|
|
|
226
223
|
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
|
|
227
224
|
|
|
228
225
|
<!-- prettier-ignore-end -->
|
|
229
|
-
|
|
230
|
-
<!-- AUTO-GENERATED-CONTENT:END -->
|
|
226
|
+
<!-- markdown-magic:end -->
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mocharcCommon.d.ts","sourceRoot":"","sources":["../src/mocharcCommon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACtC,UAAU,EAAE,MAAM,EAClB,yBAAyB,CAAC,EAAE,MAAM,EAAE,EACpC,gBAAgB,CAAC,EAAE,MAAM,GACvB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"mocharcCommon.d.ts","sourceRoot":"","sources":["../src/mocharcCommon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACtC,UAAU,EAAE,MAAM,EAClB,yBAAyB,CAAC,EAAE,MAAM,EAAE,EACpC,gBAAgB,CAAC,EAAE,MAAM,GACvB,oBAAoB,CAgHtB"}
|
package/lib/mocharcCommon.js
CHANGED
|
@@ -91,8 +91,14 @@ export function getFluidTestMochaConfig(packageDir, additionalRequiredModules, t
|
|
|
91
91
|
console.log(`Writing test results relative to package to nyc/${outputFilePrefix}junit-report.xml`);
|
|
92
92
|
}
|
|
93
93
|
const suiteName = reportPrefix !== undefined ? `${packageJson.name} - ${reportPrefix}` : packageJson.name;
|
|
94
|
+
// This must be the exact module specifier mocha-multi-reporters will `require(...)` to load the reporter
|
|
95
|
+
// (see its source: https://github.com/stevemao/mocha-multi-reporters/blob/master/lib/MultiReporters.js),
|
|
96
|
+
// i.e. it can't be shortened to some arbitrary friendly name. It also determines the reporter-specific
|
|
97
|
+
// option key mocha-multi-reporters expects below (and in test-config.json): it camelCases this exact
|
|
98
|
+
// string and appends "ReporterOptions" (e.g. "@foo/bar/baz" -> "fooBarBazReporterOptions").
|
|
99
|
+
const xunitReporterName = "@fluid-internal/mocha-test-setup/xunit-reporter";
|
|
94
100
|
config["reporter-options"] = [
|
|
95
|
-
`configFile=${path.join(import.meta.dirname, "..", "test-config.json")},cmrOutput
|
|
101
|
+
`configFile=${path.join(import.meta.dirname, "..", "test-config.json")},cmrOutput=${xunitReporterName}+output+${outputFilePrefix}:${xunitReporterName}+suiteName+${suiteName}`,
|
|
96
102
|
];
|
|
97
103
|
}
|
|
98
104
|
if (process.env.FLUID_TEST_TIMEOUT !== undefined) {
|
package/lib/mocharcCommon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mocharcCommon.js","sourceRoot":"","sources":["../src/mocharcCommon.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Mocha configuration object returned by {@link getFluidTestMochaConfig}.\n */\nexport interface FluidTestMochaConfig {\n\trecursive: boolean;\n\trequire: string[];\n\t\"unhandled-rejections\": string;\n\t\"fail-zero\": boolean;\n\tignore: string[];\n\t\"node-option\": string[];\n\tspec: string;\n\texit?: boolean;\n\ttimeout?: number | string;\n\tfgrep?: string[];\n\treporter?: string;\n\treporterOptions?: string[];\n\t\"reporter-options\"?: string[];\n\t\"forbid-only\"?: boolean;\n}\n\n/**\n * Get the mocha configuration for running tests using the conventions followed in the Fluid Framework repository.\n *\n * @param packageDir - the directory of the package, typically set using `__dirname`\n * @param additionalRequiredModules - modules to require in addition to the standard set.\n * @param testReportPrefix - prefix for the test output report file names.\n * @remarks\n * Additional configuration can be provided via environment variables: see {@link file://./README.md}.\n *\n * Users desiring exact control over the `spec` from the CLI should delete or replace the spec from the returned config, since mocha's behavior is to extend it, not override it.\n */\nexport function getFluidTestMochaConfig(\n\tpackageDir: string,\n\tadditionalRequiredModules?: string[],\n\ttestReportPrefix?: string,\n): FluidTestMochaConfig {\n\tconst requiredModules = [\n\t\t// General mocha setup e.g. suppresses console.log,\n\t\t// This has to be before others (except logger) so that registerMochaTestWrapperFuncs is available\n\t\t\"@fluid-internal/mocha-test-setup\",\n\t\t\"source-map-support/register\",\n\t\t...(additionalRequiredModules ?? []),\n\t];\n\n\tif (process.env.FLUID_TEST_LOGGER_PKG_SPECIFIER !== undefined) {\n\t\t// Inject implementation of createTestLogger, put it first before mocha-test-setup\n\t\trequiredModules.unshift(process.env.FLUID_TEST_LOGGER_PKG_SPECIFIER);\n\t}\n\n\tlet reportPrefix = testReportPrefix;\n\tlet defaultSpec = \"lib/test\";\n\tif (process.env.FLUID_TEST_MODULE_SYSTEM === \"CJS\") {\n\t\tdefaultSpec = \"dist/test\";\n\t\tconst testVariant = process.env.FLUID_TEST_VARIANT;\n\t\tprocess.env.FLUID_TEST_VARIANT = testVariant !== undefined ? `CJS,${testVariant}` : \"CJS\";\n\t\treportPrefix = reportPrefix !== undefined ? `${reportPrefix}-CJS` : \"CJS\";\n\t}\n\n\tconst config: FluidTestMochaConfig = {\n\t\t\"recursive\": true,\n\t\t\"require\": requiredModules,\n\t\t\"unhandled-rejections\": \"strict\",\n\t\t// Fail the test run if no tests are found/run. This catches cases where test files fail to\n\t\t// load silently (e.g. due to broken imports), which would otherwise produce a green \"0 passing\"\n\t\t// result with exit code 0.\n\t\t\"fail-zero\": true,\n\t\tignore: [\n\t\t\t// Ignore \"tools\" which are scripts intended to be run, not part of the test suite.\n\t\t\t\"**/*.tool.{js,cjs,mjs}\",\n\t\t],\n\t\t\"node-option\": [\n\t\t\t// Allow test-only indexes to be imported. Search the FF repo for package.json files with this condition to see example usage.\n\t\t\t\"conditions=allow-ff-test-exports\",\n\t\t\t// Performance tests benefit from having access to GC, and memory tests require it.\n\t\t\t// Exposing it here avoids all packages which do perf testing from having to expose it.\n\t\t\t// Note that since \"node-option\" is explicitly set,\n\t\t\t// these must be provided here and not via mocha's --v8-expose-gc.\n\t\t\t\"expose-gc\",\n\t\t],\n\t\tspec: process.env.MOCHA_SPEC ?? defaultSpec,\n\t};\n\n\t// This approach to checking for this flag is consistent with some (but not all) others in this file,\n\t// but not with tools/benchmark/src/Configuration.ts.\n\t// For now, undefined, \"1\" and \"true\" should work consistently across all known use, and \"1\" is the main form we explicitly use.\n\t// All these should be made to match, see AB#69054.\n\tif (process.env.FLUID_TEST_PERF_MODE !== undefined) {\n\t\tif (process.env.SILENT_TEST_OUTPUT === undefined) {\n\t\t\tconsole.log(`Running performance tests...`);\n\t\t}\n\n\t\t// Some perf tests are often quite slow, and we don't want to lose the data by hitting a timeout.\n\t\t// This is 1000 seconds, so ~16 minutes.\n\t\t// This can be overridden by setting FLUID_TEST_TIMEOUT to a different value if desired.\n\t\tconfig.timeout = 1_000_000;\n\n\t\t// If there is no filter specified, limit to benchmarks.\n\t\t// If mocha allowed multiple filters to all be applied to further narrow results, we would do this unconditionally.\n\t\tif (!(process.argv.includes(\"--fgrep\") || process.argv.includes(\"--grep\"))) {\n\t\t\tconfig.fgrep = [\"@Benchmark\"];\n\t\t}\n\n\t\tconfig.reporter = \"@fluid-tools/benchmark/dist/mocha/Reporter.js\";\n\t\tif (!process.argv.includes(\"--reporterOptions\")) {\n\t\t\t// If report options were not specified, default to:\n\t\t\tconfig.reporterOptions = [\"reportFile=./benchmarkOutput.json\"];\n\t\t}\n\t} else {\n\t\tconst packageJsonPath = path.join(packageDir, \"package.json\");\n\t\tconst packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as {\n\t\t\tname: string;\n\t\t};\n\t\tconfig.reporter = `mocha-multi-reporters`;\n\t\t// See https://www.npmjs.com/package/mocha-multi-reporters#cmroutput-option\n\t\tconst outputFilePrefix = reportPrefix !== undefined ? `${reportPrefix}-` : \"\";\n\t\tif (process.env.SILENT_TEST_OUTPUT === undefined) {\n\t\t\tconsole.log(\n\t\t\t\t`Writing test results relative to package to nyc/${outputFilePrefix}junit-report.xml`,\n\t\t\t);\n\t\t}\n\t\tconst suiteName =\n\t\t\treportPrefix !== undefined ? `${packageJson.name} - ${reportPrefix}` : packageJson.name;\n\t\tconfig[\"reporter-options\"] = [\n\t\t\t`configFile=${path.join(\n\t\t\t\timport.meta.dirname,\n\t\t\t\t\"..\",\n\t\t\t\t\"test-config.json\",\n\t\t\t)},cmrOutput=xunit+output+${outputFilePrefix}:xunit+suiteName+${suiteName}`,\n\t\t];\n\t}\n\n\tif (process.env.FLUID_TEST_TIMEOUT !== undefined) {\n\t\tconfig.timeout = process.env.FLUID_TEST_TIMEOUT;\n\t}\n\n\tif (process.env.FLUID_TEST_FORBID_ONLY !== undefined) {\n\t\tconfig[\"forbid-only\"] = true;\n\t}\n\n\treturn config;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mocharcCommon.js","sourceRoot":"","sources":["../src/mocharcCommon.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Mocha configuration object returned by {@link getFluidTestMochaConfig}.\n */\nexport interface FluidTestMochaConfig {\n\trecursive: boolean;\n\trequire: string[];\n\t\"unhandled-rejections\": string;\n\t\"fail-zero\": boolean;\n\tignore: string[];\n\t\"node-option\": string[];\n\tspec: string;\n\texit?: boolean;\n\ttimeout?: number | string;\n\tfgrep?: string[];\n\treporter?: string;\n\treporterOptions?: string[];\n\t\"reporter-options\"?: string[];\n\t\"forbid-only\"?: boolean;\n}\n\n/**\n * Get the mocha configuration for running tests using the conventions followed in the Fluid Framework repository.\n *\n * @param packageDir - the directory of the package, typically set using `__dirname`\n * @param additionalRequiredModules - modules to require in addition to the standard set.\n * @param testReportPrefix - prefix for the test output report file names.\n * @remarks\n * Additional configuration can be provided via environment variables: see {@link file://./README.md}.\n *\n * Users desiring exact control over the `spec` from the CLI should delete or replace the spec from the returned config, since mocha's behavior is to extend it, not override it.\n */\nexport function getFluidTestMochaConfig(\n\tpackageDir: string,\n\tadditionalRequiredModules?: string[],\n\ttestReportPrefix?: string,\n): FluidTestMochaConfig {\n\tconst requiredModules = [\n\t\t// General mocha setup e.g. suppresses console.log,\n\t\t// This has to be before others (except logger) so that registerMochaTestWrapperFuncs is available\n\t\t\"@fluid-internal/mocha-test-setup\",\n\t\t\"source-map-support/register\",\n\t\t...(additionalRequiredModules ?? []),\n\t];\n\n\tif (process.env.FLUID_TEST_LOGGER_PKG_SPECIFIER !== undefined) {\n\t\t// Inject implementation of createTestLogger, put it first before mocha-test-setup\n\t\trequiredModules.unshift(process.env.FLUID_TEST_LOGGER_PKG_SPECIFIER);\n\t}\n\n\tlet reportPrefix = testReportPrefix;\n\tlet defaultSpec = \"lib/test\";\n\tif (process.env.FLUID_TEST_MODULE_SYSTEM === \"CJS\") {\n\t\tdefaultSpec = \"dist/test\";\n\t\tconst testVariant = process.env.FLUID_TEST_VARIANT;\n\t\tprocess.env.FLUID_TEST_VARIANT = testVariant !== undefined ? `CJS,${testVariant}` : \"CJS\";\n\t\treportPrefix = reportPrefix !== undefined ? `${reportPrefix}-CJS` : \"CJS\";\n\t}\n\n\tconst config: FluidTestMochaConfig = {\n\t\t\"recursive\": true,\n\t\t\"require\": requiredModules,\n\t\t\"unhandled-rejections\": \"strict\",\n\t\t// Fail the test run if no tests are found/run. This catches cases where test files fail to\n\t\t// load silently (e.g. due to broken imports), which would otherwise produce a green \"0 passing\"\n\t\t// result with exit code 0.\n\t\t\"fail-zero\": true,\n\t\tignore: [\n\t\t\t// Ignore \"tools\" which are scripts intended to be run, not part of the test suite.\n\t\t\t\"**/*.tool.{js,cjs,mjs}\",\n\t\t],\n\t\t\"node-option\": [\n\t\t\t// Allow test-only indexes to be imported. Search the FF repo for package.json files with this condition to see example usage.\n\t\t\t\"conditions=allow-ff-test-exports\",\n\t\t\t// Performance tests benefit from having access to GC, and memory tests require it.\n\t\t\t// Exposing it here avoids all packages which do perf testing from having to expose it.\n\t\t\t// Note that since \"node-option\" is explicitly set,\n\t\t\t// these must be provided here and not via mocha's --v8-expose-gc.\n\t\t\t\"expose-gc\",\n\t\t],\n\t\tspec: process.env.MOCHA_SPEC ?? defaultSpec,\n\t};\n\n\t// This approach to checking for this flag is consistent with some (but not all) others in this file,\n\t// but not with tools/benchmark/src/Configuration.ts.\n\t// For now, undefined, \"1\" and \"true\" should work consistently across all known use, and \"1\" is the main form we explicitly use.\n\t// All these should be made to match, see AB#69054.\n\tif (process.env.FLUID_TEST_PERF_MODE !== undefined) {\n\t\tif (process.env.SILENT_TEST_OUTPUT === undefined) {\n\t\t\tconsole.log(`Running performance tests...`);\n\t\t}\n\n\t\t// Some perf tests are often quite slow, and we don't want to lose the data by hitting a timeout.\n\t\t// This is 1000 seconds, so ~16 minutes.\n\t\t// This can be overridden by setting FLUID_TEST_TIMEOUT to a different value if desired.\n\t\tconfig.timeout = 1_000_000;\n\n\t\t// If there is no filter specified, limit to benchmarks.\n\t\t// If mocha allowed multiple filters to all be applied to further narrow results, we would do this unconditionally.\n\t\tif (!(process.argv.includes(\"--fgrep\") || process.argv.includes(\"--grep\"))) {\n\t\t\tconfig.fgrep = [\"@Benchmark\"];\n\t\t}\n\n\t\tconfig.reporter = \"@fluid-tools/benchmark/dist/mocha/Reporter.js\";\n\t\tif (!process.argv.includes(\"--reporterOptions\")) {\n\t\t\t// If report options were not specified, default to:\n\t\t\tconfig.reporterOptions = [\"reportFile=./benchmarkOutput.json\"];\n\t\t}\n\t} else {\n\t\tconst packageJsonPath = path.join(packageDir, \"package.json\");\n\t\tconst packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as {\n\t\t\tname: string;\n\t\t};\n\t\tconfig.reporter = `mocha-multi-reporters`;\n\t\t// See https://www.npmjs.com/package/mocha-multi-reporters#cmroutput-option\n\n\t\tconst outputFilePrefix = reportPrefix !== undefined ? `${reportPrefix}-` : \"\";\n\t\tif (process.env.SILENT_TEST_OUTPUT === undefined) {\n\t\t\tconsole.log(\n\t\t\t\t`Writing test results relative to package to nyc/${outputFilePrefix}junit-report.xml`,\n\t\t\t);\n\t\t}\n\t\tconst suiteName =\n\t\t\treportPrefix !== undefined ? `${packageJson.name} - ${reportPrefix}` : packageJson.name;\n\t\t// This must be the exact module specifier mocha-multi-reporters will `require(...)` to load the reporter\n\t\t// (see its source: https://github.com/stevemao/mocha-multi-reporters/blob/master/lib/MultiReporters.js),\n\t\t// i.e. it can't be shortened to some arbitrary friendly name. It also determines the reporter-specific\n\t\t// option key mocha-multi-reporters expects below (and in test-config.json): it camelCases this exact\n\t\t// string and appends \"ReporterOptions\" (e.g. \"@foo/bar/baz\" -> \"fooBarBazReporterOptions\").\n\t\tconst xunitReporterName = \"@fluid-internal/mocha-test-setup/xunit-reporter\";\n\t\tconfig[\"reporter-options\"] = [\n\t\t\t`configFile=${path.join(\n\t\t\t\timport.meta.dirname,\n\t\t\t\t\"..\",\n\t\t\t\t\"test-config.json\",\n\t\t\t)},cmrOutput=${xunitReporterName}+output+${outputFilePrefix}:${xunitReporterName}+suiteName+${suiteName}`,\n\t\t];\n\t}\n\n\tif (process.env.FLUID_TEST_TIMEOUT !== undefined) {\n\t\tconfig.timeout = process.env.FLUID_TEST_TIMEOUT;\n\t}\n\n\tif (process.env.FLUID_TEST_FORBID_ONLY !== undefined) {\n\t\tconfig[\"forbid-only\"] = true;\n\t}\n\n\treturn config;\n}\n"]}
|
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluid-internal/mocha-test-setup";
|
|
8
|
-
export declare const pkgVersion = "3.0
|
|
8
|
+
export declare const pkgVersion = "3.2.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-internal/mocha-test-setup\";\nexport const pkgVersion = \"3.0
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluid-internal/mocha-test-setup\";\nexport const pkgVersion = \"3.2.0\";\n"]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Walks up from `startDir` looking for the repo root, identified by the presence of
|
|
7
|
+
* `pnpm-workspace.yaml`. Falls back to `startDir` if no such ancestor is found (e.g. if the workspace
|
|
8
|
+
* layout ever changes).
|
|
9
|
+
*
|
|
10
|
+
* @remarks Exported (in addition to being used internally) so tests can independently compute the
|
|
11
|
+
* expected `classname` for a given file without duplicating this logic.
|
|
12
|
+
*/
|
|
13
|
+
export declare function findRepoRoot(startDir: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* The subset of a Mocha `Test` that {@link FluidXunitReporter} cares about.
|
|
16
|
+
*/
|
|
17
|
+
interface JUnitTestLike {
|
|
18
|
+
/**
|
|
19
|
+
* Absolute path of the file the test is defined in, as set by Mocha.
|
|
20
|
+
*/
|
|
21
|
+
file?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The `Suite` (or nested `Suite`s) the test is defined in. `xunit`'s `test` method relies on
|
|
24
|
+
* `parent.fullTitle()`, and mocha's own `isPending()` implementation recurses into `parent.isPending()`,
|
|
25
|
+
* so the whole object (not just `fullTitle`) needs to be preserved when overriding it below.
|
|
26
|
+
*/
|
|
27
|
+
parent: object;
|
|
28
|
+
/**
|
|
29
|
+
* The test's fully qualified title: its own title, prefixed by its ancestor `describe` blocks' titles.
|
|
30
|
+
*/
|
|
31
|
+
fullTitle(): string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Minimal typing for mocha's built-in `xunit` reporter constructor and the `test` instance method
|
|
35
|
+
* {@link FluidXunitReporter} overrides.
|
|
36
|
+
*/
|
|
37
|
+
interface XUnitReporterInstance {
|
|
38
|
+
test(test: JUnitTestLike, options?: unknown): void;
|
|
39
|
+
}
|
|
40
|
+
declare const XUnitReporterCtor: new (runner: unknown, options: unknown) => XUnitReporterInstance;
|
|
41
|
+
/**
|
|
42
|
+
* A JUnit reporter for Mocha, based on mocha's built-in `xunit` reporter, that fixes two issues with the
|
|
43
|
+
* default `xunit` output when many packages' reports are viewed together in Azure DevOps's Tests tab.
|
|
44
|
+
*
|
|
45
|
+
* `name` (the `<testcase>`'s display title in Azure DevOps): `xunit` sets this to the test's own,
|
|
46
|
+
* non-fully-qualified title (e.g. `"increments"`), which frequently collides with other tests of the same
|
|
47
|
+
* name defined under different `describe` blocks or files. This override sets it to the fully qualified
|
|
48
|
+
* title instead (the full `describe`/`it` chain), which is unique.
|
|
49
|
+
*
|
|
50
|
+
* `classname` (used by Azure DevOps's JUnit importer to populate the "Test file" grouping — see
|
|
51
|
+
* `AutomatedTestStorage` in
|
|
52
|
+
* {@link https://github.com/microsoft/azure-pipelines-agent/blob/master/src/Agent.Worker/TestResults/Legacy/JunitResultReader.cs | JunitResultReader.cs}):
|
|
53
|
+
* `xunit` sets this to the fully qualified title as well, so that grouping showed test titles instead of
|
|
54
|
+
* file names. This override sets it to the path (relative to the repo root) of the file containing the
|
|
55
|
+
* test.
|
|
56
|
+
*
|
|
57
|
+
* All other behavior — notably, `xunit`'s single flat `<testsuite>` per report file — is unchanged, so
|
|
58
|
+
* this reporter is not subject to the Azure DevOps "Test Run" naming regression that `mocha-junit-reporter`
|
|
59
|
+
* (which emits one `<testsuite>` per `describe` block, rather than one per file) causes: Azure DevOps's
|
|
60
|
+
* JUnit importer falls back to a generic `JUnit_<file name>` run title whenever a report file contains more
|
|
61
|
+
* than one `<testsuite>` element, unconditionally, regardless of file or suite naming.
|
|
62
|
+
*/
|
|
63
|
+
export declare class FluidXunitReporter extends XUnitReporterCtor {
|
|
64
|
+
test(test: JUnitTestLike, options?: unknown): void;
|
|
65
|
+
}
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=xunitReporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xunitReporter.d.ts","sourceRoot":"","sources":["../src/xunitReporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAcrD;AAID;;GAEG;AACH,UAAU,aAAa;IACtB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,UAAU,qBAAqB;IAC9B,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACnD;AAED,QAAA,MAAM,iBAAiB,EAAuC,KAC7D,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,OAAO,KACZ,qBAAqB,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,kBAAmB,SAAQ,iBAAiB;IACjD,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;CAkBzD"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import Mocha from "mocha";
|
|
8
|
+
/**
|
|
9
|
+
* Walks up from `startDir` looking for the repo root, identified by the presence of
|
|
10
|
+
* `pnpm-workspace.yaml`. Falls back to `startDir` if no such ancestor is found (e.g. if the workspace
|
|
11
|
+
* layout ever changes).
|
|
12
|
+
*
|
|
13
|
+
* @remarks Exported (in addition to being used internally) so tests can independently compute the
|
|
14
|
+
* expected `classname` for a given file without duplicating this logic.
|
|
15
|
+
*/
|
|
16
|
+
export function findRepoRoot(startDir) {
|
|
17
|
+
let dir = startDir;
|
|
18
|
+
// eslint-disable-next-line no-constant-condition -- terminates via the `parent === dir` root check below
|
|
19
|
+
while (true) {
|
|
20
|
+
if (existsSync(path.join(dir, "pnpm-workspace.yaml"))) {
|
|
21
|
+
return dir;
|
|
22
|
+
}
|
|
23
|
+
const parent = path.dirname(dir);
|
|
24
|
+
if (parent === dir) {
|
|
25
|
+
// Reached the filesystem root without finding a workspace marker.
|
|
26
|
+
return startDir;
|
|
27
|
+
}
|
|
28
|
+
dir = parent;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const repoRoot = findRepoRoot(process.cwd());
|
|
32
|
+
const XUnitReporterCtor = Mocha.reporters.XUnit;
|
|
33
|
+
/**
|
|
34
|
+
* A JUnit reporter for Mocha, based on mocha's built-in `xunit` reporter, that fixes two issues with the
|
|
35
|
+
* default `xunit` output when many packages' reports are viewed together in Azure DevOps's Tests tab.
|
|
36
|
+
*
|
|
37
|
+
* `name` (the `<testcase>`'s display title in Azure DevOps): `xunit` sets this to the test's own,
|
|
38
|
+
* non-fully-qualified title (e.g. `"increments"`), which frequently collides with other tests of the same
|
|
39
|
+
* name defined under different `describe` blocks or files. This override sets it to the fully qualified
|
|
40
|
+
* title instead (the full `describe`/`it` chain), which is unique.
|
|
41
|
+
*
|
|
42
|
+
* `classname` (used by Azure DevOps's JUnit importer to populate the "Test file" grouping — see
|
|
43
|
+
* `AutomatedTestStorage` in
|
|
44
|
+
* {@link https://github.com/microsoft/azure-pipelines-agent/blob/master/src/Agent.Worker/TestResults/Legacy/JunitResultReader.cs | JunitResultReader.cs}):
|
|
45
|
+
* `xunit` sets this to the fully qualified title as well, so that grouping showed test titles instead of
|
|
46
|
+
* file names. This override sets it to the path (relative to the repo root) of the file containing the
|
|
47
|
+
* test.
|
|
48
|
+
*
|
|
49
|
+
* All other behavior — notably, `xunit`'s single flat `<testsuite>` per report file — is unchanged, so
|
|
50
|
+
* this reporter is not subject to the Azure DevOps "Test Run" naming regression that `mocha-junit-reporter`
|
|
51
|
+
* (which emits one `<testsuite>` per `describe` block, rather than one per file) causes: Azure DevOps's
|
|
52
|
+
* JUnit importer falls back to a generic `JUnit_<file name>` run title whenever a report file contains more
|
|
53
|
+
* than one `<testsuite>` element, unconditionally, regardless of file or suite naming.
|
|
54
|
+
*/
|
|
55
|
+
export class FluidXunitReporter extends XUnitReporterCtor {
|
|
56
|
+
test(test, options) {
|
|
57
|
+
const classname = test.file === undefined ? test.fullTitle() : path.relative(repoRoot, test.file);
|
|
58
|
+
// `xunit`'s `test` method reads `test.title` for `name` and `test.parent.fullTitle()` for
|
|
59
|
+
// `classname`. Wrap `test` and `test.parent` (via prototypal inheritance, so unrelated
|
|
60
|
+
// properties/methods they're relied on for — `file`, `duration`, `state`, `err`, `isPending()`
|
|
61
|
+
// (which recurses into `parent.isPending()`) — still resolve correctly) to present the values
|
|
62
|
+
// wanted here, without mutating the shared `test`/`test.parent` objects that other reporters
|
|
63
|
+
// running in the same `mocha-multi-reporters` process also read.
|
|
64
|
+
const wrappedParent = Object.create(test.parent, {
|
|
65
|
+
fullTitle: { value: () => classname, enumerable: true },
|
|
66
|
+
});
|
|
67
|
+
const wrapped = Object.create(test, {
|
|
68
|
+
title: { value: test.fullTitle(), enumerable: true },
|
|
69
|
+
parent: { value: wrappedParent, enumerable: true },
|
|
70
|
+
});
|
|
71
|
+
super.test(wrapped, options);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=xunitReporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xunitReporter.js","sourceRoot":"","sources":["../src/xunitReporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC5C,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,yGAAyG;IACzG,OAAO,IAAI,EAAE,CAAC;QACb,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,EAAE,CAAC;YACvD,OAAO,GAAG,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACpB,kEAAkE;YAClE,OAAO,QAAQ,CAAC;QACjB,CAAC;QACD,GAAG,GAAG,MAAM,CAAC;IACd,CAAC;AACF,CAAC;AAED,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAgC7C,MAAM,iBAAiB,GAAG,KAAK,CAAC,SAAS,CAAC,KAGhB,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,kBAAmB,SAAQ,iBAAiB;IACjD,IAAI,CAAC,IAAmB,EAAE,OAAiB;QACjD,MAAM,SAAS,GACd,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACjF,0FAA0F;QAC1F,uFAAuF;QACvF,+FAA+F;QAC/F,8FAA8F;QAC9F,6FAA6F;QAC7F,iEAAiE;QACjE,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE;YAChD,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE;SACvD,CAA4B,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;YACnC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE;YACpD,MAAM,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,IAAI,EAAE;SAClD,CAAkB,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9B,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport Mocha from \"mocha\";\n\n/**\n * Walks up from `startDir` looking for the repo root, identified by the presence of\n * `pnpm-workspace.yaml`. Falls back to `startDir` if no such ancestor is found (e.g. if the workspace\n * layout ever changes).\n *\n * @remarks Exported (in addition to being used internally) so tests can independently compute the\n * expected `classname` for a given file without duplicating this logic.\n */\nexport function findRepoRoot(startDir: string): string {\n\tlet dir = startDir;\n\t// eslint-disable-next-line no-constant-condition -- terminates via the `parent === dir` root check below\n\twhile (true) {\n\t\tif (existsSync(path.join(dir, \"pnpm-workspace.yaml\"))) {\n\t\t\treturn dir;\n\t\t}\n\t\tconst parent = path.dirname(dir);\n\t\tif (parent === dir) {\n\t\t\t// Reached the filesystem root without finding a workspace marker.\n\t\t\treturn startDir;\n\t\t}\n\t\tdir = parent;\n\t}\n}\n\nconst repoRoot = findRepoRoot(process.cwd());\n\n/**\n * The subset of a Mocha `Test` that {@link FluidXunitReporter} cares about.\n */\ninterface JUnitTestLike {\n\t/**\n\t * Absolute path of the file the test is defined in, as set by Mocha.\n\t */\n\tfile?: string;\n\n\t/**\n\t * The `Suite` (or nested `Suite`s) the test is defined in. `xunit`'s `test` method relies on\n\t * `parent.fullTitle()`, and mocha's own `isPending()` implementation recurses into `parent.isPending()`,\n\t * so the whole object (not just `fullTitle`) needs to be preserved when overriding it below.\n\t */\n\tparent: object;\n\n\t/**\n\t * The test's fully qualified title: its own title, prefixed by its ancestor `describe` blocks' titles.\n\t */\n\tfullTitle(): string;\n}\n\n/**\n * Minimal typing for mocha's built-in `xunit` reporter constructor and the `test` instance method\n * {@link FluidXunitReporter} overrides.\n */\ninterface XUnitReporterInstance {\n\ttest(test: JUnitTestLike, options?: unknown): void;\n}\n\nconst XUnitReporterCtor = Mocha.reporters.XUnit as unknown as new (\n\trunner: unknown,\n\toptions: unknown,\n) => XUnitReporterInstance;\n\n/**\n * A JUnit reporter for Mocha, based on mocha's built-in `xunit` reporter, that fixes two issues with the\n * default `xunit` output when many packages' reports are viewed together in Azure DevOps's Tests tab.\n *\n * `name` (the `<testcase>`'s display title in Azure DevOps): `xunit` sets this to the test's own,\n * non-fully-qualified title (e.g. `\"increments\"`), which frequently collides with other tests of the same\n * name defined under different `describe` blocks or files. This override sets it to the fully qualified\n * title instead (the full `describe`/`it` chain), which is unique.\n *\n * `classname` (used by Azure DevOps's JUnit importer to populate the \"Test file\" grouping — see\n * `AutomatedTestStorage` in\n * {@link https://github.com/microsoft/azure-pipelines-agent/blob/master/src/Agent.Worker/TestResults/Legacy/JunitResultReader.cs | JunitResultReader.cs}):\n * `xunit` sets this to the fully qualified title as well, so that grouping showed test titles instead of\n * file names. This override sets it to the path (relative to the repo root) of the file containing the\n * test.\n *\n * All other behavior — notably, `xunit`'s single flat `<testsuite>` per report file — is unchanged, so\n * this reporter is not subject to the Azure DevOps \"Test Run\" naming regression that `mocha-junit-reporter`\n * (which emits one `<testsuite>` per `describe` block, rather than one per file) causes: Azure DevOps's\n * JUnit importer falls back to a generic `JUnit_<file name>` run title whenever a report file contains more\n * than one `<testsuite>` element, unconditionally, regardless of file or suite naming.\n */\nexport class FluidXunitReporter extends XUnitReporterCtor {\n\tpublic test(test: JUnitTestLike, options?: unknown): void {\n\t\tconst classname =\n\t\t\ttest.file === undefined ? test.fullTitle() : path.relative(repoRoot, test.file);\n\t\t// `xunit`'s `test` method reads `test.title` for `name` and `test.parent.fullTitle()` for\n\t\t// `classname`. Wrap `test` and `test.parent` (via prototypal inheritance, so unrelated\n\t\t// properties/methods they're relied on for — `file`, `duration`, `state`, `err`, `isPending()`\n\t\t// (which recurses into `parent.isPending()`) — still resolve correctly) to present the values\n\t\t// wanted here, without mutating the shared `test`/`test.parent` objects that other reporters\n\t\t// running in the same `mocha-multi-reporters` process also read.\n\t\tconst wrappedParent = Object.create(test.parent, {\n\t\t\tfullTitle: { value: () => classname, enumerable: true },\n\t\t}) as JUnitTestLike[\"parent\"];\n\t\tconst wrapped = Object.create(test, {\n\t\t\ttitle: { value: test.fullTitle(), enumerable: true },\n\t\t\tparent: { value: wrappedParent, enumerable: true },\n\t\t}) as JUnitTestLike;\n\t\tsuper.test(wrapped, options);\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluid-internal/mocha-test-setup",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Utilities for Fluid tests",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -19,11 +19,15 @@
|
|
|
19
19
|
"./mocharc-common": {
|
|
20
20
|
"require": "./mocharc-common-cjswrapper.cjs",
|
|
21
21
|
"default": "./lib/mocharcCommon.js"
|
|
22
|
+
},
|
|
23
|
+
"./xunit-reporter": {
|
|
24
|
+
"require": "./xunit-reporter-cjswrapper.cjs",
|
|
25
|
+
"default": "./lib/xunitReporter.js"
|
|
22
26
|
}
|
|
23
27
|
},
|
|
24
28
|
"dependencies": {
|
|
25
|
-
"@fluid-internal/test-driver-definitions": "~3.0
|
|
26
|
-
"@fluidframework/core-interfaces": "~3.0
|
|
29
|
+
"@fluid-internal/test-driver-definitions": "~3.2.0",
|
|
30
|
+
"@fluidframework/core-interfaces": "~3.2.0",
|
|
27
31
|
"mocha": "^11.7.5",
|
|
28
32
|
"source-map-support": "^0.5.21"
|
|
29
33
|
},
|
|
@@ -37,12 +41,14 @@
|
|
|
37
41
|
"@microsoft/api-extractor": "7.58.1",
|
|
38
42
|
"@types/mocha": "^10.0.10",
|
|
39
43
|
"@types/node": "~22.19.17",
|
|
44
|
+
"@types/xml2js": "^0.4.14",
|
|
40
45
|
"concurrently": "^10.0.3",
|
|
41
46
|
"copyfiles": "^2.4.1",
|
|
42
47
|
"eslint": "~9.39.1",
|
|
43
48
|
"jiti": "^2.6.1",
|
|
44
49
|
"rimraf": "^6.1.3",
|
|
45
|
-
"typescript": "~6.0.3"
|
|
50
|
+
"typescript": "~6.0.3",
|
|
51
|
+
"xml2js": "^0.6.2"
|
|
46
52
|
},
|
|
47
53
|
"fluidBuild": {
|
|
48
54
|
"_tasks_comment": "build:cjs is configured to depend on build:esm task as all CommonJS consumers expect mocha support which is implemented in ESM. Building ESM when CommonJS is requested ensures the implementation expectation is satisfied.",
|
|
@@ -67,7 +73,7 @@
|
|
|
67
73
|
"build:docs": "api-extractor run --local --config api-extractor/api-extractor-model.json",
|
|
68
74
|
"build:esm": "tsc --project ./tsconfig.json",
|
|
69
75
|
"build:genver": "gen-version",
|
|
70
|
-
"check:are-the-types-wrong": "attw --pack . --profile esm-only --exclude-entrypoints ./mocharc-common",
|
|
76
|
+
"check:are-the-types-wrong": "attw --pack . --profile esm-only --exclude-entrypoints ./mocharc-common ./xunit-reporter",
|
|
71
77
|
"check:biome": "biome check .",
|
|
72
78
|
"check:exports": "concurrently \"npm:check:exports:*\"",
|
|
73
79
|
"check:exports:bundle-release-tags": "api-extractor run --config api-extractor/api-extractor-lint-bundle.json",
|
|
@@ -76,12 +82,15 @@
|
|
|
76
82
|
"check:types:inexactOptionalPropertyTypes": "tsc --project ./tsconfig.json --noEmit --exactOptionalPropertyTypes false --skipLibCheck --emitDeclarationOnly false --tsBuildInfoFile ./tsconfig.inexactOptionalPropertyTypes.tsbuildinfo",
|
|
77
83
|
"ci:build:api-reports": "api-extractor run --config api-extractor/api-extractor-report.json",
|
|
78
84
|
"ci:build:docs": "api-extractor run --config api-extractor/api-extractor-model.json",
|
|
79
|
-
"clean": "rimraf --glob dist lib \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp",
|
|
85
|
+
"clean": "rimraf --glob dist lib \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
|
|
80
86
|
"eslint": "eslint --quiet --format stylish src",
|
|
81
87
|
"eslint:fix": "eslint --quiet --format stylish src --fix --fix-type problem,suggestion,layout",
|
|
82
88
|
"format": "npm run format:biome",
|
|
83
89
|
"format:biome": "biome check . --write",
|
|
84
90
|
"lint": "fluid-build . --task lint",
|
|
85
|
-
"lint:fix": "fluid-build . --task eslint:fix --task format"
|
|
91
|
+
"lint:fix": "fluid-build . --task eslint:fix --task format",
|
|
92
|
+
"test": "npm run test:mocha",
|
|
93
|
+
"test:mocha": "npm run test:mocha:esm",
|
|
94
|
+
"test:mocha:esm": "mocha"
|
|
86
95
|
}
|
|
87
96
|
}
|
package/src/mocharcCommon.ts
CHANGED
|
@@ -120,6 +120,7 @@ export function getFluidTestMochaConfig(
|
|
|
120
120
|
};
|
|
121
121
|
config.reporter = `mocha-multi-reporters`;
|
|
122
122
|
// See https://www.npmjs.com/package/mocha-multi-reporters#cmroutput-option
|
|
123
|
+
|
|
123
124
|
const outputFilePrefix = reportPrefix !== undefined ? `${reportPrefix}-` : "";
|
|
124
125
|
if (process.env.SILENT_TEST_OUTPUT === undefined) {
|
|
125
126
|
console.log(
|
|
@@ -128,12 +129,18 @@ export function getFluidTestMochaConfig(
|
|
|
128
129
|
}
|
|
129
130
|
const suiteName =
|
|
130
131
|
reportPrefix !== undefined ? `${packageJson.name} - ${reportPrefix}` : packageJson.name;
|
|
132
|
+
// This must be the exact module specifier mocha-multi-reporters will `require(...)` to load the reporter
|
|
133
|
+
// (see its source: https://github.com/stevemao/mocha-multi-reporters/blob/master/lib/MultiReporters.js),
|
|
134
|
+
// i.e. it can't be shortened to some arbitrary friendly name. It also determines the reporter-specific
|
|
135
|
+
// option key mocha-multi-reporters expects below (and in test-config.json): it camelCases this exact
|
|
136
|
+
// string and appends "ReporterOptions" (e.g. "@foo/bar/baz" -> "fooBarBazReporterOptions").
|
|
137
|
+
const xunitReporterName = "@fluid-internal/mocha-test-setup/xunit-reporter";
|
|
131
138
|
config["reporter-options"] = [
|
|
132
139
|
`configFile=${path.join(
|
|
133
140
|
import.meta.dirname,
|
|
134
141
|
"..",
|
|
135
142
|
"test-config.json",
|
|
136
|
-
)},cmrOutput
|
|
143
|
+
)},cmrOutput=${xunitReporterName}+output+${outputFilePrefix}:${xunitReporterName}+suiteName+${suiteName}`,
|
|
137
144
|
];
|
|
138
145
|
}
|
|
139
146
|
|
package/src/packageVersion.ts
CHANGED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
|
|
9
|
+
import Mocha from "mocha";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Walks up from `startDir` looking for the repo root, identified by the presence of
|
|
13
|
+
* `pnpm-workspace.yaml`. Falls back to `startDir` if no such ancestor is found (e.g. if the workspace
|
|
14
|
+
* layout ever changes).
|
|
15
|
+
*
|
|
16
|
+
* @remarks Exported (in addition to being used internally) so tests can independently compute the
|
|
17
|
+
* expected `classname` for a given file without duplicating this logic.
|
|
18
|
+
*/
|
|
19
|
+
export function findRepoRoot(startDir: string): string {
|
|
20
|
+
let dir = startDir;
|
|
21
|
+
// eslint-disable-next-line no-constant-condition -- terminates via the `parent === dir` root check below
|
|
22
|
+
while (true) {
|
|
23
|
+
if (existsSync(path.join(dir, "pnpm-workspace.yaml"))) {
|
|
24
|
+
return dir;
|
|
25
|
+
}
|
|
26
|
+
const parent = path.dirname(dir);
|
|
27
|
+
if (parent === dir) {
|
|
28
|
+
// Reached the filesystem root without finding a workspace marker.
|
|
29
|
+
return startDir;
|
|
30
|
+
}
|
|
31
|
+
dir = parent;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const repoRoot = findRepoRoot(process.cwd());
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The subset of a Mocha `Test` that {@link FluidXunitReporter} cares about.
|
|
39
|
+
*/
|
|
40
|
+
interface JUnitTestLike {
|
|
41
|
+
/**
|
|
42
|
+
* Absolute path of the file the test is defined in, as set by Mocha.
|
|
43
|
+
*/
|
|
44
|
+
file?: string;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The `Suite` (or nested `Suite`s) the test is defined in. `xunit`'s `test` method relies on
|
|
48
|
+
* `parent.fullTitle()`, and mocha's own `isPending()` implementation recurses into `parent.isPending()`,
|
|
49
|
+
* so the whole object (not just `fullTitle`) needs to be preserved when overriding it below.
|
|
50
|
+
*/
|
|
51
|
+
parent: object;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The test's fully qualified title: its own title, prefixed by its ancestor `describe` blocks' titles.
|
|
55
|
+
*/
|
|
56
|
+
fullTitle(): string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Minimal typing for mocha's built-in `xunit` reporter constructor and the `test` instance method
|
|
61
|
+
* {@link FluidXunitReporter} overrides.
|
|
62
|
+
*/
|
|
63
|
+
interface XUnitReporterInstance {
|
|
64
|
+
test(test: JUnitTestLike, options?: unknown): void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const XUnitReporterCtor = Mocha.reporters.XUnit as unknown as new (
|
|
68
|
+
runner: unknown,
|
|
69
|
+
options: unknown,
|
|
70
|
+
) => XUnitReporterInstance;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* A JUnit reporter for Mocha, based on mocha's built-in `xunit` reporter, that fixes two issues with the
|
|
74
|
+
* default `xunit` output when many packages' reports are viewed together in Azure DevOps's Tests tab.
|
|
75
|
+
*
|
|
76
|
+
* `name` (the `<testcase>`'s display title in Azure DevOps): `xunit` sets this to the test's own,
|
|
77
|
+
* non-fully-qualified title (e.g. `"increments"`), which frequently collides with other tests of the same
|
|
78
|
+
* name defined under different `describe` blocks or files. This override sets it to the fully qualified
|
|
79
|
+
* title instead (the full `describe`/`it` chain), which is unique.
|
|
80
|
+
*
|
|
81
|
+
* `classname` (used by Azure DevOps's JUnit importer to populate the "Test file" grouping — see
|
|
82
|
+
* `AutomatedTestStorage` in
|
|
83
|
+
* {@link https://github.com/microsoft/azure-pipelines-agent/blob/master/src/Agent.Worker/TestResults/Legacy/JunitResultReader.cs | JunitResultReader.cs}):
|
|
84
|
+
* `xunit` sets this to the fully qualified title as well, so that grouping showed test titles instead of
|
|
85
|
+
* file names. This override sets it to the path (relative to the repo root) of the file containing the
|
|
86
|
+
* test.
|
|
87
|
+
*
|
|
88
|
+
* All other behavior — notably, `xunit`'s single flat `<testsuite>` per report file — is unchanged, so
|
|
89
|
+
* this reporter is not subject to the Azure DevOps "Test Run" naming regression that `mocha-junit-reporter`
|
|
90
|
+
* (which emits one `<testsuite>` per `describe` block, rather than one per file) causes: Azure DevOps's
|
|
91
|
+
* JUnit importer falls back to a generic `JUnit_<file name>` run title whenever a report file contains more
|
|
92
|
+
* than one `<testsuite>` element, unconditionally, regardless of file or suite naming.
|
|
93
|
+
*/
|
|
94
|
+
export class FluidXunitReporter extends XUnitReporterCtor {
|
|
95
|
+
public test(test: JUnitTestLike, options?: unknown): void {
|
|
96
|
+
const classname =
|
|
97
|
+
test.file === undefined ? test.fullTitle() : path.relative(repoRoot, test.file);
|
|
98
|
+
// `xunit`'s `test` method reads `test.title` for `name` and `test.parent.fullTitle()` for
|
|
99
|
+
// `classname`. Wrap `test` and `test.parent` (via prototypal inheritance, so unrelated
|
|
100
|
+
// properties/methods they're relied on for — `file`, `duration`, `state`, `err`, `isPending()`
|
|
101
|
+
// (which recurses into `parent.isPending()`) — still resolve correctly) to present the values
|
|
102
|
+
// wanted here, without mutating the shared `test`/`test.parent` objects that other reporters
|
|
103
|
+
// running in the same `mocha-multi-reporters` process also read.
|
|
104
|
+
const wrappedParent = Object.create(test.parent, {
|
|
105
|
+
fullTitle: { value: () => classname, enumerable: true },
|
|
106
|
+
}) as JUnitTestLike["parent"];
|
|
107
|
+
const wrapped = Object.create(test, {
|
|
108
|
+
title: { value: test.fullTitle(), enumerable: true },
|
|
109
|
+
parent: { value: wrappedParent, enumerable: true },
|
|
110
|
+
}) as JUnitTestLike;
|
|
111
|
+
super.test(wrapped, options);
|
|
112
|
+
}
|
|
113
|
+
}
|
package/test-config.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"reporterEnabled": "spec
|
|
3
|
-
"
|
|
2
|
+
"reporterEnabled": "spec,@fluid-internal/mocha-test-setup/xunit-reporter",
|
|
3
|
+
"fluidInternalMochaTestSetupXunitReporterReporterOptions": {
|
|
4
4
|
"output": "nyc/{id}junit-report.xml",
|
|
5
5
|
"suiteName": "{id}"
|
|
6
6
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// This file exists to preserve CommonJS default export compatibility for the xunit-reporter entrypoint,
|
|
7
|
+
// since `mocha-multi-reporters` loads reporters via a plain CommonJS `require()`.
|
|
8
|
+
// Once all consumers are using named imports, this file can be removed and all conditions can point
|
|
9
|
+
// directly to the ESM file. attw xunit-reporter exclusion can also be removed at that time.
|
|
10
|
+
|
|
11
|
+
"use strict";
|
|
12
|
+
|
|
13
|
+
const { FluidXunitReporter } = require("./lib/xunitReporter.js");
|
|
14
|
+
|
|
15
|
+
module.exports = FluidXunitReporter;
|