@itwin/certa 5.9.0-dev.9 → 5.9.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/CHANGELOG.md +21 -1
- package/lib/runners/chrome/ChromeTestRunner.d.ts.map +1 -1
- package/lib/runners/chrome/ChromeTestRunner.js +4 -1
- package/lib/runners/chrome/ChromeTestRunner.js.map +1 -1
- package/lib/runners/chrome/webserver.js +10 -3
- package/lib/runners/chrome/webserver.js.map +1 -1
- package/lib/utils/SpawnUtils.js +2 -2
- package/lib/utils/SpawnUtils.js.map +1 -1
- package/lib/utils/initLogging.js +2 -1
- package/lib/utils/initLogging.js.map +1 -1
- package/lib/utils/initSourceMaps.d.ts.map +1 -1
- package/lib/utils/initSourceMaps.js +1 -1
- package/lib/utils/initSourceMaps.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
# Change Log - @itwin/certa
|
|
2
2
|
|
|
3
|
-
This log was last generated on
|
|
3
|
+
This log was last generated on Mon, 04 May 2026 16:32:08 GMT and should not be manually modified.
|
|
4
|
+
|
|
5
|
+
## 5.9.0
|
|
6
|
+
Mon, 04 May 2026 16:32:08 GMT
|
|
7
|
+
|
|
8
|
+
_Version update only_
|
|
9
|
+
|
|
10
|
+
## 5.8.4
|
|
11
|
+
Thu, 23 Apr 2026 18:05:13 GMT
|
|
12
|
+
|
|
13
|
+
_Version update only_
|
|
14
|
+
|
|
15
|
+
## 5.8.3
|
|
16
|
+
Thu, 23 Apr 2026 14:52:42 GMT
|
|
17
|
+
|
|
18
|
+
_Version update only_
|
|
19
|
+
|
|
20
|
+
## 5.8.2
|
|
21
|
+
Thu, 16 Apr 2026 11:05:01 GMT
|
|
22
|
+
|
|
23
|
+
_Version update only_
|
|
4
24
|
|
|
5
25
|
## 5.8.1
|
|
6
26
|
Fri, 10 Apr 2026 13:02:00 GMT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChromeTestRunner.d.ts","sourceRoot":"","sources":["../../../src/runners/chrome/ChromeTestRunner.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAchD,qBAAa,gBAAgB;IAC3B,gBAAuB,gBAAgB,QAAQ;IAC/C,gBAAuB,eAAe,QAAQ;WAC1B,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;WA4B9C,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ChromeTestRunner.d.ts","sourceRoot":"","sources":["../../../src/runners/chrome/ChromeTestRunner.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAchD,qBAAa,gBAAgB;IAC3B,gBAAuB,gBAAgB,QAAQ;IAC/C,gBAAuB,eAAe,QAAQ;WAC1B,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;WA4B9C,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAmBjE"}
|
|
@@ -43,7 +43,10 @@ class ChromeTestRunner {
|
|
|
43
43
|
// FIXME: Do we really want to always enforce this behavior?
|
|
44
44
|
if (process.env.CI || process.env.TF_BUILD)
|
|
45
45
|
config.mochaOptions.forbidOnly = true;
|
|
46
|
-
const
|
|
46
|
+
const port = process.env.CERTA_PORT;
|
|
47
|
+
if (undefined === port)
|
|
48
|
+
throw new Error("CERTA_PORT is not defined.");
|
|
49
|
+
const { failures, coverage } = await runTestsInPlaywright(config, port);
|
|
47
50
|
webserverProcess.kill();
|
|
48
51
|
// Save nyc/istanbul coverage file.
|
|
49
52
|
if (config.cover)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChromeTestRunner.js","sourceRoot":"","sources":["../../../src/runners/chrome/ChromeTestRunner.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\nimport * as path from \"path\";\nimport { Browser, chromium, LaunchOptions, Page } from \"playwright\";\nimport { ChildProcess } from \"child_process\";\nimport { spawnChildProcess } from \"../../utils/SpawnUtils\";\nimport { executeRegisteredCallback } from \"../../utils/CallbackUtils\";\nimport { CertaConfig } from \"../../CertaConfig\";\nimport { writeCoverageData } from \"../../utils/CoverageUtils\";\nimport { configureRemoteReporter } from \"./MochaRemoteReporter\";\n\ninterface ChromeTestResults {\n failures: number;\n coverage: any;\n}\n\ntype ConsoleMethodName = \"log\" | \"error\" | \"dir\";\n\nlet browser: Browser;\nlet webserverProcess: ChildProcess;\n\nexport class ChromeTestRunner {\n public static readonly supportsCoverage = true;\n public static readonly supportsCleanup = true;\n public static async initialize(config: CertaConfig): Promise<void> {\n // Go ahead and launch playwright now - the VS Code debugger gets confused if it can't at least see the chrome instance right away.\n const options: LaunchOptions = {\n args: config.chromeOptions.args,\n headless: !config.debug,\n };\n\n if (config.debug)\n options.args?.push(`--disable-gpu`, `--remote-debugging-port=${config.ports.frontendDebugging}`);\n\n browser = await chromium.launch(options);\n\n const webserverEnv = {\n CERTA_PORT: `${config.ports.frontend}`, // eslint-disable-line @typescript-eslint/naming-convention\n CERTA_PATH: path.join(__dirname, \"../../../public/index.html\"), // eslint-disable-line @typescript-eslint/naming-convention\n CERTA_PUBLIC_DIRS: JSON.stringify(config.chromeOptions.publicDirs), // eslint-disable-line @typescript-eslint/naming-convention\n };\n webserverProcess = spawnChildProcess(\"node\", [require.resolve(\"./webserver\")], webserverEnv, true);\n\n // Don't continue until the webserver is started and listening.\n const webserverExited = new Promise<never>((_resolve, reject) => webserverProcess.once(\"exit\", () => reject(new Error(\"Webserver exited!\"))));\n const webserverStarted = new Promise<number>((resolve) => webserverProcess.once(\"message\", resolve));\n const actualPort = await Promise.race([webserverExited, webserverStarted]);\n if (actualPort !== config.ports.frontend)\n console.warn(`CERTA: Port ${config.ports.frontend} was already in use, so serving test resources on port ${actualPort}`);\n process.env.CERTA_PORT = String(actualPort);\n }\n\n public static async runTests(config: CertaConfig): Promise<void> {\n // FIXME: Do we really want to always enforce this behavior?\n if (process.env.CI || process.env.TF_BUILD)\n (config.mochaOptions as any).forbidOnly = true;\n\n const { failures, coverage } = await runTestsInPlaywright(config, process.env.CERTA_PORT!);\n webserverProcess.kill();\n\n // Save nyc/istanbul coverage file.\n if (config.cover)\n writeCoverageData(coverage);\n\n process.exitCode = failures;\n (process as any).emit(\"chrome-test-runner-done\");\n }\n}\n\nasync function loadScript(page: Page, scriptPath: string) {\n return page.addScriptTag({ url: `/@/${scriptPath}` });\n}\n\nasync function runTestsInPlaywright(config: CertaConfig, port: string) {\n return new Promise<ChromeTestResults>(async (resolve, reject) => {\n try {\n const page = browser.contexts().pop()?.pages()?.pop() || await browser.newPage();\n\n // Don't let dialogs block tests\n page.on(\"dialog\", async (dialog: any) => dialog.dismiss());\n\n // Re-throw any uncaught exceptions from the frontend in the backend\n page.on(\"pageerror\", async (error) => {\n await browser.close();\n reject(error);\n });\n\n // Expose some functions to the frontend that will execute _in the backend context_\n await page.exposeFunction(\"_CertaConsole\", (type: ConsoleMethodName, args: any[]) => console[type](...args));\n await page.exposeFunction(\"_CertaSendToBackend\", executeRegisteredCallback);\n await page.exposeFunction(\"_CertaReportResults\", (results: ChromeTestResults) => {\n setTimeout(async () => {\n await browser.close();\n resolve(results);\n });\n });\n\n // Now load the page (and requisite scripts)...\n const testBundle = (config.cover && config.instrumentedTestBundle) || config.testBundle;\n await page.goto(`http://localhost:${port}`);\n await page.addScriptTag({ content: `var _CERTA_CONFIG = ${JSON.stringify(config)};` });\n await loadScript(page, require.resolve(\"../../utils/initLogging.js\"));\n await loadScript(page, require.resolve(\"mocha/mocha.js\"));\n await loadScript(page, require.resolve(\"source-map-support/browser-source-map-support.js\"));\n await loadScript(page, require.resolve(\"../../utils/initSourceMaps.js\"));\n await loadScript(page, require.resolve(\"./MochaSerializer.js\"));\n await configureRemoteReporter(page);\n await loadScript(page, require.resolve(\"../../utils/initMocha.js\"));\n await loadScript(page, testBundle);\n\n // ...and start the tests\n await page.evaluate(async () => {\n // NB: This is being evaluated in the frontend context!\n Mocha.reporters.Base.color = true as any;\n const globals = window as any;\n mocha.run((failures) => {\n const coverage = globals.__coverage__;\n globals._CertaReportResults({ failures, coverage }); // This will close the browser\n });\n });\n } catch (error) {\n await browser.close();\n reject(error); // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors\n }\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ChromeTestRunner.js","sourceRoot":"","sources":["../../../src/runners/chrome/ChromeTestRunner.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\nimport * as path from \"path\";\nimport { Browser, chromium, LaunchOptions, Page } from \"playwright\";\nimport { ChildProcess } from \"child_process\";\nimport { spawnChildProcess } from \"../../utils/SpawnUtils\";\nimport { executeRegisteredCallback } from \"../../utils/CallbackUtils\";\nimport { CertaConfig } from \"../../CertaConfig\";\nimport { writeCoverageData } from \"../../utils/CoverageUtils\";\nimport { configureRemoteReporter } from \"./MochaRemoteReporter\";\n\ninterface ChromeTestResults {\n failures: number;\n coverage: any;\n}\n\ntype ConsoleMethodName = \"log\" | \"error\" | \"dir\";\n\nlet browser: Browser;\nlet webserverProcess: ChildProcess;\n\nexport class ChromeTestRunner {\n public static readonly supportsCoverage = true;\n public static readonly supportsCleanup = true;\n public static async initialize(config: CertaConfig): Promise<void> {\n // Go ahead and launch playwright now - the VS Code debugger gets confused if it can't at least see the chrome instance right away.\n const options: LaunchOptions = {\n args: config.chromeOptions.args,\n headless: !config.debug,\n };\n\n if (config.debug)\n options.args?.push(`--disable-gpu`, `--remote-debugging-port=${config.ports.frontendDebugging}`);\n\n browser = await chromium.launch(options);\n\n const webserverEnv = {\n CERTA_PORT: `${config.ports.frontend}`, // eslint-disable-line @typescript-eslint/naming-convention\n CERTA_PATH: path.join(__dirname, \"../../../public/index.html\"), // eslint-disable-line @typescript-eslint/naming-convention\n CERTA_PUBLIC_DIRS: JSON.stringify(config.chromeOptions.publicDirs), // eslint-disable-line @typescript-eslint/naming-convention\n };\n webserverProcess = spawnChildProcess(\"node\", [require.resolve(\"./webserver\")], webserverEnv, true);\n\n // Don't continue until the webserver is started and listening.\n const webserverExited = new Promise<never>((_resolve, reject) => webserverProcess.once(\"exit\", () => reject(new Error(\"Webserver exited!\"))));\n const webserverStarted = new Promise<number>((resolve) => webserverProcess.once(\"message\", resolve));\n const actualPort = await Promise.race([webserverExited, webserverStarted]);\n if (actualPort !== config.ports.frontend)\n console.warn(`CERTA: Port ${config.ports.frontend} was already in use, so serving test resources on port ${actualPort}`);\n process.env.CERTA_PORT = String(actualPort);\n }\n\n public static async runTests(config: CertaConfig): Promise<void> {\n // FIXME: Do we really want to always enforce this behavior?\n if (process.env.CI || process.env.TF_BUILD)\n (config.mochaOptions as any).forbidOnly = true;\n\n const port = process.env.CERTA_PORT;\n if (undefined === port)\n throw new Error(\"CERTA_PORT is not defined.\");\n\n const { failures, coverage } = await runTestsInPlaywright(config, port);\n webserverProcess.kill();\n\n // Save nyc/istanbul coverage file.\n if (config.cover)\n writeCoverageData(coverage);\n\n process.exitCode = failures;\n (process as any).emit(\"chrome-test-runner-done\");\n }\n}\n\nasync function loadScript(page: Page, scriptPath: string) {\n return page.addScriptTag({ url: `/@/${scriptPath}` });\n}\n\nasync function runTestsInPlaywright(config: CertaConfig, port: string) {\n return new Promise<ChromeTestResults>(async (resolve, reject) => {\n try {\n const page = browser.contexts().pop()?.pages()?.pop() || await browser.newPage();\n\n // Don't let dialogs block tests\n page.on(\"dialog\", async (dialog: any) => dialog.dismiss());\n\n // Re-throw any uncaught exceptions from the frontend in the backend\n page.on(\"pageerror\", async (error) => {\n await browser.close();\n reject(error);\n });\n\n // Expose some functions to the frontend that will execute _in the backend context_\n await page.exposeFunction(\"_CertaConsole\", (type: ConsoleMethodName, args: any[]) => console[type](...args));\n await page.exposeFunction(\"_CertaSendToBackend\", executeRegisteredCallback);\n await page.exposeFunction(\"_CertaReportResults\", (results: ChromeTestResults) => {\n setTimeout(async () => {\n await browser.close();\n resolve(results);\n });\n });\n\n // Now load the page (and requisite scripts)...\n const testBundle = (config.cover && config.instrumentedTestBundle) || config.testBundle;\n await page.goto(`http://localhost:${port}`);\n await page.addScriptTag({ content: `var _CERTA_CONFIG = ${JSON.stringify(config)};` });\n await loadScript(page, require.resolve(\"../../utils/initLogging.js\"));\n await loadScript(page, require.resolve(\"mocha/mocha.js\"));\n await loadScript(page, require.resolve(\"source-map-support/browser-source-map-support.js\"));\n await loadScript(page, require.resolve(\"../../utils/initSourceMaps.js\"));\n await loadScript(page, require.resolve(\"./MochaSerializer.js\"));\n await configureRemoteReporter(page);\n await loadScript(page, require.resolve(\"../../utils/initMocha.js\"));\n await loadScript(page, testBundle);\n\n // ...and start the tests\n await page.evaluate(async () => {\n // NB: This is being evaluated in the frontend context!\n Mocha.reporters.Base.color = true as any;\n const globals = window as any;\n mocha.run((failures) => {\n const coverage = globals.__coverage__;\n globals._CertaReportResults({ failures, coverage }); // This will close the browser\n });\n });\n } catch (error) {\n await browser.close();\n reject(error); // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors\n }\n });\n}\n"]}
|
|
@@ -18,8 +18,14 @@ app.all("/*", (_req, res, next) => {
|
|
|
18
18
|
});
|
|
19
19
|
// The generated HTML file should be served at the "root" URL (i.e., http://localhost:3000/).
|
|
20
20
|
app.use("/", (req, resp, next) => {
|
|
21
|
-
if (req.path === "/")
|
|
22
|
-
|
|
21
|
+
if (req.path === "/") {
|
|
22
|
+
const certaPath = process.env.CERTA_PATH;
|
|
23
|
+
if (undefined === certaPath) {
|
|
24
|
+
resp.sendStatus(500);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
resp.sendFile(certaPath);
|
|
28
|
+
}
|
|
23
29
|
else
|
|
24
30
|
next();
|
|
25
31
|
});
|
|
@@ -55,7 +61,8 @@ let port = parseInt(process.env.CERTA_PORT ?? "3000", 10);
|
|
|
55
61
|
const server = http.createServer(app);
|
|
56
62
|
server.on("listening", async () => {
|
|
57
63
|
console.log(`Certa web frontend now listening on port ${port}`);
|
|
58
|
-
process.send
|
|
64
|
+
if (undefined !== process.send)
|
|
65
|
+
process.send(port);
|
|
59
66
|
});
|
|
60
67
|
// The preferred port (process.env.CERTA_PORT) may be in use. If that happens detect a free port and try again.
|
|
61
68
|
// Even though we detect a free port, there can still be race conditions when many certa processes run simultaneously.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webserver.js","sourceRoot":"","sources":["../../../src/runners/chrome/webserver.ts"],"names":[],"mappings":";;AAAA;;;+FAG+F;AAC/F,sCAAsC;AACtC,mCAAmC;AACnC,6BAA6B;AAC7B,6BAA6B;AAE7B,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;AAEtB,2BAA2B;AAC3B,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;IAChC,GAAG,CAAC,MAAM,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAC/C,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,oBAAoB,CAAC,CAAC;IACjE,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,qLAAqL,CAAC,CAAC;IAClO,IAAI,EAAE,CAAC;AACT,CAAC,CAAC,CAAC;AAEH,6FAA6F;AAC7F,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAC/B,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG;
|
|
1
|
+
{"version":3,"file":"webserver.js","sourceRoot":"","sources":["../../../src/runners/chrome/webserver.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\nimport * as detect from \"detect-port\";\nimport * as express from \"express\";\nimport * as http from \"http\";\nimport * as path from \"path\";\n\nconst app = express();\n\n// Enable CORS for all apis\napp.all(\"/*\", (_req, res, next) => {\n res.header(\"Access-Control-Allow-Origin\", \"*\");\n res.header(\"Access-Control-Allow-Methods\", \"POST, GET, OPTIONS\");\n res.header(\"Access-Control-Allow-Headers\", \"Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, X-Correlation-Id, X-Session-Id, X-Application-Id, X-Application-Version, X-User-Id, X-Protocol-Version\");\n next();\n});\n\n// The generated HTML file should be served at the \"root\" URL (i.e., http://localhost:3000/).\napp.use(\"/\", (req, resp, next) => {\n if (req.path === \"/\") {\n const certaPath = process.env.CERTA_PATH;\n if (undefined === certaPath) {\n resp.sendStatus(500);\n return;\n }\n\n resp.sendFile(certaPath);\n }\n else\n next();\n});\n\n// Handle a special route for serving absolute paths and files from node_modules\napp.use(\"/@/\", (_req, resp) => {\n const filePath = _req.originalUrl.replace(/^\\/@\\//, \"\");\n const canonicalPath = require(\"canonical-path\");\n const sourceMap = require(\"source-map-support\").retrieveSourceMap(filePath);\n const fullPath = path.resolve(\"/\", filePath);\n resp.sendFile(canonicalPath.normalize(fullPath), {\n headers: (sourceMap) && {\n \"X-SourceMap\": `/@/${sourceMap.url}`,\n },\n });\n});\n\n// Serve static assets from any configured \"public\" directories\nconst publicDirs: string[] = JSON.parse(process.env.CERTA_PUBLIC_DIRS || \"[]\");\nfor (const publicDir of publicDirs) {\n app.use(express.static(publicDir));\n}\n\n// All other routes should log a warning\nconst alreadyLogged = new Set<string>();\napp.use(\"*\", (req, resp) => {\n // Don't repeat these warnings if the same asset was requested multiple times.\n if (!alreadyLogged.has(req.originalUrl)) {\n console.warn(`WARNING: Tests attempted to load missing asset: \"${req.originalUrl}\"`);\n alreadyLogged.add(req.originalUrl);\n }\n resp.sendStatus(404);\n});\n\n// Once the server actually starts, we should log and send the actual port back to the parent process\nlet port = parseInt(process.env.CERTA_PORT ?? \"3000\", 10);\nconst server = http.createServer(app);\nserver.on(\"listening\", async () => {\n console.log(`Certa web frontend now listening on port ${port}`);\n if (undefined !== process.send)\n process.send(port);\n});\n\n// The preferred port (process.env.CERTA_PORT) may be in use. If that happens detect a free port and try again.\n// Even though we detect a free port, there can still be race conditions when many certa processes run simultaneously.\n// Therefore, we'll retry up to 4 times with a new free port.\nconst maxRetries = 4;\nlet numRetries = 0;\nserver.on(\"error\", async (e: any) => {\n if (e.code !== \"EADDRINUSE\" || numRetries >= maxRetries) {\n console.error(e);\n process.exit(1);\n }\n try {\n numRetries++;\n port = await detect(port);\n server.close();\n server.listen(port);\n } catch (error) {\n console.error(error);\n process.exit(1);\n }\n});\n\n// Run the server...\nserver.listen(port);\n"]}
|
package/lib/utils/SpawnUtils.js
CHANGED
|
@@ -26,8 +26,8 @@ function spawnChildProcess(command, args, env, useIpc = false) {
|
|
|
26
26
|
const childProcess = (0, child_process_1.spawn)(command, args, { stdio, cwd: process.cwd(), env: childEnv });
|
|
27
27
|
// For some reason, spawning using `stdio: "inherit"` results in some garbled output (for example, "✓" is printed as "ΓêÜ").
|
|
28
28
|
// Using `stdio: "pipe"` and manually redirecting the output here seems to work though.
|
|
29
|
-
childProcess.stdout
|
|
30
|
-
childProcess.stderr
|
|
29
|
+
childProcess.stdout?.on("data", (data) => process.stdout.write(data));
|
|
30
|
+
childProcess.stderr?.on("data", (data) => process.stderr.write(data));
|
|
31
31
|
return childProcess;
|
|
32
32
|
}
|
|
33
33
|
/** Returns a Promise that will be resolved with the given child process's exit code upon termination. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpawnUtils.js","sourceRoot":"","sources":["../../src/utils/SpawnUtils.ts"],"names":[],"mappings":";;AAeA,8CAYC;AAGD,wBAIC;AAwBD,gDAWC;AAWD,sCAMC;AAtFD;;;+FAG+F;AAC/F,iDAAkE;AAClE,uCAAuC;AAEvC;;;;;;;GAOG;AACH,SAAgB,iBAAiB,CAAC,OAAe,EAAE,IAA2B,EAAE,GAAuB,EAAE,MAAM,GAAG,KAAK;IACrH,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC;IAEpD,iFAAiF;IACjF,yHAAyH;IACzH,MAAM,KAAK,GAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACxE,MAAM,YAAY,GAAG,IAAA,qBAAK,EAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxF,4HAA4H;IAC5H,uFAAuF;IACvF,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"SpawnUtils.js","sourceRoot":"","sources":["../../src/utils/SpawnUtils.ts"],"names":[],"mappings":";;AAeA,8CAYC;AAGD,wBAIC;AAwBD,gDAWC;AAWD,sCAMC;AAtFD;;;+FAG+F;AAC/F,iDAAkE;AAClE,uCAAuC;AAEvC;;;;;;;GAOG;AACH,SAAgB,iBAAiB,CAAC,OAAe,EAAE,IAA2B,EAAE,GAAuB,EAAE,MAAM,GAAG,KAAK;IACrH,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC;IAEpD,iFAAiF;IACjF,yHAAyH;IACzH,MAAM,KAAK,GAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACxE,MAAM,YAAY,GAAG,IAAA,qBAAK,EAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxF,4HAA4H;IAC5H,uFAAuF;IACvF,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,yGAAyG;AAClG,KAAK,UAAU,MAAM,CAAC,KAAmB;IAC9C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,yGAAyG;AACzG,KAAK,UAAU,iBAAiB,CAAC,KAAmB;IAClD,IAAI,eAAe,GAAG,CAAC,CAAC,CAAC,mBAAmB;IAC5C,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAY,EAAE,EAAE;QACnC,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE;YAC7B,0IAA0I;YAC1I,oIAAoI;YACpI,yIAAyI;YACzI,6FAA6F;YAC7F,OAAO,CAAC,eAAe,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,kBAAkB;IACtC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,4FAA4F;IAC5F,mFAAmF;IACnF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACzC,IAAI,QAAQ,IAAI,CAAC;QACf,IAAI,CAAC,QAAQ,CAAC,GAAG,kBAAkB,CAAC;IAEtC,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACrF,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,aAAa,CAAC,IAAY;IACxC,gEAAgE;IAChE,IAAI,SAAS,CAAC,GAAG,EAAE;QACjB,OAAO;IAET,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\nimport { ChildProcess, spawn, StdioOptions } from \"child_process\";\nimport * as inspector from \"inspector\";\n\n/**\n * Helper function for spawning a child process with the same cwd, env, stdout, and stderr as the current process.\n * Processes spawned by this function will also have an IPC channel, so the may communicate with their parent via `process.send()`.\n * @param command The command to run.\n * @param args List of string arguments.\n * @param env Environment vars to override in the child process.\n * @param useIpc Whether to enable an IPC channel when spawning.\n */\nexport function spawnChildProcess(command: string, args: ReadonlyArray<string>, env?: NodeJS.ProcessEnv, useIpc = false): ChildProcess {\n const childEnv = { ...process.env, ...(env || {}) };\n\n // FIXME: We should be able to remove the useIpc param and just always enable it,\n // but it's not safe to spawn electron with IPC enabled until https://github.com/electron/electron/issues/17044 is fixed.\n const stdio: StdioOptions = (useIpc) ? [\"ipc\", \"pipe\", \"pipe\"] : \"pipe\";\n const childProcess = spawn(command, args, { stdio, cwd: process.cwd(), env: childEnv });\n // For some reason, spawning using `stdio: \"inherit\"` results in some garbled output (for example, \"✓\" is printed as \"ΓêÜ\").\n // Using `stdio: \"pipe\"` and manually redirecting the output here seems to work though.\n childProcess.stdout?.on(\"data\", (data: any) => process.stdout.write(data));\n childProcess.stderr?.on(\"data\", (data: any) => process.stderr.write(data));\n return childProcess;\n}\n\n/** Returns a Promise that will be resolved with the given child process's exit code upon termination. */\nexport async function onExit(child: ChildProcess): Promise<number> {\n return new Promise((resolve) => {\n child.on(\"exit\", (status) => resolve(status || 0));\n });\n}\n\n/** Returns a Promise that will be resolved with the given child process's exit code upon termination. */\nasync function onExitElectronApp(child: ChildProcess): Promise<number> {\n let messageExitCode = 1; // Default to error\n child.on(\"message\", (message: any) => {\n messageExitCode = message.exitCode;\n });\n\n return new Promise((resolve) => {\n child.on(\"exit\", (_exitCode) => {\n // Note: Upgrading to electron 10 seems to cause the electron child process to always exit with 3221225477 = 0xC0000005(Access Violation).\n // This causes the exitCode we pass to app.exit(_exitCode) to be lost. To work around this issue, we instead pass a message from the\n // child process (see ElectronTestRunner), right before we call app.exit(). This message includes the exitCode based on the status of the\n // test runs. See ElectronTestRunner.runTests, and the above listener to the \"message\" event.\n resolve(messageExitCode);\n });\n });\n}\n\n/**\n * Helper function for relaunching (as a child process) the current process in electron instead of node.\n * Returns a promise that will be resolved with the exit code of the child process, once it terminates.\n */\nexport async function relaunchInElectron(): Promise<number> {\n const args = process.argv.slice(1);\n\n // '--debug' is not allowed in Electron and '--inspect' will automatically start a debugger,\n // so we use custom parameter to indicate what we want to start debugger ourselves.\n const debugIdx = args.indexOf(\"--debug\");\n if (debugIdx >= 0)\n args[debugIdx] = \"--debug-electron\";\n\n const child = spawnChildProcess(require(\"electron/index.js\"), args, undefined, true);\n return onExitElectronApp(child);\n}\n\n/**\n * Activates the v8 inspector and starts listening on the given port, then breaks as soon as a debugger has connected.\n * This is essentially what node does when run with `--inspect-brk={port}`, but doing this manually gives us more control\n * over precisely _which_ child process connects to the debugger.\n *\n * For example, when using the chrome test runner, we want debug the original certa process (\"node certa ...args\") as the\n * test \"backend\", but with the electron test runner, we want to debug a child process (\"electron certa ...args\").\n * @param port Port to listen on for inspector connections.\n */\nexport function startDebugger(port: number) {\n // Don't try to activate if there's already an active inspector.\n if (inspector.url())\n return;\n\n inspector.open(port, undefined, true);\n}\n"]}
|
package/lib/utils/initLogging.js
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
// NB: This file is not a CommonJs module - it needs to run in the browser. Do not import or export modules here!
|
|
7
7
|
// Redirect all console output back to the main (backend) process, if necessary
|
|
8
8
|
if (typeof _CertaConsole !== "undefined") {
|
|
9
|
+
const certaConsole = _CertaConsole;
|
|
9
10
|
function forwardConsole(name) {
|
|
10
11
|
const original = console[name];
|
|
11
12
|
console[name] = (...args) => {
|
|
12
|
-
|
|
13
|
+
certaConsole(name, args);
|
|
13
14
|
// Also preserve the original behavior. This way, test progress is reported in both the backend _and_ frontend processes.
|
|
14
15
|
// This helps keep the output readable when debugging the frontend.
|
|
15
16
|
original.apply(console, args);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initLogging.js","sourceRoot":"","sources":["../../src/utils/initLogging.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,iHAAiH;AAIjH,+EAA+E;AAC/E,IAAI,OAAO,aAAa,KAAK,WAAW,EAAE,CAAC;IACzC,SAAS,cAAc,CAAC,IAA6B;QACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAW,EAAE,EAAE;YACjC,
|
|
1
|
+
{"version":3,"file":"initLogging.js","sourceRoot":"","sources":["../../src/utils/initLogging.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,iHAAiH;AAIjH,+EAA+E;AAC/E,IAAI,OAAO,aAAa,KAAK,WAAW,EAAE,CAAC;IACzC,MAAM,YAAY,GAAG,aAAa,CAAC;IACnC,SAAS,cAAc,CAAC,IAA6B;QACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAW,EAAE,EAAE;YACjC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACzB,yHAAyH;YACzH,mEAAmE;YACnE,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,IAAW,CAAC,CAAC;QACvC,CAAC,CAAC;IACJ,CAAC;IACD,cAAc,CAAC,KAAK,CAAC,CAAC;IACtB,cAAc,CAAC,OAAO,CAAC,CAAC;IACxB,cAAc,CAAC,KAAK,CAAC,CAAC;AACxB,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n// NB: This file is not a CommonJs module - it needs to run in the browser. Do not import or export modules here!\n\ndeclare let _CertaConsole: undefined | ((name: string, args: any[]) => void); // eslint-disable-line @typescript-eslint/naming-convention\n\n// Redirect all console output back to the main (backend) process, if necessary\nif (typeof _CertaConsole !== \"undefined\") {\n const certaConsole = _CertaConsole;\n function forwardConsole(name: \"log\" | \"error\" | \"dir\") {\n const original = console[name];\n console[name] = (...args: any[]) => {\n certaConsole(name, args);\n // Also preserve the original behavior. This way, test progress is reported in both the backend _and_ frontend processes.\n // This helps keep the output readable when debugging the frontend.\n original.apply(console, args as any);\n };\n }\n forwardConsole(\"log\");\n forwardConsole(\"error\");\n forwardConsole(\"dir\");\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initSourceMaps.d.ts","sourceRoot":"","sources":["../../src/utils/initSourceMaps.ts"],"names":[],"mappings":"AAOA,OAAO,CAAC,MAAM,gBAAgB,EAAE,GAAG,CAAC;AAKpC,QAAA,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"initSourceMaps.d.ts","sourceRoot":"","sources":["../../src/utils/initSourceMaps.ts"],"names":[],"mappings":"AAOA,OAAO,CAAC,MAAM,gBAAgB,EAAE,GAAG,CAAC;AAKpC,QAAA,MAAM,yBAAyB,6BAK0wF,OAAQ,QAAQ,uBALhwF,CAAC"}
|
|
@@ -9,7 +9,7 @@ sourceMapSupport.install();
|
|
|
9
9
|
// It gets pretty close though, so we'll just monkey-patch here to fix them.
|
|
10
10
|
const originalPrepareStackTrace = Error.prepareStackTrace;
|
|
11
11
|
Error.prepareStackTrace = function (...args) {
|
|
12
|
-
const res = originalPrepareStackTrace.call(this, ...args);
|
|
12
|
+
const res = String(originalPrepareStackTrace ? originalPrepareStackTrace.call(this, ...args) : args[0]);
|
|
13
13
|
return res.replace(/\(.*file:(\/|\\)/g, "(").replace(/at .*file:(\/|\\)/g, "at ");
|
|
14
14
|
};
|
|
15
15
|
//# sourceMappingURL=initSourceMaps.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initSourceMaps.js","sourceRoot":"","sources":["../../src/utils/initSourceMaps.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,iHAAiH;AAIjH,gBAAgB,CAAC,OAAO,EAAE,CAAC;AAE3B,0FAA0F;AAC1F,4EAA4E;AAC5E,MAAM,yBAAyB,GAAG,KAAK,CAAC,iBAAiB,CAAC;AAC1D,KAAK,CAAC,iBAAiB,GAAG,UAAU,GAAG,IAAI;IACzC,MAAM,GAAG,GAAG,
|
|
1
|
+
{"version":3,"file":"initSourceMaps.js","sourceRoot":"","sources":["../../src/utils/initSourceMaps.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,iHAAiH;AAIjH,gBAAgB,CAAC,OAAO,EAAE,CAAC;AAE3B,0FAA0F;AAC1F,4EAA4E;AAC5E,MAAM,yBAAyB,GAAG,KAAK,CAAC,iBAAiB,CAAC;AAC1D,KAAK,CAAC,iBAAiB,GAAG,UAAU,GAAG,IAAI;IACzC,MAAM,GAAG,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACxG,OAAO,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;AACpF,CAAC,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n* See LICENSE.md in the project root for license terms and full copyright notice.\n*--------------------------------------------------------------------------------------------*/\n// NB: This file is not a CommonJs module - it needs to run in the browser. Do not import or export modules here!\n\n// NB: This requires source-map-support/browser-source-map-support.js to be loaded first!\ndeclare const sourceMapSupport: any;\nsourceMapSupport.install();\n\n// The source-map-support package does not correctly format stack traces from the browser.\n// It gets pretty close though, so we'll just monkey-patch here to fix them.\nconst originalPrepareStackTrace = Error.prepareStackTrace;\nError.prepareStackTrace = function (...args) {\n const res = String(originalPrepareStackTrace ? originalPrepareStackTrace.call(this, ...args) : args[0]);\n return res.replace(/\\(.*file:(\\/|\\\\)/g, \"(\").replace(/at .*file:(\\/|\\\\)/g, \"at \");\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itwin/certa",
|
|
3
|
-
"version": "5.9.0
|
|
3
|
+
"version": "5.9.0",
|
|
4
4
|
"description": "A mocha-based integration test runner",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "bin/certa.js",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"nyc": "^17.1.0",
|
|
48
48
|
"rimraf": "^6.0.1",
|
|
49
49
|
"typescript": "~5.6.2",
|
|
50
|
-
"@itwin/build-tools": "5.9.0
|
|
50
|
+
"@itwin/build-tools": "5.9.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"electron": "^35.0.0 || ^36.0.0 || ^37.0.0 || ^38.0.0 || ^39.0.0 || ^40.0.0 || ^41.0.0"
|