@itwin/certa 4.1.0-dev.7 → 4.1.0-dev.71

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 CHANGED
@@ -1,6 +1,80 @@
1
1
  # Change Log - @itwin/certa
2
2
 
3
- This log was last generated on Tue, 25 Apr 2023 17:50:35 GMT and should not be manually modified.
3
+ This log was last generated on Mon, 24 Jul 2023 12:35:20 GMT and should not be manually modified.
4
+
5
+ ## 4.0.6
6
+ Mon, 24 Jul 2023 05:07:33 GMT
7
+
8
+ _Version update only_
9
+
10
+ ## 4.0.5
11
+ Tue, 18 Jul 2023 12:21:56 GMT
12
+
13
+ _Version update only_
14
+
15
+ ## 4.0.4
16
+ Wed, 12 Jul 2023 15:50:01 GMT
17
+
18
+ _Version update only_
19
+
20
+ ## 4.0.3
21
+ Mon, 03 Jul 2023 15:28:41 GMT
22
+
23
+ _Version update only_
24
+
25
+ ## 4.0.2
26
+ Wed, 21 Jun 2023 22:04:43 GMT
27
+
28
+ _Version update only_
29
+
30
+ ## 4.0.1
31
+ Wed, 21 Jun 2023 20:29:13 GMT
32
+
33
+ _Version update only_
34
+
35
+ ## 4.0.0
36
+ Mon, 22 May 2023 15:34:14 GMT
37
+
38
+ ### Updates
39
+
40
+ - Update to eslint@8
41
+ - Add support for Electron 24.
42
+ - Drop Electron 14, 15, 16, 17, 22. Start supporting Electron 23.
43
+
44
+ ## 3.7.11
45
+ Tue, 11 Jul 2023 17:17:21 GMT
46
+
47
+ _Version update only_
48
+
49
+ ## 3.7.10
50
+ Wed, 05 Jul 2023 13:41:21 GMT
51
+
52
+ _Version update only_
53
+
54
+ ## 3.7.9
55
+ Tue, 20 Jun 2023 12:51:02 GMT
56
+
57
+ _Version update only_
58
+
59
+ ## 3.7.8
60
+ Thu, 01 Jun 2023 17:00:39 GMT
61
+
62
+ _Version update only_
63
+
64
+ ## 3.7.7
65
+ Wed, 24 May 2023 17:27:09 GMT
66
+
67
+ _Version update only_
68
+
69
+ ## 3.7.6
70
+ Mon, 15 May 2023 18:23:40 GMT
71
+
72
+ _Version update only_
73
+
74
+ ## 3.7.5
75
+ Thu, 04 May 2023 19:43:18 GMT
76
+
77
+ _Version update only_
4
78
 
5
79
  ## 3.7.4
6
80
  Tue, 25 Apr 2023 17:50:35 GMT
package/README.md CHANGED
@@ -99,7 +99,7 @@ The following diagram shows a simplified process tree for each test runner:
99
99
  🞑 = Frontend ⧈ = Backend □ = Other
100
100
  ```
101
101
 
102
- > *Chrome technically spawns many child processes of its own, but since we're using Puppeteer to automate chrome,
102
+ > *Chrome technically spawns many child processes of its own, but since we're using Playwright to automate chrome,
103
103
  > this can be considered an implementation detail.
104
104
 
105
105
  Note that each test runner designates a single __frontend__ and __backend__ process (for the node test runner,
@@ -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;WA6B9C,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAcjE"}
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;CAcjE"}
@@ -6,7 +6,7 @@ exports.ChromeTestRunner = void 0;
6
6
  * See LICENSE.md in the project root for license terms and full copyright notice.
7
7
  *--------------------------------------------------------------------------------------------*/
8
8
  const path = require("path");
9
- const puppeteer = require("puppeteer");
9
+ const playwright_1 = require("playwright");
10
10
  const SpawnUtils_1 = require("../../utils/SpawnUtils");
11
11
  const CallbackUtils_1 = require("../../utils/CallbackUtils");
12
12
  const CoverageUtils_1 = require("../../utils/CoverageUtils");
@@ -15,15 +15,14 @@ let browser;
15
15
  let webserverProcess;
16
16
  class ChromeTestRunner {
17
17
  static async initialize(config) {
18
- // Go ahead and launch puppeteer now - the VS Code debugger gets confused if it can't at least see the chrome instance right away.
18
+ // Go ahead and launch playwright now - the VS Code debugger gets confused if it can't at least see the chrome instance right away.
19
19
  const options = {
20
- ignoreHTTPSErrors: true,
21
20
  args: config.chromeOptions.args,
22
21
  headless: !config.debug,
23
22
  };
24
23
  if (config.debug)
25
- options.args.push(`--disable-gpu`, `--remote-debugging-port=${config.ports.frontendDebugging}`);
26
- browser = await puppeteer.launch(options);
24
+ options.args?.push(`--disable-gpu`, `--remote-debugging-port=${config.ports.frontendDebugging}`);
25
+ browser = await playwright_1.chromium.launch(options);
27
26
  const webserverEnv = {
28
27
  CERTA_PORT: `${config.ports.frontend}`,
29
28
  CERTA_PATH: path.join(__dirname, "../../../public/index.html"),
@@ -42,7 +41,7 @@ class ChromeTestRunner {
42
41
  // FIXME: Do we really want to always enforce this behavior?
43
42
  if (process.env.CI || process.env.TF_BUILD)
44
43
  config.mochaOptions.forbidOnly = true;
45
- const { failures, coverage } = await runTestsInPuppeteer(config, process.env.CERTA_PORT);
44
+ const { failures, coverage } = await runTestsInPlaywright(config, process.env.CERTA_PORT);
46
45
  webserverProcess.kill();
47
46
  // Save nyc/istanbul coverage file.
48
47
  if (config.cover)
@@ -56,10 +55,10 @@ exports.ChromeTestRunner = ChromeTestRunner;
56
55
  async function loadScript(page, scriptPath) {
57
56
  return page.addScriptTag({ url: `/@/${scriptPath}` });
58
57
  }
59
- async function runTestsInPuppeteer(config, port) {
58
+ async function runTestsInPlaywright(config, port) {
60
59
  return new Promise(async (resolve, reject) => {
61
60
  try {
62
- const page = (await browser.pages()).pop() || await browser.newPage();
61
+ const page = browser.contexts().pop()?.pages()?.pop() || await browser.newPage();
63
62
  // Don't let dialogs block tests
64
63
  page.on("dialog", async (dialog) => dialog.dismiss());
65
64
  // Re-throw any uncaught exceptions from the frontend in the backend
@@ -1 +1 @@
1
- {"version":3,"file":"ChromeTestRunner.js","sourceRoot":"","sources":["../../../src/runners/chrome/ChromeTestRunner.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport * as path from \"path\";\r\nimport * as puppeteer from \"puppeteer\";\r\nimport { ChildProcess } from \"child_process\";\r\nimport { spawnChildProcess } from \"../../utils/SpawnUtils\";\r\nimport { executeRegisteredCallback } from \"../../utils/CallbackUtils\";\r\nimport { CertaConfig } from \"../../CertaConfig\";\r\nimport { writeCoverageData } from \"../../utils/CoverageUtils\";\r\nimport { configureRemoteReporter } from \"./MochaRemoteReporter\";\r\n\r\ninterface ChromeTestResults {\r\n failures: number;\r\n coverage: any;\r\n}\r\n\r\ntype ConsoleMethodName = \"log\" | \"error\" | \"dir\";\r\n\r\nlet browser: puppeteer.Browser;\r\nlet webserverProcess: ChildProcess;\r\n\r\nexport class ChromeTestRunner {\r\n public static readonly supportsCoverage = true;\r\n public static readonly supportsCleanup = true;\r\n public static async initialize(config: CertaConfig): Promise<void> {\r\n // Go ahead and launch puppeteer now - the VS Code debugger gets confused if it can't at least see the chrome instance right away.\r\n const options = {\r\n ignoreHTTPSErrors: true,\r\n args: config.chromeOptions.args,\r\n headless: !config.debug,\r\n };\r\n\r\n if (config.debug)\r\n options.args.push(`--disable-gpu`, `--remote-debugging-port=${config.ports.frontendDebugging}`);\r\n\r\n browser = await puppeteer.launch(options);\r\n\r\n const webserverEnv = {\r\n CERTA_PORT: `${config.ports.frontend}`, // eslint-disable-line @typescript-eslint/naming-convention\r\n CERTA_PATH: path.join(__dirname, \"../../../public/index.html\"), // eslint-disable-line @typescript-eslint/naming-convention\r\n CERTA_PUBLIC_DIRS: JSON.stringify(config.chromeOptions.publicDirs), // eslint-disable-line @typescript-eslint/naming-convention\r\n };\r\n webserverProcess = spawnChildProcess(\"node\", [require.resolve(\"./webserver\")], webserverEnv, true);\r\n\r\n // Don't continue until the webserver is started and listening.\r\n const webserverExited = new Promise<never>((_resolve, reject) => webserverProcess.once(\"exit\", () => reject(\"Webserver exited!\")));\r\n const webserverStarted = new Promise<number>((resolve) => webserverProcess.once(\"message\", resolve));\r\n const actualPort = await Promise.race([webserverExited, webserverStarted]);\r\n if (actualPort !== config.ports.frontend)\r\n console.warn(`CERTA: Port ${config.ports.frontend} was already in use, so serving test resources on port ${actualPort}`);\r\n process.env.CERTA_PORT = String(actualPort);\r\n }\r\n\r\n public static async runTests(config: CertaConfig): Promise<void> {\r\n // FIXME: Do we really want to always enforce this behavior?\r\n if (process.env.CI || process.env.TF_BUILD)\r\n (config.mochaOptions as any).forbidOnly = true;\r\n\r\n const { failures, coverage } = await runTestsInPuppeteer(config, process.env.CERTA_PORT!);\r\n webserverProcess.kill();\r\n\r\n // Save nyc/istanbul coverage file.\r\n if (config.cover)\r\n writeCoverageData(coverage);\r\n\r\n process.exitCode = failures;\r\n }\r\n}\r\n\r\nasync function loadScript(page: puppeteer.Page, scriptPath: string) {\r\n return page.addScriptTag({ url: `/@/${scriptPath}` });\r\n}\r\n\r\nasync function runTestsInPuppeteer(config: CertaConfig, port: string) {\r\n return new Promise<ChromeTestResults>(async (resolve, reject) => {\r\n try {\r\n const page = (await browser.pages()).pop() || await browser.newPage();\r\n\r\n // Don't let dialogs block tests\r\n page.on(\"dialog\", async (dialog) => dialog.dismiss());\r\n\r\n // Re-throw any uncaught exceptions from the frontend in the backend\r\n page.on(\"pageerror\", reject);\r\n\r\n // Expose some functions to the frontend that will execute _in the backend context_\r\n await page.exposeFunction(\"_CertaConsole\", (type: ConsoleMethodName, args: any[]) => console[type](...args));\r\n await page.exposeFunction(\"_CertaSendToBackend\", executeRegisteredCallback);\r\n await page.exposeFunction(\"_CertaReportResults\", (results: ChromeTestResults) => {\r\n setTimeout(async () => {\r\n await browser.close();\r\n resolve(results);\r\n });\r\n });\r\n\r\n // Now load the page (and requisite scripts)...\r\n const testBundle = (config.cover && config.instrumentedTestBundle) || config.testBundle;\r\n await page.goto(`http://localhost:${port}`);\r\n await page.addScriptTag({ content: `var _CERTA_CONFIG = ${JSON.stringify(config)};` });\r\n await loadScript(page, require.resolve(\"../../utils/initLogging.js\"));\r\n await loadScript(page, require.resolve(\"mocha/mocha.js\"));\r\n await loadScript(page, require.resolve(\"source-map-support/browser-source-map-support.js\"));\r\n await loadScript(page, require.resolve(\"../../utils/initSourceMaps.js\"));\r\n await loadScript(page, require.resolve(\"./MochaSerializer.js\"));\r\n await configureRemoteReporter(page);\r\n await loadScript(page, require.resolve(\"../../utils/initMocha.js\"));\r\n await loadScript(page, testBundle);\r\n\r\n // ...and start the tests\r\n await page.evaluate(async () => {\r\n // NB: This is being evaluated in the frontend context!\r\n Mocha.reporters.Base.color = true as any;\r\n const globals = window as any;\r\n mocha.run((failures) => {\r\n const coverage = globals.__coverage__;\r\n globals._CertaReportResults({ failures, coverage }); // This will close the browser\r\n });\r\n });\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n}\r\n"]}
1
+ {"version":3,"file":"ChromeTestRunner.js","sourceRoot":"","sources":["../../../src/runners/chrome/ChromeTestRunner.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport * as path from \"path\";\r\nimport { Browser, chromium, LaunchOptions, Page } from \"playwright\";\r\nimport { ChildProcess } from \"child_process\";\r\nimport { spawnChildProcess } from \"../../utils/SpawnUtils\";\r\nimport { executeRegisteredCallback } from \"../../utils/CallbackUtils\";\r\nimport { CertaConfig } from \"../../CertaConfig\";\r\nimport { writeCoverageData } from \"../../utils/CoverageUtils\";\r\nimport { configureRemoteReporter } from \"./MochaRemoteReporter\";\r\n\r\ninterface ChromeTestResults {\r\n failures: number;\r\n coverage: any;\r\n}\r\n\r\ntype ConsoleMethodName = \"log\" | \"error\" | \"dir\";\r\n\r\nlet browser: Browser;\r\nlet webserverProcess: ChildProcess;\r\n\r\nexport class ChromeTestRunner {\r\n public static readonly supportsCoverage = true;\r\n public static readonly supportsCleanup = true;\r\n public static async initialize(config: CertaConfig): Promise<void> {\r\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.\r\n const options: LaunchOptions = {\r\n args: config.chromeOptions.args,\r\n headless: !config.debug,\r\n };\r\n\r\n if (config.debug)\r\n options.args?.push(`--disable-gpu`, `--remote-debugging-port=${config.ports.frontendDebugging}`);\r\n\r\n browser = await chromium.launch(options);\r\n\r\n const webserverEnv = {\r\n CERTA_PORT: `${config.ports.frontend}`, // eslint-disable-line @typescript-eslint/naming-convention\r\n CERTA_PATH: path.join(__dirname, \"../../../public/index.html\"), // eslint-disable-line @typescript-eslint/naming-convention\r\n CERTA_PUBLIC_DIRS: JSON.stringify(config.chromeOptions.publicDirs), // eslint-disable-line @typescript-eslint/naming-convention\r\n };\r\n webserverProcess = spawnChildProcess(\"node\", [require.resolve(\"./webserver\")], webserverEnv, true);\r\n\r\n // Don't continue until the webserver is started and listening.\r\n const webserverExited = new Promise<never>((_resolve, reject) => webserverProcess.once(\"exit\", () => reject(\"Webserver exited!\")));\r\n const webserverStarted = new Promise<number>((resolve) => webserverProcess.once(\"message\", resolve));\r\n const actualPort = await Promise.race([webserverExited, webserverStarted]);\r\n if (actualPort !== config.ports.frontend)\r\n console.warn(`CERTA: Port ${config.ports.frontend} was already in use, so serving test resources on port ${actualPort}`);\r\n process.env.CERTA_PORT = String(actualPort);\r\n }\r\n\r\n public static async runTests(config: CertaConfig): Promise<void> {\r\n // FIXME: Do we really want to always enforce this behavior?\r\n if (process.env.CI || process.env.TF_BUILD)\r\n (config.mochaOptions as any).forbidOnly = true;\r\n\r\n const { failures, coverage } = await runTestsInPlaywright(config, process.env.CERTA_PORT!);\r\n webserverProcess.kill();\r\n\r\n // Save nyc/istanbul coverage file.\r\n if (config.cover)\r\n writeCoverageData(coverage);\r\n\r\n process.exitCode = failures;\r\n }\r\n}\r\n\r\nasync function loadScript(page: Page, scriptPath: string) {\r\n return page.addScriptTag({ url: `/@/${scriptPath}` });\r\n}\r\n\r\nasync function runTestsInPlaywright(config: CertaConfig, port: string) {\r\n return new Promise<ChromeTestResults>(async (resolve, reject) => {\r\n try {\r\n const page = browser.contexts().pop()?.pages()?.pop() || await browser.newPage();\r\n\r\n // Don't let dialogs block tests\r\n page.on(\"dialog\", async (dialog: any) => dialog.dismiss());\r\n\r\n // Re-throw any uncaught exceptions from the frontend in the backend\r\n page.on(\"pageerror\", reject);\r\n\r\n // Expose some functions to the frontend that will execute _in the backend context_\r\n await page.exposeFunction(\"_CertaConsole\", (type: ConsoleMethodName, args: any[]) => console[type](...args));\r\n await page.exposeFunction(\"_CertaSendToBackend\", executeRegisteredCallback);\r\n await page.exposeFunction(\"_CertaReportResults\", (results: ChromeTestResults) => {\r\n setTimeout(async () => {\r\n await browser.close();\r\n resolve(results);\r\n });\r\n });\r\n\r\n // Now load the page (and requisite scripts)...\r\n const testBundle = (config.cover && config.instrumentedTestBundle) || config.testBundle;\r\n await page.goto(`http://localhost:${port}`);\r\n await page.addScriptTag({ content: `var _CERTA_CONFIG = ${JSON.stringify(config)};` });\r\n await loadScript(page, require.resolve(\"../../utils/initLogging.js\"));\r\n await loadScript(page, require.resolve(\"mocha/mocha.js\"));\r\n await loadScript(page, require.resolve(\"source-map-support/browser-source-map-support.js\"));\r\n await loadScript(page, require.resolve(\"../../utils/initSourceMaps.js\"));\r\n await loadScript(page, require.resolve(\"./MochaSerializer.js\"));\r\n await configureRemoteReporter(page);\r\n await loadScript(page, require.resolve(\"../../utils/initMocha.js\"));\r\n await loadScript(page, testBundle);\r\n\r\n // ...and start the tests\r\n await page.evaluate(async () => {\r\n // NB: This is being evaluated in the frontend context!\r\n Mocha.reporters.Base.color = true as any;\r\n const globals = window as any;\r\n mocha.run((failures) => {\r\n const coverage = globals.__coverage__;\r\n globals._CertaReportResults({ failures, coverage }); // This will close the browser\r\n });\r\n });\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n}\r\n"]}
@@ -1,4 +1,4 @@
1
- import * as puppeteer from "puppeteer";
1
+ import { Page } from "playwright";
2
2
  import "./MochaSerializer";
3
- export declare function configureRemoteReporter(page: puppeteer.Page): Promise<void>;
3
+ export declare function configureRemoteReporter(page: Page): Promise<void>;
4
4
  //# sourceMappingURL=MochaRemoteReporter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MochaRemoteReporter.d.ts","sourceRoot":"","sources":["../../../src/runners/chrome/MochaRemoteReporter.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,SAAS,MAAM,WAAW,CAAC;AACvC,OAAO,mBAAmB,CAAC;AAG3B,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,iBAkDjE"}
1
+ {"version":3,"file":"MochaRemoteReporter.d.ts","sourceRoot":"","sources":["../../../src/runners/chrome/MochaRemoteReporter.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,mBAAmB,CAAC;AAG3B,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,IAAI,iBAkDvD"}
@@ -1 +1 @@
1
- {"version":3,"file":"MochaRemoteReporter.js","sourceRoot":"","sources":["../../../src/runners/chrome/MochaRemoteReporter.ts"],"names":[],"mappings":";;;AAAA;;;+FAG+F;AAC/F,mCAAsC;AAEtC,6BAA2B;AAGpB,KAAK,UAAU,uBAAuB,CAAC,IAAoB;IAChE,0DAA0D;IAC1D,+EAA+E;IAC/E,MAAM,UAAU,GAAG,IAAI,qBAAY,EAAE,CAAC;IACtC,IAAI,YAAiB,CAAC;IAEtB,kFAAkF;IAClF,MAAM,IAAI,CAAC,cAAc,CAAC,sBAAsB,EAAE,CAAC,gBAAwB,EAAE,YAAoB,EAAE,eAAoB,EAAE,EAAE;QACzH,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;QAE7D,+DAA+D;QAC/D,yEAAyE;QACzE,MAAM,CAAC,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAE/C,uFAAuF;QACvF,yEAAyE;QACzE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAC9C,YAAY,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAEpC,mEAAmE;QACnE,YAAY,GAAG,IAAI,YAAY,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,kFAAkF;IAClF,MAAM,IAAI,CAAC,cAAc,CAAC,yBAAyB,EAAE,CAAC,IAAY,EAAE,KAAU,EAAE,GAAG,IAAW,EAAE,EAAE;QAChG,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC;QAC3B,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;QACvB,CAAC,GAAG,EAAE;YACJ,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5C,KAAK,CAAC,QAAQ,GAAG,CAAC,YAAoB,EAAE,eAAoB,EAAE,EAAE;gBAC9D,uEAAuE;gBACvE,MAAM,cAAc;oBAClB,YAAY,MAAoB,EAAE,QAAa;wBAC7C,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;wBACzH,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;4BAC1B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,IAAW,EAAE,EAAE;gCAClC,MAAM,CAAC,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;4BACxG,CAAC,CAAC,CAAC;yBACJ;wBACD,MAAM,CAAC,oBAAoB,CAAC,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;oBAChG,CAAC;iBACF;gBACD,OAAO,QAAQ,CAAC,cAA2C,CAAC,CAAC;YAC/D,CAAC,CAAC;QACJ,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,CAAC,CAAC;AACL,CAAC;AAlDD,0DAkDC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { EventEmitter } from \"events\";\r\nimport * as puppeteer from \"puppeteer\";\r\nimport \"./MochaSerializer\";\r\ndeclare const window: any;\r\n\r\nexport async function configureRemoteReporter(page: puppeteer.Page) {\r\n // This will stand in for mocha's \"runner\" on the backend.\r\n // Basically, we'll just be using this to echo events from the frontend runner.\r\n const mockRunner = new EventEmitter();\r\n let realReporter: any;\r\n\r\n // Expose a function to the frontend for initializing the reporter on the backend.\r\n await page.exposeFunction(\"_CertaCreateReporter\", (serializedRunner: string, reporterName: string, reporterOptions: any) => {\r\n const runner = MochaSerializer.deserialize(serializedRunner);\r\n\r\n // Reporters will use these methods to register event handlers.\r\n // Since `runner` has been marshalled via JSON, they don't already exist.\r\n runner.on = mockRunner.on.bind(mockRunner);\r\n runner.once = mockRunner.once.bind(mockRunner);\r\n\r\n // Mocha already knows how to find and construct a reporter object from a reporterName,\r\n // so we can just leverage that instead of having to re-implement it all.\r\n const backendMocha = new (require(\"mocha\"))();\r\n backendMocha.reporter(reporterName);\r\n\r\n // Mocha.reporter saves the reporter constructor in this._reporter.\r\n realReporter = new backendMocha._reporter(runner, { reporterOptions });\r\n });\r\n\r\n // Expose a function to the frontend for initializing the reporter on the backend.\r\n await page.exposeFunction(\"_CertaEmitReporterEvent\", (name: string, stats: any, ...args: any[]) => {\r\n realReporter.stats = stats;\r\n mockRunner.emit(name, ...args.map((a) => MochaSerializer.deserialize(a)));\r\n });\r\n\r\n await page.evaluate(() => {\r\n (() => {\r\n const original = mocha.reporter.bind(mocha);\r\n mocha.reporter = (reporterName: string, reporterOptions: any) => {\r\n // A mocha reporter class that just forwards all events to the backend.\r\n class RemoteReporter {\r\n constructor(runner: Mocha.Runner, _options: any) {\r\n const events = [\"start\", \"end\", \"suite\", \"suite end\", \"test\", \"test end\", \"hook\", \"hook end\", \"pass\", \"fail\", \"pending\"];\r\n for (const event of events) {\r\n runner.on(event, (...args: any[]) => {\r\n window._CertaEmitReporterEvent(event, runner.stats, ...args.map((a) => MochaSerializer.serialize(a)));\r\n });\r\n }\r\n window._CertaCreateReporter(MochaSerializer.serialize(runner), reporterName, reporterOptions);\r\n }\r\n }\r\n return original(RemoteReporter as Mocha.ReporterConstructor);\r\n };\r\n })();\r\n });\r\n}\r\n"]}
1
+ {"version":3,"file":"MochaRemoteReporter.js","sourceRoot":"","sources":["../../../src/runners/chrome/MochaRemoteReporter.ts"],"names":[],"mappings":";;;AAAA;;;+FAG+F;AAC/F,mCAAsC;AAEtC,6BAA2B;AAGpB,KAAK,UAAU,uBAAuB,CAAC,IAAU;IACtD,0DAA0D;IAC1D,+EAA+E;IAC/E,MAAM,UAAU,GAAG,IAAI,qBAAY,EAAE,CAAC;IACtC,IAAI,YAAiB,CAAC;IAEtB,kFAAkF;IAClF,MAAM,IAAI,CAAC,cAAc,CAAC,sBAAsB,EAAE,CAAC,gBAAwB,EAAE,YAAoB,EAAE,eAAoB,EAAE,EAAE;QACzH,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;QAE7D,+DAA+D;QAC/D,yEAAyE;QACzE,MAAM,CAAC,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAE/C,uFAAuF;QACvF,yEAAyE;QACzE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAC9C,YAAY,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAEpC,mEAAmE;QACnE,YAAY,GAAG,IAAI,YAAY,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,kFAAkF;IAClF,MAAM,IAAI,CAAC,cAAc,CAAC,yBAAyB,EAAE,CAAC,IAAY,EAAE,KAAU,EAAE,GAAG,IAAW,EAAE,EAAE;QAChG,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC;QAC3B,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE;QACvB,CAAC,GAAG,EAAE;YACJ,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5C,KAAK,CAAC,QAAQ,GAAG,CAAC,YAAoB,EAAE,eAAoB,EAAE,EAAE;gBAC9D,uEAAuE;gBACvE,MAAM,cAAc;oBAClB,YAAY,MAAoB,EAAE,QAAa;wBAC7C,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;wBACzH,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;4BAC1B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,IAAW,EAAE,EAAE;gCAClC,MAAM,CAAC,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;4BACxG,CAAC,CAAC,CAAC;yBACJ;wBACD,MAAM,CAAC,oBAAoB,CAAC,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;oBAChG,CAAC;iBACF;gBACD,OAAO,QAAQ,CAAC,cAA2C,CAAC,CAAC;YAC/D,CAAC,CAAC;QACJ,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,CAAC,CAAC;AACL,CAAC;AAlDD,0DAkDC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\nimport { EventEmitter } from \"events\";\r\nimport { Page } from \"playwright\";\r\nimport \"./MochaSerializer\";\r\ndeclare const window: any;\r\n\r\nexport async function configureRemoteReporter(page: Page) {\r\n // This will stand in for mocha's \"runner\" on the backend.\r\n // Basically, we'll just be using this to echo events from the frontend runner.\r\n const mockRunner = new EventEmitter();\r\n let realReporter: any;\r\n\r\n // Expose a function to the frontend for initializing the reporter on the backend.\r\n await page.exposeFunction(\"_CertaCreateReporter\", (serializedRunner: string, reporterName: string, reporterOptions: any) => {\r\n const runner = MochaSerializer.deserialize(serializedRunner);\r\n\r\n // Reporters will use these methods to register event handlers.\r\n // Since `runner` has been marshalled via JSON, they don't already exist.\r\n runner.on = mockRunner.on.bind(mockRunner);\r\n runner.once = mockRunner.once.bind(mockRunner);\r\n\r\n // Mocha already knows how to find and construct a reporter object from a reporterName,\r\n // so we can just leverage that instead of having to re-implement it all.\r\n const backendMocha = new (require(\"mocha\"))();\r\n backendMocha.reporter(reporterName);\r\n\r\n // Mocha.reporter saves the reporter constructor in this._reporter.\r\n realReporter = new backendMocha._reporter(runner, { reporterOptions });\r\n });\r\n\r\n // Expose a function to the frontend for initializing the reporter on the backend.\r\n await page.exposeFunction(\"_CertaEmitReporterEvent\", (name: string, stats: any, ...args: any[]) => {\r\n realReporter.stats = stats;\r\n mockRunner.emit(name, ...args.map((a) => MochaSerializer.deserialize(a)));\r\n });\r\n\r\n await page.evaluate(() => {\r\n (() => {\r\n const original = mocha.reporter.bind(mocha);\r\n mocha.reporter = (reporterName: string, reporterOptions: any) => {\r\n // A mocha reporter class that just forwards all events to the backend.\r\n class RemoteReporter {\r\n constructor(runner: Mocha.Runner, _options: any) {\r\n const events = [\"start\", \"end\", \"suite\", \"suite end\", \"test\", \"test end\", \"hook\", \"hook end\", \"pass\", \"fail\", \"pending\"];\r\n for (const event of events) {\r\n runner.on(event, (...args: any[]) => {\r\n window._CertaEmitReporterEvent(event, runner.stats, ...args.map((a) => MochaSerializer.serialize(a)));\r\n });\r\n }\r\n window._CertaCreateReporter(MochaSerializer.serialize(runner), reporterName, reporterOptions);\r\n }\r\n }\r\n return original(RemoteReporter as Mocha.ReporterConstructor);\r\n };\r\n })();\r\n });\r\n}\r\n"]}
@@ -3,7 +3,7 @@ type MochaObj = Mocha.Runnable | Mocha.Suite;
3
3
  /**
4
4
  * Helper for marshalling certain mocha objects between frontend and backend processes.
5
5
  *
6
- * Normally, puppeteer automatically uses JSON to serialize and deserialize arguments to backend functions exposed via `page.exposeFunction()`.
6
+ * Normally, playwright automatically uses JSON to serialize and deserialize arguments to backend functions exposed via `page.exposeFunction()`.
7
7
  * However, we face two problems when trying to pass `Mocha.Runnable` and `Mocha.Suite` instances to the backend:
8
8
  * - These objects have circular references
9
9
  * - JSON round-tripping won't preserve these objects' prototypes, and thus will be missing methods that reporters rely on.
@@ -7,7 +7,7 @@
7
7
  /**
8
8
  * Helper for marshalling certain mocha objects between frontend and backend processes.
9
9
  *
10
- * Normally, puppeteer automatically uses JSON to serialize and deserialize arguments to backend functions exposed via `page.exposeFunction()`.
10
+ * Normally, playwright automatically uses JSON to serialize and deserialize arguments to backend functions exposed via `page.exposeFunction()`.
11
11
  * However, we face two problems when trying to pass `Mocha.Runnable` and `Mocha.Suite` instances to the backend:
12
12
  * - These objects have circular references
13
13
  * - JSON round-tripping won't preserve these objects' prototypes, and thus will be missing methods that reporters rely on.
@@ -1 +1 @@
1
- {"version":3,"file":"MochaSerializer.js","sourceRoot":"","sources":["../../../src/runners/chrome/MochaSerializer.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// NB: This file is not a CommonJs module - it needs to run in the browser. Do not import or export modules here!\r\n\r\n// Object types we need to handle specially when serializing/deserializing\r\ntype MochaObj = Mocha.Runnable | Mocha.Suite;\r\n\r\n/**\r\n * Helper for marshalling certain mocha objects between frontend and backend processes.\r\n *\r\n * Normally, puppeteer automatically uses JSON to serialize and deserialize arguments to backend functions exposed via `page.exposeFunction()`.\r\n * However, we face two problems when trying to pass `Mocha.Runnable` and `Mocha.Suite` instances to the backend:\r\n * - These objects have circular references\r\n * - JSON round-tripping won't preserve these objects' prototypes, and thus will be missing methods that reporters rely on.\r\n *\r\n * This class attempts to solve this by replacing all instances of these classes with \"handles\" that simply refer to their\r\n * index in a central \"registry\" array. Because we serialize and deserialize in the same order, we can re-create this \"registry\"\r\n * on the backend as we deserialize.\r\n */\r\nclass MochaSerializer {\r\n private static _registry: MochaObj[] = [];\r\n\r\n public static createHandle(raw: MochaObj, isPrimary: boolean) {\r\n let $$index = this._registry.indexOf(raw);\r\n // Browser side of mocha is webpacked so the constructor name has an added suffix for example `Test` is converted into `Test$4`.\r\n // This is not the case is node side of mocha, so an error is thrown because of this mismatch. The `.replace()` is there to strip that suffix\r\n let $$typeName: string;\r\n if (raw instanceof Mocha.Suite)\r\n $$typeName = \"Suite\";\r\n else if (raw instanceof Mocha.Test)\r\n $$typeName = \"Test\";\r\n else if (raw instanceof Mocha.Hook)\r\n $$typeName = \"Hook\";\r\n else\r\n throw new Error(\"Unexpected instance of Mocha\");\r\n\r\n if ($$index < 0) {\r\n $$index = this._registry.push(raw) - 1;\r\n // This is a new instance, so we also need to include its properties\r\n isPrimary = true;\r\n }\r\n\r\n return (isPrimary) ? { $$index, $$typeName, ...raw } : { $$index, $$typeName };\r\n }\r\n\r\n /**\r\n * (On the frontend) Serializes a value to JSON string, recursively replacing any MochaObjs with appropriate handles\r\n * TODO: There are ***surely*** more performant ways to do this...\r\n *\r\n * @param root The root object to serialize. If this is a MochaObj, it will always include all\r\n * properties (even if it should already exist in the backend's registry).\r\n */\r\n public static serialize(root: any) {\r\n const isMochaObj = (obj: any): obj is MochaObj => (obj instanceof Mocha.Runnable || obj instanceof Mocha.Suite);\r\n\r\n const replacer = (key: string, value: any): any => {\r\n // Some pretty important properties of Errors are not enumerable, so we need to special handle them here:\r\n if (value instanceof Error)\r\n return { ...value, name: value.name, message: value.message, stack: value.stack };\r\n\r\n if (key === \"\" || !isMochaObj(value))\r\n return value;\r\n\r\n return JSON.parse(JSON.stringify(this.createHandle(value, false), replacer));\r\n };\r\n\r\n return JSON.stringify(isMochaObj(root) ? this.createHandle(root, true) : root, replacer);\r\n }\r\n\r\n /**\r\n * (On the backend) Deserializes a JSON string, replacing any MochaObj handles with their corresponding instances.\r\n * The first time we encounter a given instance's handle, we'll transform that handle object to serve as the actual instance on the backend.\r\n */\r\n public static deserialize(txt: string): any {\r\n return JSON.parse(txt, (_key, value) => {\r\n // We only need to special-case our \"handle\" objects, and we'll assume anything with `$$index` fits the bill.\r\n if (typeof value !== \"object\" || value === null || typeof value.$$index !== \"number\")\r\n return value;\r\n\r\n // Try to lookup this handle's instance in our registry\r\n const existing = this._registry[value.$$index];\r\n if (existing) {\r\n // Update property values (in case they've changed)\r\n for (const name of Object.getOwnPropertyNames(value)) {\r\n (existing as any)[name] = value[name];\r\n }\r\n return existing;\r\n }\r\n\r\n // Set the prototype and add the handle to the registry - we can now treat this as (essentially) the real instance.\r\n Object.setPrototypeOf(value, require(\"mocha\")[value.$$typeName].prototype);\r\n this._registry[value.$$index] = value;\r\n return value;\r\n });\r\n }\r\n}\r\n\r\nif (typeof global !== \"undefined\")\r\n (global as any).MochaSerializer = MochaSerializer;\r\n"]}
1
+ {"version":3,"file":"MochaSerializer.js","sourceRoot":"","sources":["../../../src/runners/chrome/MochaSerializer.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// NB: This file is not a CommonJs module - it needs to run in the browser. Do not import or export modules here!\r\n\r\n// Object types we need to handle specially when serializing/deserializing\r\ntype MochaObj = Mocha.Runnable | Mocha.Suite;\r\n\r\n/**\r\n * Helper for marshalling certain mocha objects between frontend and backend processes.\r\n *\r\n * Normally, playwright automatically uses JSON to serialize and deserialize arguments to backend functions exposed via `page.exposeFunction()`.\r\n * However, we face two problems when trying to pass `Mocha.Runnable` and `Mocha.Suite` instances to the backend:\r\n * - These objects have circular references\r\n * - JSON round-tripping won't preserve these objects' prototypes, and thus will be missing methods that reporters rely on.\r\n *\r\n * This class attempts to solve this by replacing all instances of these classes with \"handles\" that simply refer to their\r\n * index in a central \"registry\" array. Because we serialize and deserialize in the same order, we can re-create this \"registry\"\r\n * on the backend as we deserialize.\r\n */\r\nclass MochaSerializer {\r\n private static _registry: MochaObj[] = [];\r\n\r\n public static createHandle(raw: MochaObj, isPrimary: boolean) {\r\n let $$index = this._registry.indexOf(raw);\r\n // Browser side of mocha is webpacked so the constructor name has an added suffix for example `Test` is converted into `Test$4`.\r\n // This is not the case is node side of mocha, so an error is thrown because of this mismatch. The `.replace()` is there to strip that suffix\r\n let $$typeName: string;\r\n if (raw instanceof Mocha.Suite)\r\n $$typeName = \"Suite\";\r\n else if (raw instanceof Mocha.Test)\r\n $$typeName = \"Test\";\r\n else if (raw instanceof Mocha.Hook)\r\n $$typeName = \"Hook\";\r\n else\r\n throw new Error(\"Unexpected instance of Mocha\");\r\n\r\n if ($$index < 0) {\r\n $$index = this._registry.push(raw) - 1;\r\n // This is a new instance, so we also need to include its properties\r\n isPrimary = true;\r\n }\r\n\r\n return (isPrimary) ? { $$index, $$typeName, ...raw } : { $$index, $$typeName };\r\n }\r\n\r\n /**\r\n * (On the frontend) Serializes a value to JSON string, recursively replacing any MochaObjs with appropriate handles\r\n * TODO: There are ***surely*** more performant ways to do this...\r\n *\r\n * @param root The root object to serialize. If this is a MochaObj, it will always include all\r\n * properties (even if it should already exist in the backend's registry).\r\n */\r\n public static serialize(root: any) {\r\n const isMochaObj = (obj: any): obj is MochaObj => (obj instanceof Mocha.Runnable || obj instanceof Mocha.Suite);\r\n\r\n const replacer = (key: string, value: any): any => {\r\n // Some pretty important properties of Errors are not enumerable, so we need to special handle them here:\r\n if (value instanceof Error)\r\n return { ...value, name: value.name, message: value.message, stack: value.stack };\r\n\r\n if (key === \"\" || !isMochaObj(value))\r\n return value;\r\n\r\n return JSON.parse(JSON.stringify(this.createHandle(value, false), replacer));\r\n };\r\n\r\n return JSON.stringify(isMochaObj(root) ? this.createHandle(root, true) : root, replacer);\r\n }\r\n\r\n /**\r\n * (On the backend) Deserializes a JSON string, replacing any MochaObj handles with their corresponding instances.\r\n * The first time we encounter a given instance's handle, we'll transform that handle object to serve as the actual instance on the backend.\r\n */\r\n public static deserialize(txt: string): any {\r\n return JSON.parse(txt, (_key, value) => {\r\n // We only need to special-case our \"handle\" objects, and we'll assume anything with `$$index` fits the bill.\r\n if (typeof value !== \"object\" || value === null || typeof value.$$index !== \"number\")\r\n return value;\r\n\r\n // Try to lookup this handle's instance in our registry\r\n const existing = this._registry[value.$$index];\r\n if (existing) {\r\n // Update property values (in case they've changed)\r\n for (const name of Object.getOwnPropertyNames(value)) {\r\n (existing as any)[name] = value[name];\r\n }\r\n return existing;\r\n }\r\n\r\n // Set the prototype and add the handle to the registry - we can now treat this as (essentially) the real instance.\r\n Object.setPrototypeOf(value, require(\"mocha\")[value.$$typeName].prototype);\r\n this._registry[value.$$index] = value;\r\n return value;\r\n });\r\n }\r\n}\r\n\r\nif (typeof global !== \"undefined\")\r\n (global as any).MochaSerializer = MochaSerializer;\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/certa",
3
- "version": "4.1.0-dev.7",
3
+ "version": "4.1.0-dev.71",
4
4
  "description": "A mocha-based integration test runner",
5
5
  "license": "MIT",
6
6
  "main": "bin/certa.js",
@@ -29,46 +29,34 @@
29
29
  "jsonc-parser": "~2.0.3",
30
30
  "lodash": "^4.17.10",
31
31
  "mocha": "^10.0.0",
32
- "puppeteer": "15.5.0",
32
+ "playwright": "~1.35.1",
33
33
  "source-map-support": "^0.5.6",
34
34
  "yargs": "^17.4.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@itwin/eslint-plugin": "^4.0.0-dev.33",
37
+ "@itwin/eslint-plugin": "4.0.0-dev.44",
38
38
  "@types/chai": "4.3.1",
39
39
  "@types/detect-port": "~1.1.0",
40
40
  "@types/express": "^4.16.1",
41
41
  "@types/lodash": "^4.14.0",
42
42
  "@types/mocha": "^8.2.2",
43
- "@types/node": "^18.11.5",
43
+ "@types/node": "18.16.1",
44
44
  "@types/yargs": "17.0.19",
45
- "electron": "^24.0.0",
46
- "eslint": "^8.36.0",
45
+ "electron": "^25.0.0",
46
+ "eslint": "^8.44.0",
47
47
  "nyc": "^15.1.0",
48
48
  "rimraf": "^3.0.2",
49
49
  "typescript": "~5.0.2",
50
- "@itwin/build-tools": "4.1.0-dev.7"
50
+ "@itwin/build-tools": "4.1.0-dev.71"
51
51
  },
52
52
  "peerDependencies": {
53
- "electron": ">=23.0.0 <25.0.0"
53
+ "electron": ">=23.0.0 <26.0.0"
54
54
  },
55
55
  "peerDependenciesMeta": {
56
56
  "electron": {
57
57
  "optional": true
58
58
  }
59
59
  },
60
- "eslintConfig": {
61
- "plugins": [
62
- "@itwin"
63
- ],
64
- "extends": "plugin:@itwin/itwinjs-recommended",
65
- "rules": {
66
- "@typescript-eslint/no-misused-promises": "off",
67
- "@typescript-eslint/no-var-requires": "off",
68
- "@typescript-eslint/unbound-method": "off",
69
- "no-console": "off"
70
- }
71
- },
72
60
  "scripts": {
73
61
  "build": "tsc 1>&2",
74
62
  "clean": "rimraf lib .rush/temp/package-deps*.json",