diff --git a/README.md b/README.md index 1982397..82b04b1 100644 --- a/README.md +++ b/README.md @@ -9,29 +9,204 @@ runs tests using Node and UVU Configured for Node 14+ . To update, change base tsconfig from "extends": "@tsconfig/node14/tsconfig.json", update "engines" section in package.json, and update .node-version file -# Running -Use `yarn run all` . It will configure and run all the build steps +# Usage -## Setup +## Configuration Setup + +## Configuration Setup + +To set up the `applause.json` config file for the WebdriverIO tests, follow these steps: + +1. Create a new file named `applause.json` in the root directory of your project. + +2. Open the `applause.json` file and add the following JSON structure: + +```json +{ + "apiKey": "API_KEY", + "productId": 0, + "applauseTestCycleId": 0, + "testRailOptions": { + "projectId": 0, + "suiteId": 0, + "planName": "Example Plan Name", + "runName": "Example Run Name" + } +} +``` + +The `apiKey` and `productId` settings are required for execution. The `testRailOptions` and `applauseTestCycleId` settings are optional. + +3. Save the `applause.json` file. + +Now, when you run your WebdriverIO tests, they will be configured to use the settings specified in the `applause.json` file. + +## Applause Automation Reporting + +To use the `ApplauseRunService` and `ApplauseResultService` in a WebdriverIO configuration file, follow these steps: + +1. Install the `wdio-applause-reporter` package as a dev dependency by running the command: `npm install wdio-applause-reporter --save-dev`. + +2. Import the `ApplauseRunService` and `ApplauseResultService` classes in your WebdriverIO configuration file: + +```javascript +import { ApplauseRunService, ApplauseResultService } frpom 'wdio-applause-reporter'; +``` + +3. Add the `ApplauseRunService` and `ApplauseResultService` to the `services` array in your WebdriverIO configuration file: + +```javascript +exports.config = { + // ... other configuration options + + services: [ + // ... other services + [ApplauseRunService, {}], + [ApplauseResultService, {}] + ], + + // ... other configuration options +}; +``` + +4. Run your WebdriverIO tests as usual. The `ApplauseRunService` will handle setting up the Applause TestRun the `ApplauseResultService` will handle the reporting. + +## Applause Platform Reporting + +To use the `ApplausePlatformReporter` in the reporter section of a WebdriverIO configuration file, follow these steps: + +1. Install the `wdio-applause-reporter` package as a dev dependency by running the command: `npm install wdio-applause-reporter --save-dev`. -`yarn install` +2. Import the `ApplausePlatformReporter` class in your WebdriverIO configuration file: -### build +```javascript +import { ApplausePlatformReporter } from 'wdio-applause-reporter'; +``` -`yarn build` +3. Add the `ApplausePlatformReporter` to the `reporters` array in your WebdriverIO configuration file: -### test +```javascript +exports.config = { + // ... other configuration options -`yarn test` + reporters: [ + // ... other reporters + [ApplausePlatformReporter, {}] + ], -### clean + // ... other configuration options +}; +``` -`yarn clean` +4. Run your WebdriverIO tests as usual. The `ApplausePlatformReporter` will handle reporting to the Applause Platform. -### lint +## Winston Logger Configurations + +To insert a custom Winston logger into the `ApplausePlatformReporter`, `ApplauseRunService`, and `ApplauseResultService`, you can follow these steps: + +1. Create a custom Winston logger configuration in your WebdriverIO configuration file. You can use the `winston` package to create and configure your logger. Here's an example: + +```javascript +import winston from 'winston'; + +const logger = winston.createLogger({ + level: 'info', + format: winston.format.simple(), + transports: [ + new winston.transports.Console() + ] +}); +``` + +2. Pass the custom logger to the respective services and reporter by adding the `logger` option to their configuration. Here's an example: + +```javascript +exports.config = { + // ... other configuration options + + services: [ + // ... other services + [ApplauseRunService, { + logger: logger + }], + [ApplauseResultService, { + logger: logger + }] + ], + + reporters: [ + // ... other reporters + [ApplausePlatformReporter, { + logger: logger + }] + ], + + // ... other configuration options +}; +``` + +By providing the `logger` option with your custom logger, you can integrate it into the `ApplausePlatformReporter`, `ApplauseRunService`, and `ApplauseResultService` for logging purposes. + +To insert a custom Winston logger into the `ApplausePlatformReporter`, `ApplauseRunService`, and `ApplauseResultService`, you can follow these steps: + +1. Create a custom Winston logger configuration in your WebdriverIO configuration file. You can use the `winston` package to create and configure your logger. Here's an example: + +```javascript +import winston from 'winston'; + +const logger = winston.createLogger({ + level: 'info', + format: winston.format.simple(), + transports: [ + new winston.transports.Console(), + new ApplauseTransport(), + ] +}); +``` + +2. Pass the custom logger to the respective services and reporter by adding the `logger` option to their configuration. Here's an example: + +```javascript +exports.config = { + // ... other configuration options + + services: [ + // ... other services + [ApplauseRunService, { + logger: logger + }], + [ApplauseResultService, { + logger: logger + }] + ], + + reporters: [ + // ... other reporters + [ApplausePlatformReporter, { + logger: logger + }] + ], + + // ... other configuration options +}; +``` + +By providing the `logger` option with your custom logger, you can integrate it into the `ApplausePlatformReporter`, `ApplauseRunService`, and `ApplauseResultService` for logging purposes. + + +# Developing +Use `yarn run all` . It will configure and run all the build steps + +## Setup -`yarn lint` +To set up the project, follow these steps: -## Publishing +1. Clone the repository to your local machine. +2. Navigate to the project directory: `/Users/rconner/src/wdio-applause-reporter/`. +3. Install the project dependencies by running the command: `yarn install`. +4. Build the project by running: `yarn build`. +5. Run the tests using: `yarn test`. +6. Clean the project by running: `yarn clean`. +7. Lint the code with: `yarn lint`. -`yarn publish` +Make sure you have Node.js 14+ installed and configured before proceeding with these steps. diff --git a/dist/index.cjs b/dist/index.cjs index 19d0ae8..508bdd1 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -3,69 +3,191 @@ var WDIOReporter = require('@wdio/reporter'); var applauseReporterCommon = require('applause-reporter-common'); -class ApplauseWdioReporter extends WDIOReporter { +class ApplauseRunService { reporter; - constructor(options) { - super({ stdout: true, ...options }); - const config = applauseReporterCommon.loadConfig({ - properties: options, - }); - // Setup the initial maps - this.reporter = new applauseReporterCommon.ApplauseReporter(config); + logger; + // @ts-ignore + constructor(serviceOptions) { + this.logger = + serviceOptions['logger'] || applauseReporterCommon.constructDefaultLogger(); + this.reporter = new applauseReporterCommon.ApplauseReporter(applauseReporterCommon.loadConfig(serviceOptions), this.logger); + } + // @ts-ignore + async onPrepare() { + const testRunId = await this.reporter.runnerStart(); + process.env['APPLAUSE_RUN_ID'] = `${testRunId}`; } - onRunnerStart() { - this.reporter.runnerStart(); + // @ts-ignore + async onComplete() { + await this.reporter.runnerEnd(); } - onTestStart(testStats) { - this.reporter.startTestCase(testStats.uid, testStats.fullTitle, { +} +class ApplauseResultService { + reporter; + logger; + activeTest; + // @ts-ignore + constructor(serviceOptions) { + this.logger = + serviceOptions['logger'] || applauseReporterCommon.constructDefaultLogger(); + this.reporter = new applauseReporterCommon.ApplauseReporter(applauseReporterCommon.loadConfig(serviceOptions), this.logger); + } + /** + * Before test hook. This is called for tests executed by the Mocha or Jasmine framework. See beforeScenario for + * execution of Cucumber tests. + * + * @param test The test object + */ + async beforeTest(test) { + const title = this.lookupTitle(test); + this.logger.info('Starting test: ' + title); + this.activeTest = title; + await this.reporter.startTestCase(title, title, { providerSessionIds: [browser.sessionId], }); } - onTestPass(test) { - this.reporter.submitTestCaseResult(test.uid, applauseReporterCommon.TestResultStatus.PASSED, { - providerSessionGuids: [browser.sessionId], + /** + * The beforeScenario hook is called before each scenario in a Cucumber test. + * + * @param world The cucumber world object + */ + async beforeScenario(world) { + const title = this.lookupTitle(world); + this.logger.info('Starting Scenario: ' + title); + this.activeTest = title; + await this.reporter.startTestCase(title, title, { + providerSessionIds: [browser.sessionId], }); } - onTestFail(test) { - this.reporter.submitTestCaseResult(test.uid, applauseReporterCommon.TestResultStatus.FAILED, { - failureReason: test.error?.message, - providerSessionGuids: [browser.sessionId], - }); + async afterCommand(commandName, args, result) { + if (!this.activeTest) { + return; + } + if (commandName.startsWith('saveScreenshot')) { + const screenshotName = args[0].split('/').pop() || 'screenshot.png'; + this.logger.debug('Capturing screenshot'); + await this.reporter.attachTestCaseAsset(this.activeTest, screenshotName, browser.sessionId, applauseReporterCommon.AssetType.SCREENSHOT, Buffer.from(result, 'base64')); + } } - onTestRetry(test) { - this.reporter.submitTestCaseResult(test.uid, applauseReporterCommon.TestResultStatus.SKIPPED, { - failureReason: test.error?.message, - providerSessionGuids: [browser.sessionId], + /** + * The afterTest hook is called after each test in a Mocha or Jasmine test. + * + * @param test The test object + * @param _context The context object + * @param result The result object + */ + async afterTest(test, _context, result) { + this.activeTest = undefined; + const title = this.lookupTitle(test); + if (result.passed) { + this.logger.info('Test Passed: ' + title); + } + else { + this.logger.error('Test Failed: ' + title); + } + await this.captureAssets(title, result.passed); + await this.reporter.submitTestCaseResult(title, result.passed ? applauseReporterCommon.TestResultStatus.PASSED : applauseReporterCommon.TestResultStatus.FAILED, { + failureReason: result.exception, }); } - onTestSkip(test) { - this.reporter.submitTestCaseResult(test.uid, applauseReporterCommon.TestResultStatus.SKIPPED, { - failureReason: test.error?.message, - providerSessionGuids: [browser.sessionId], + /** + * The afterScenario hook is called after each scenario in a Cucumber test. + * + * @param world The cucumber world object + * @param result The result object + */ + async afterScenario(world, result) { + this.activeTest = undefined; + const title = this.lookupTitle(world); + if (result.passed) { + this.logger.info('Test Passed: ' + title); + } + else { + this.logger.error('Test Failed: ' + title); + } + await this.captureAssets(title, result.passed); + await this.reporter.submitTestCaseResult(title, result.passed ? applauseReporterCommon.TestResultStatus.PASSED : applauseReporterCommon.TestResultStatus.FAILED, { + failureReason: result.exception, }); } - async onRunnerEnd() { - await this.reporter.runnerEnd(); + /** + * Function to lookup the title from a Test or World object. WebdriverIO is inconsistent with where the title is stored. In some + * cases it is in the `fullName` property, in others it is in the `fullTitle` property, and in others it is in the `title` property. + * For cucumber, it is stored in the `pickle.name` property. If none of these are found, it will return ''. + * + * @param test The test or world object + * @returns The title of the test + */ + lookupTitle(test) { + if (test.fullName) { + return test.fullName; + } + if (test.fullTitle) { + return test.fullTitle; + } + if (!!test.parent && !!test.title) { + return test.parent + ' ' + test.title; + } + if (!!test.pickle && !!test.pickle.name) { + return test.pickle.name; + } + return ''; } - get isSynchronised() { - return this.reporter.isSynchronized(); + /** + * Function to capture assets for a test case. This includes a screenshot, page source, and console log. If the test case failed, + * the failure screenshot will be attached to the test case. + * + * @param resultId The result ID of the test case + * @param passed Whether the test case passed + */ + async captureAssets(resultId, passed) { + const assetsToUpload = []; + try { + if (!passed) { + const screenshot = Buffer.from(await browser.takeScreenshot(), 'base64'); + assetsToUpload.push([ + 'failure_screenshot.png', + applauseReporterCommon.AssetType.FAILURE_SCREENSHOT, + screenshot, + ]); + } + assetsToUpload.push([ + 'page_source.html', + applauseReporterCommon.AssetType.PAGE_SOURCE, + Buffer.from(await browser.getPageSource()), + ]); + assetsToUpload.push([ + 'console_log.txt', + applauseReporterCommon.AssetType.CONSOLE_LOG, + Buffer.from(applauseReporterCommon.APPLAUSE_LOG_RECORDS.getLogs().join('\n')), + ]); + await Promise.allSettled(assetsToUpload.map(([name, type, data]) => this.reporter.attachTestCaseAsset(resultId, name, browser.sessionId, type, data))); + } + catch (e) { + this.logger.error('Error capturing assets'); + this.logger.error(e); + } } } class ApplausePlatformWdioReporter extends WDIOReporter { publciApi; config; inflightCalls = []; + logger; constructor(options) { super({ stdout: true, ...options }); this.config = applauseReporterCommon.loadConfig({ properties: options, }); + this.logger = + options.logger || applauseReporterCommon.constructDefaultLogger(); // Setup the initial maps - this.publciApi = new applauseReporterCommon.PublicApi(this.config); + this.publciApi = new applauseReporterCommon.PublicApi(this.config, this.logger); } onTestPass(test) { const applauseTestCaseId = applauseReporterCommon.parseTestCaseName(test.fullTitle).applauseTestCaseId; if (applauseTestCaseId !== undefined) { + this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) passed`); const caps = browser.capabilities; this.inflightCalls.push(this.publciApi.submitResult(Number(applauseTestCaseId), { testCycleId: this.config.applauseTestCycleId, @@ -86,6 +208,7 @@ class ApplausePlatformWdioReporter extends WDIOReporter { onTestFail(test) { const applauseTestCaseId = applauseReporterCommon.parseTestCaseName(test.fullTitle).applauseTestCaseId; if (applauseTestCaseId !== undefined) { + this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) failed`); const caps = browser.capabilities; this.inflightCalls.push(this.publciApi.submitResult(Number(applauseTestCaseId), { testCycleId: this.config.applauseTestCycleId, @@ -106,6 +229,7 @@ class ApplausePlatformWdioReporter extends WDIOReporter { onTestSkip(test) { const applauseTestCaseId = applauseReporterCommon.parseTestCaseName(test.fullTitle).applauseTestCaseId; if (applauseTestCaseId !== undefined) { + this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) skipped`); const caps = browser.capabilities; this.inflightCalls.push(this.publciApi.submitResult(Number(applauseTestCaseId), { testCycleId: this.config.applauseTestCycleId, @@ -132,5 +256,6 @@ class ApplausePlatformWdioReporter extends WDIOReporter { } exports.ApplausePlatformWdioReporter = ApplausePlatformWdioReporter; -exports.ApplauseWdioReporter = ApplauseWdioReporter; +exports.ApplauseResultService = ApplauseResultService; +exports.ApplauseRunService = ApplauseRunService; //# sourceMappingURL=index.cjs.map diff --git a/dist/index.cjs.map b/dist/index.cjs.map index 0a5fa21..45f58ba 100644 --- a/dist/index.cjs.map +++ b/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import WDIOReporter, { TestStats } from '@wdio/reporter';\nimport {\n ApplauseReporter,\n ApplauseConfig,\n TestResultStatus,\n loadConfig,\n PublicApi,\n parseTestCaseName,\n TestRunAutoResultStatus,\n} from 'applause-reporter-common';\nimport { Browser } from 'webdriverio';\n\ndeclare let browser: Browser;\n\nexport class ApplauseWdioReporter extends WDIOReporter {\n private reporter: ApplauseReporter;\n\n constructor(options: Partial) {\n super({ stdout: true, ...options });\n const config = loadConfig({\n properties: options,\n });\n // Setup the initial maps\n this.reporter = new ApplauseReporter(config);\n }\n\n onRunnerStart() {\n this.reporter.runnerStart();\n }\n\n onTestStart(testStats: TestStats): void {\n this.reporter.startTestCase(testStats.uid, testStats.fullTitle, {\n providerSessionIds: [browser.sessionId],\n });\n }\n\n onTestPass(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.PASSED, {\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n onTestFail(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.FAILED, {\n failureReason: test.error?.message,\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n onTestRetry(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, {\n failureReason: test.error?.message,\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n onTestSkip(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, {\n failureReason: test.error?.message,\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n async onRunnerEnd(): Promise {\n await this.reporter.runnerEnd();\n }\n\n get isSynchronised(): boolean {\n return this.reporter.isSynchronized();\n }\n}\n\nexport class ApplausePlatformWdioReporter extends WDIOReporter {\n private publciApi: PublicApi;\n private config: ApplauseConfig;\n private inflightCalls: Promise[] = [];\n\n constructor(options: Partial) {\n super({ stdout: true, ...options });\n this.config = loadConfig({\n properties: options,\n });\n // Setup the initial maps\n this.publciApi = new PublicApi(this.config);\n }\n\n onTestPass(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.PASSED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestFail(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.FAILED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestSkip(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.SKIPPED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n async onRunnerEnd(): Promise {\n void (await Promise.all(this.inflightCalls));\n }\n\n get isSynchronised(): boolean {\n return this.publciApi.getCallsInFlight === 0;\n }\n}\n\nexport { ApplauseConfig };\n"],"names":["loadConfig","ApplauseReporter","TestResultStatus","PublicApi","parseTestCaseName","TestRunAutoResultStatus"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import WDIOReporter, { TestStats } from '@wdio/reporter';\nimport { Services, Frameworks } from '@wdio/types';\nimport {\n APPLAUSE_LOG_RECORDS,\n ApplauseReporter,\n AssetType,\n loadConfig,\n TestResultStatus,\n constructDefaultLogger,\n PublicApi,\n ApplauseConfig,\n parseTestCaseName,\n TestRunAutoResultStatus,\n} from 'applause-reporter-common';\nimport * as winston from 'winston';\n\nexport class ApplauseRunService implements Services.ServiceInstance {\n reporter: ApplauseReporter;\n logger: winston.Logger;\n\n // @ts-ignore\n constructor(serviceOptions: Services.ServiceOption) {\n this.logger =\n (serviceOptions['logger'] as winston.Logger) || constructDefaultLogger();\n this.reporter = new ApplauseReporter(\n loadConfig(serviceOptions),\n this.logger\n );\n }\n\n // @ts-ignore\n async onPrepare() {\n const testRunId = await this.reporter.runnerStart();\n process.env['APPLAUSE_RUN_ID'] = `${testRunId}`;\n }\n\n // @ts-ignore\n async onComplete() {\n await this.reporter.runnerEnd();\n }\n}\nexport class ApplauseResultService implements Services.ServiceInstance {\n reporter: ApplauseReporter;\n logger: winston.Logger;\n activeTest?: string;\n\n // @ts-ignore\n constructor(serviceOptions: Services.ServiceOption) {\n this.logger =\n (serviceOptions['logger'] as winston.Logger) || constructDefaultLogger();\n this.reporter = new ApplauseReporter(\n loadConfig(serviceOptions),\n this.logger\n );\n }\n\n /**\n * Before test hook. This is called for tests executed by the Mocha or Jasmine framework. See beforeScenario for\n * execution of Cucumber tests.\n *\n * @param test The test object\n */\n async beforeTest(test: Frameworks.Test) {\n const title = this.lookupTitle(test);\n this.logger.info('Starting test: ' + title);\n this.activeTest = title;\n await this.reporter.startTestCase(title, title, {\n providerSessionIds: [browser.sessionId],\n });\n }\n\n /**\n * The beforeScenario hook is called before each scenario in a Cucumber test.\n *\n * @param world The cucumber world object\n */\n async beforeScenario(world: Frameworks.World) {\n const title = this.lookupTitle(world);\n this.logger.info('Starting Scenario: ' + title);\n this.activeTest = title;\n await this.reporter.startTestCase(title, title, {\n providerSessionIds: [browser.sessionId],\n });\n }\n\n async afterCommand(\n commandName: string,\n args: any[],\n result: any\n ): Promise {\n if (!this.activeTest) {\n return;\n }\n if (commandName.startsWith('saveScreenshot')) {\n const screenshotName =\n (args[0] as string).split('/').pop() || 'screenshot.png';\n this.logger.debug('Capturing screenshot');\n await this.reporter.attachTestCaseAsset(\n this.activeTest,\n screenshotName,\n browser.sessionId,\n AssetType.SCREENSHOT,\n Buffer.from(result as string, 'base64')\n );\n }\n }\n\n /**\n * The afterTest hook is called after each test in a Mocha or Jasmine test.\n *\n * @param test The test object\n * @param _context The context object\n * @param result The result object\n */\n async afterTest(\n test: Frameworks.Test,\n _context: any,\n result: Frameworks.TestResult\n ) {\n this.activeTest = undefined;\n const title = this.lookupTitle(test);\n if (result.passed) {\n this.logger.info('Test Passed: ' + title);\n } else {\n this.logger.error('Test Failed: ' + title);\n }\n await this.captureAssets(title, result.passed);\n await this.reporter.submitTestCaseResult(\n title,\n result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED,\n {\n failureReason: result.exception,\n }\n );\n }\n\n /**\n * The afterScenario hook is called after each scenario in a Cucumber test.\n *\n * @param world The cucumber world object\n * @param result The result object\n */\n async afterScenario(world: Frameworks.World, result: Frameworks.TestResult) {\n this.activeTest = undefined;\n const title = this.lookupTitle(world);\n if (result.passed) {\n this.logger.info('Test Passed: ' + title);\n } else {\n this.logger.error('Test Failed: ' + title);\n }\n await this.captureAssets(title, result.passed);\n await this.reporter.submitTestCaseResult(\n title,\n result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED,\n {\n failureReason: result.exception,\n }\n );\n }\n\n /**\n * Function to lookup the title from a Test or World object. WebdriverIO is inconsistent with where the title is stored. In some\n * cases it is in the `fullName` property, in others it is in the `fullTitle` property, and in others it is in the `title` property.\n * For cucumber, it is stored in the `pickle.name` property. If none of these are found, it will return ''.\n *\n * @param test The test or world object\n * @returns The title of the test\n */\n private lookupTitle(\n test: Partial\n ): string {\n if (test.fullName) {\n return test.fullName;\n }\n if (test.fullTitle) {\n return test.fullTitle;\n }\n if (!!test.parent && !!test.title) {\n return test.parent + ' ' + test.title;\n }\n if (!!test.pickle && !!test.pickle.name) {\n return test.pickle.name;\n }\n return '';\n }\n\n /**\n * Function to capture assets for a test case. This includes a screenshot, page source, and console log. If the test case failed,\n * the failure screenshot will be attached to the test case.\n *\n * @param resultId The result ID of the test case\n * @param passed Whether the test case passed\n */\n private async captureAssets(\n resultId: string,\n passed: boolean\n ): Promise {\n const assetsToUpload: [string, AssetType, Buffer][] = [];\n try {\n if (!passed) {\n const screenshot = Buffer.from(\n await browser.takeScreenshot(),\n 'base64'\n );\n assetsToUpload.push([\n 'failure_screenshot.png',\n AssetType.FAILURE_SCREENSHOT,\n screenshot,\n ]);\n }\n assetsToUpload.push([\n 'page_source.html',\n AssetType.PAGE_SOURCE,\n Buffer.from(await browser.getPageSource()),\n ]);\n assetsToUpload.push([\n 'console_log.txt',\n AssetType.CONSOLE_LOG,\n Buffer.from(APPLAUSE_LOG_RECORDS.getLogs().join('\\n')),\n ]);\n\n await Promise.allSettled(\n assetsToUpload.map(([name, type, data]) =>\n this.reporter.attachTestCaseAsset(\n resultId,\n name,\n browser.sessionId,\n type,\n data\n )\n )\n );\n } catch (e) {\n this.logger.error('Error capturing assets');\n this.logger.error(e);\n }\n }\n}\n\nexport class ApplausePlatformWdioReporter extends WDIOReporter {\n private publciApi: PublicApi;\n private config: ApplauseConfig;\n private inflightCalls: Promise[] = [];\n private logger: winston.Logger;\n\n constructor(options: Partial) {\n super({ stdout: true, ...options });\n this.config = loadConfig({\n properties: options,\n });\n this.logger =\n (options.logger as winston.Logger) || constructDefaultLogger();\n // Setup the initial maps\n this.publciApi = new PublicApi(this.config, this.logger);\n }\n\n onTestPass(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) passed`);\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.PASSED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestFail(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) failed`);\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.FAILED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestSkip(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) skipped`);\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.SKIPPED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n async onRunnerEnd(): Promise {\n void (await Promise.all(this.inflightCalls));\n }\n\n get isSynchronised(): boolean {\n return this.publciApi.getCallsInFlight === 0;\n }\n}\n"],"names":["constructDefaultLogger","ApplauseReporter","loadConfig","AssetType","TestResultStatus","APPLAUSE_LOG_RECORDS","PublicApi","parseTestCaseName","TestRunAutoResultStatus"],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts index 9716502..0ea9c33 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,24 +1,75 @@ import WDIOReporter, { TestStats } from '@wdio/reporter'; -import { ApplauseConfig } from 'applause-reporter-common'; -export { ApplauseConfig } from 'applause-reporter-common'; +import { Services, Frameworks } from '@wdio/types'; +import { ApplauseReporter, ApplauseConfig } from 'applause-reporter-common'; +import * as winston from 'winston'; -declare class ApplauseWdioReporter extends WDIOReporter { - private reporter; - constructor(options: Partial); - onRunnerStart(): void; - onTestStart(testStats: TestStats): void; - onTestPass(test: TestStats): void; - onTestFail(test: TestStats): void; - onTestRetry(test: TestStats): void; - onTestSkip(test: TestStats): void; - onRunnerEnd(): Promise; - get isSynchronised(): boolean; +declare class ApplauseRunService implements Services.ServiceInstance { + reporter: ApplauseReporter; + logger: winston.Logger; + constructor(serviceOptions: Services.ServiceOption); + onPrepare(): Promise; + onComplete(): Promise; +} +declare class ApplauseResultService implements Services.ServiceInstance { + reporter: ApplauseReporter; + logger: winston.Logger; + activeTest?: string; + constructor(serviceOptions: Services.ServiceOption); + /** + * Before test hook. This is called for tests executed by the Mocha or Jasmine framework. See beforeScenario for + * execution of Cucumber tests. + * + * @param test The test object + */ + beforeTest(test: Frameworks.Test): Promise; + /** + * The beforeScenario hook is called before each scenario in a Cucumber test. + * + * @param world The cucumber world object + */ + beforeScenario(world: Frameworks.World): Promise; + afterCommand(commandName: string, args: any[], result: any): Promise; + /** + * The afterTest hook is called after each test in a Mocha or Jasmine test. + * + * @param test The test object + * @param _context The context object + * @param result The result object + */ + afterTest(test: Frameworks.Test, _context: any, result: Frameworks.TestResult): Promise; + /** + * The afterScenario hook is called after each scenario in a Cucumber test. + * + * @param world The cucumber world object + * @param result The result object + */ + afterScenario(world: Frameworks.World, result: Frameworks.TestResult): Promise; + /** + * Function to lookup the title from a Test or World object. WebdriverIO is inconsistent with where the title is stored. In some + * cases it is in the `fullName` property, in others it is in the `fullTitle` property, and in others it is in the `title` property. + * For cucumber, it is stored in the `pickle.name` property. If none of these are found, it will return ''. + * + * @param test The test or world object + * @returns The title of the test + */ + private lookupTitle; + /** + * Function to capture assets for a test case. This includes a screenshot, page source, and console log. If the test case failed, + * the failure screenshot will be attached to the test case. + * + * @param resultId The result ID of the test case + * @param passed Whether the test case passed + */ + private captureAssets; } declare class ApplausePlatformWdioReporter extends WDIOReporter { private publciApi; private config; private inflightCalls; - constructor(options: Partial); + private logger; + constructor(options: Partial); onTestPass(test: TestStats): void; onTestFail(test: TestStats): void; onTestSkip(test: TestStats): void; @@ -26,4 +77,4 @@ declare class ApplausePlatformWdioReporter extends WDIOReporter { get isSynchronised(): boolean; } -export { ApplausePlatformWdioReporter, ApplauseWdioReporter }; +export { ApplausePlatformWdioReporter, ApplauseResultService, ApplauseRunService }; diff --git a/dist/index.min.js b/dist/index.min.js index c41d0d9..53eb007 100644 --- a/dist/index.min.js +++ b/dist/index.min.js @@ -1,2 +1,2 @@ -!function(e,s){"object"==typeof exports&&"undefined"!=typeof module?s(exports,require("@wdio/reporter"),require("applause-reporter-common")):"function"==typeof define&&define.amd?define(["exports","@wdio/reporter","applause-reporter-common"],s):s((e="undefined"!=typeof globalThis?globalThis:e||self)["wdio-applause-reporter"]={},e.WDIOReporter,e.applauseReporterCommon)}(this,(function(e,s,t){"use strict";e.ApplausePlatformWdioReporter=class extends s{publciApi;config;inflightCalls=[];constructor(e){super({stdout:!0,...e}),this.config=t.loadConfig({properties:e}),this.publciApi=new t.PublicApi(this.config)}onTestPass(e){const s=t.parseTestCaseName(e.fullTitle).applauseTestCaseId;if(void 0!==s){const e=browser.capabilities;this.inflightCalls.push(this.publciApi.submitResult(Number(s),{testCycleId:this.config.applauseTestCycleId,status:t.TestRunAutoResultStatus.PASSED,sessionDetailsJson:{value:{deviceName:e["appium:deviceName"],orientation:e["appium:orientation"],platformName:e.platformName,platformVersion:e["appium:platformVersion"],browserName:e.browserName,browserVersion:e.browserVersion}}}))}}onTestFail(e){const s=t.parseTestCaseName(e.fullTitle).applauseTestCaseId;if(void 0!==s){const e=browser.capabilities;this.inflightCalls.push(this.publciApi.submitResult(Number(s),{testCycleId:this.config.applauseTestCycleId,status:t.TestRunAutoResultStatus.FAILED,sessionDetailsJson:{value:{deviceName:e["appium:deviceName"],orientation:e["appium:orientation"],platformName:e.platformName,platformVersion:e["appium:platformVersion"],browserName:e.browserName,browserVersion:e.browserVersion}}}))}}onTestSkip(e){const s=t.parseTestCaseName(e.fullTitle).applauseTestCaseId;if(void 0!==s){const e=browser.capabilities;this.inflightCalls.push(this.publciApi.submitResult(Number(s),{testCycleId:this.config.applauseTestCycleId,status:t.TestRunAutoResultStatus.SKIPPED,sessionDetailsJson:{value:{deviceName:e["appium:deviceName"],orientation:e["appium:orientation"],platformName:e.platformName,platformVersion:e["appium:platformVersion"],browserName:e.browserName,browserVersion:e.browserVersion}}}))}}async onRunnerEnd(){await Promise.all(this.inflightCalls)}get isSynchronised(){return 0===this.publciApi.getCallsInFlight}},e.ApplauseWdioReporter=class extends s{reporter;constructor(e){super({stdout:!0,...e});const s=t.loadConfig({properties:e});this.reporter=new t.ApplauseReporter(s)}onRunnerStart(){this.reporter.runnerStart()}onTestStart(e){this.reporter.startTestCase(e.uid,e.fullTitle,{providerSessionIds:[browser.sessionId]})}onTestPass(e){this.reporter.submitTestCaseResult(e.uid,t.TestResultStatus.PASSED,{providerSessionGuids:[browser.sessionId]})}onTestFail(e){this.reporter.submitTestCaseResult(e.uid,t.TestResultStatus.FAILED,{failureReason:e.error?.message,providerSessionGuids:[browser.sessionId]})}onTestRetry(e){this.reporter.submitTestCaseResult(e.uid,t.TestResultStatus.SKIPPED,{failureReason:e.error?.message,providerSessionGuids:[browser.sessionId]})}onTestSkip(e){this.reporter.submitTestCaseResult(e.uid,t.TestResultStatus.SKIPPED,{failureReason:e.error?.message,providerSessionGuids:[browser.sessionId]})}async onRunnerEnd(){await this.reporter.runnerEnd()}get isSynchronised(){return this.reporter.isSynchronized()}}})); +!function(e,s){"object"==typeof exports&&"undefined"!=typeof module?s(exports,require("@wdio/reporter"),require("applause-reporter-common")):"function"==typeof define&&define.amd?define(["exports","@wdio/reporter","applause-reporter-common"],s):s((e="undefined"!=typeof globalThis?globalThis:e||self)["wdio-applause-reporter"]={},e.WDIOReporter,e.applauseReporterCommon)}(this,(function(e,s,t){"use strict";e.ApplausePlatformWdioReporter=class extends s{publciApi;config;inflightCalls=[];logger;constructor(e){super({stdout:!0,...e}),this.config=t.loadConfig({properties:e}),this.logger=e.logger||t.constructDefaultLogger(),this.publciApi=new t.PublicApi(this.config,this.logger)}onTestPass(e){const s=t.parseTestCaseName(e.fullTitle).applauseTestCaseId;if(void 0!==s){this.logger.info(`Test ${e.fullTitle}(${s}) passed`);const r=browser.capabilities;this.inflightCalls.push(this.publciApi.submitResult(Number(s),{testCycleId:this.config.applauseTestCycleId,status:t.TestRunAutoResultStatus.PASSED,sessionDetailsJson:{value:{deviceName:r["appium:deviceName"],orientation:r["appium:orientation"],platformName:r.platformName,platformVersion:r["appium:platformVersion"],browserName:r.browserName,browserVersion:r.browserVersion}}}))}}onTestFail(e){const s=t.parseTestCaseName(e.fullTitle).applauseTestCaseId;if(void 0!==s){this.logger.info(`Test ${e.fullTitle}(${s}) failed`);const r=browser.capabilities;this.inflightCalls.push(this.publciApi.submitResult(Number(s),{testCycleId:this.config.applauseTestCycleId,status:t.TestRunAutoResultStatus.FAILED,sessionDetailsJson:{value:{deviceName:r["appium:deviceName"],orientation:r["appium:orientation"],platformName:r.platformName,platformVersion:r["appium:platformVersion"],browserName:r.browserName,browserVersion:r.browserVersion}}}))}}onTestSkip(e){const s=t.parseTestCaseName(e.fullTitle).applauseTestCaseId;if(void 0!==s){this.logger.info(`Test ${e.fullTitle}(${s}) skipped`);const r=browser.capabilities;this.inflightCalls.push(this.publciApi.submitResult(Number(s),{testCycleId:this.config.applauseTestCycleId,status:t.TestRunAutoResultStatus.SKIPPED,sessionDetailsJson:{value:{deviceName:r["appium:deviceName"],orientation:r["appium:orientation"],platformName:r.platformName,platformVersion:r["appium:platformVersion"],browserName:r.browserName,browserVersion:r.browserVersion}}}))}}async onRunnerEnd(){await Promise.all(this.inflightCalls)}get isSynchronised(){return 0===this.publciApi.getCallsInFlight}},e.ApplauseResultService=class{reporter;logger;activeTest;constructor(e){this.logger=e.logger||t.constructDefaultLogger(),this.reporter=new t.ApplauseReporter(t.loadConfig(e),this.logger)}async beforeTest(e){const s=this.lookupTitle(e);this.logger.info("Starting test: "+s),this.activeTest=s,await this.reporter.startTestCase(s,s,{providerSessionIds:[browser.sessionId]})}async beforeScenario(e){const s=this.lookupTitle(e);this.logger.info("Starting Scenario: "+s),this.activeTest=s,await this.reporter.startTestCase(s,s,{providerSessionIds:[browser.sessionId]})}async afterCommand(e,s,r){if(this.activeTest&&e.startsWith("saveScreenshot")){const e=s[0].split("/").pop()||"screenshot.png";this.logger.debug("Capturing screenshot"),await this.reporter.attachTestCaseAsset(this.activeTest,e,browser.sessionId,t.AssetType.SCREENSHOT,Buffer.from(r,"base64"))}}async afterTest(e,s,r){this.activeTest=void 0;const i=this.lookupTitle(e);r.passed?this.logger.info("Test Passed: "+i):this.logger.error("Test Failed: "+i),await this.captureAssets(i,r.passed),await this.reporter.submitTestCaseResult(i,r.passed?t.TestResultStatus.PASSED:t.TestResultStatus.FAILED,{failureReason:r.exception})}async afterScenario(e,s){this.activeTest=void 0;const r=this.lookupTitle(e);s.passed?this.logger.info("Test Passed: "+r):this.logger.error("Test Failed: "+r),await this.captureAssets(r,s.passed),await this.reporter.submitTestCaseResult(r,s.passed?t.TestResultStatus.PASSED:t.TestResultStatus.FAILED,{failureReason:s.exception})}lookupTitle(e){return e.fullName?e.fullName:e.fullTitle?e.fullTitle:e.parent&&e.title?e.parent+" "+e.title:e.pickle&&e.pickle.name?e.pickle.name:""}async captureAssets(e,s){const r=[];try{if(!s){const e=Buffer.from(await browser.takeScreenshot(),"base64");r.push(["failure_screenshot.png",t.AssetType.FAILURE_SCREENSHOT,e])}r.push(["page_source.html",t.AssetType.PAGE_SOURCE,Buffer.from(await browser.getPageSource())]),r.push(["console_log.txt",t.AssetType.CONSOLE_LOG,Buffer.from(t.APPLAUSE_LOG_RECORDS.getLogs().join("\n"))]),await Promise.allSettled(r.map((([s,t,r])=>this.reporter.attachTestCaseAsset(e,s,browser.sessionId,t,r))))}catch(e){this.logger.error("Error capturing assets"),this.logger.error(e)}}},e.ApplauseRunService=class{reporter;logger;constructor(e){this.logger=e.logger||t.constructDefaultLogger(),this.reporter=new t.ApplauseReporter(t.loadConfig(e),this.logger)}async onPrepare(){const e=await this.reporter.runnerStart();process.env.APPLAUSE_RUN_ID=`${e}`}async onComplete(){await this.reporter.runnerEnd()}}})); //# sourceMappingURL=index.min.js.map diff --git a/dist/index.min.js.map b/dist/index.min.js.map index 417b582..bbb41b5 100644 --- a/dist/index.min.js.map +++ b/dist/index.min.js.map @@ -1 +1 @@ -{"version":3,"file":"index.min.js","sources":["../src/index.ts"],"sourcesContent":["import WDIOReporter, { TestStats } from '@wdio/reporter';\nimport {\n ApplauseReporter,\n ApplauseConfig,\n TestResultStatus,\n loadConfig,\n PublicApi,\n parseTestCaseName,\n TestRunAutoResultStatus,\n} from 'applause-reporter-common';\nimport { Browser } from 'webdriverio';\n\ndeclare let browser: Browser;\n\nexport class ApplauseWdioReporter extends WDIOReporter {\n private reporter: ApplauseReporter;\n\n constructor(options: Partial) {\n super({ stdout: true, ...options });\n const config = loadConfig({\n properties: options,\n });\n // Setup the initial maps\n this.reporter = new ApplauseReporter(config);\n }\n\n onRunnerStart() {\n this.reporter.runnerStart();\n }\n\n onTestStart(testStats: TestStats): void {\n this.reporter.startTestCase(testStats.uid, testStats.fullTitle, {\n providerSessionIds: [browser.sessionId],\n });\n }\n\n onTestPass(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.PASSED, {\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n onTestFail(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.FAILED, {\n failureReason: test.error?.message,\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n onTestRetry(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, {\n failureReason: test.error?.message,\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n onTestSkip(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, {\n failureReason: test.error?.message,\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n async onRunnerEnd(): Promise {\n await this.reporter.runnerEnd();\n }\n\n get isSynchronised(): boolean {\n return this.reporter.isSynchronized();\n }\n}\n\nexport class ApplausePlatformWdioReporter extends WDIOReporter {\n private publciApi: PublicApi;\n private config: ApplauseConfig;\n private inflightCalls: Promise[] = [];\n\n constructor(options: Partial) {\n super({ stdout: true, ...options });\n this.config = loadConfig({\n properties: options,\n });\n // Setup the initial maps\n this.publciApi = new PublicApi(this.config);\n }\n\n onTestPass(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.PASSED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestFail(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.FAILED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestSkip(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.SKIPPED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n async onRunnerEnd(): Promise {\n void (await Promise.all(this.inflightCalls));\n }\n\n get isSynchronised(): boolean {\n return this.publciApi.getCallsInFlight === 0;\n }\n}\n\nexport { ApplauseConfig };\n"],"names":["WDIOReporter","publciApi","config","inflightCalls","constructor","options","super","stdout","this","loadConfig","properties","PublicApi","onTestPass","test","applauseTestCaseId","parseTestCaseName","fullTitle","undefined","caps","browser","capabilities","push","submitResult","Number","testCycleId","applauseTestCycleId","status","TestRunAutoResultStatus","PASSED","sessionDetailsJson","value","deviceName","orientation","platformName","platformVersion","browserName","browserVersion","onTestFail","FAILED","onTestSkip","SKIPPED","onRunnerEnd","Promise","all","isSynchronised","getCallsInFlight","reporter","ApplauseReporter","onRunnerStart","runnerStart","onTestStart","testStats","startTestCase","uid","providerSessionIds","sessionId","submitTestCaseResult","TestResultStatus","providerSessionGuids","failureReason","error","message","onTestRetry","runnerEnd","isSynchronized"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.min.js","sources":["../src/index.ts"],"sourcesContent":["import WDIOReporter, { TestStats } from '@wdio/reporter';\nimport { Services, Frameworks } from '@wdio/types';\nimport {\n APPLAUSE_LOG_RECORDS,\n ApplauseReporter,\n AssetType,\n loadConfig,\n TestResultStatus,\n constructDefaultLogger,\n PublicApi,\n ApplauseConfig,\n parseTestCaseName,\n TestRunAutoResultStatus,\n} from 'applause-reporter-common';\nimport * as winston from 'winston';\n\nexport class ApplauseRunService implements Services.ServiceInstance {\n reporter: ApplauseReporter;\n logger: winston.Logger;\n\n // @ts-ignore\n constructor(serviceOptions: Services.ServiceOption) {\n this.logger =\n (serviceOptions['logger'] as winston.Logger) || constructDefaultLogger();\n this.reporter = new ApplauseReporter(\n loadConfig(serviceOptions),\n this.logger\n );\n }\n\n // @ts-ignore\n async onPrepare() {\n const testRunId = await this.reporter.runnerStart();\n process.env['APPLAUSE_RUN_ID'] = `${testRunId}`;\n }\n\n // @ts-ignore\n async onComplete() {\n await this.reporter.runnerEnd();\n }\n}\nexport class ApplauseResultService implements Services.ServiceInstance {\n reporter: ApplauseReporter;\n logger: winston.Logger;\n activeTest?: string;\n\n // @ts-ignore\n constructor(serviceOptions: Services.ServiceOption) {\n this.logger =\n (serviceOptions['logger'] as winston.Logger) || constructDefaultLogger();\n this.reporter = new ApplauseReporter(\n loadConfig(serviceOptions),\n this.logger\n );\n }\n\n /**\n * Before test hook. This is called for tests executed by the Mocha or Jasmine framework. See beforeScenario for\n * execution of Cucumber tests.\n *\n * @param test The test object\n */\n async beforeTest(test: Frameworks.Test) {\n const title = this.lookupTitle(test);\n this.logger.info('Starting test: ' + title);\n this.activeTest = title;\n await this.reporter.startTestCase(title, title, {\n providerSessionIds: [browser.sessionId],\n });\n }\n\n /**\n * The beforeScenario hook is called before each scenario in a Cucumber test.\n *\n * @param world The cucumber world object\n */\n async beforeScenario(world: Frameworks.World) {\n const title = this.lookupTitle(world);\n this.logger.info('Starting Scenario: ' + title);\n this.activeTest = title;\n await this.reporter.startTestCase(title, title, {\n providerSessionIds: [browser.sessionId],\n });\n }\n\n async afterCommand(\n commandName: string,\n args: any[],\n result: any\n ): Promise {\n if (!this.activeTest) {\n return;\n }\n if (commandName.startsWith('saveScreenshot')) {\n const screenshotName =\n (args[0] as string).split('/').pop() || 'screenshot.png';\n this.logger.debug('Capturing screenshot');\n await this.reporter.attachTestCaseAsset(\n this.activeTest,\n screenshotName,\n browser.sessionId,\n AssetType.SCREENSHOT,\n Buffer.from(result as string, 'base64')\n );\n }\n }\n\n /**\n * The afterTest hook is called after each test in a Mocha or Jasmine test.\n *\n * @param test The test object\n * @param _context The context object\n * @param result The result object\n */\n async afterTest(\n test: Frameworks.Test,\n _context: any,\n result: Frameworks.TestResult\n ) {\n this.activeTest = undefined;\n const title = this.lookupTitle(test);\n if (result.passed) {\n this.logger.info('Test Passed: ' + title);\n } else {\n this.logger.error('Test Failed: ' + title);\n }\n await this.captureAssets(title, result.passed);\n await this.reporter.submitTestCaseResult(\n title,\n result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED,\n {\n failureReason: result.exception,\n }\n );\n }\n\n /**\n * The afterScenario hook is called after each scenario in a Cucumber test.\n *\n * @param world The cucumber world object\n * @param result The result object\n */\n async afterScenario(world: Frameworks.World, result: Frameworks.TestResult) {\n this.activeTest = undefined;\n const title = this.lookupTitle(world);\n if (result.passed) {\n this.logger.info('Test Passed: ' + title);\n } else {\n this.logger.error('Test Failed: ' + title);\n }\n await this.captureAssets(title, result.passed);\n await this.reporter.submitTestCaseResult(\n title,\n result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED,\n {\n failureReason: result.exception,\n }\n );\n }\n\n /**\n * Function to lookup the title from a Test or World object. WebdriverIO is inconsistent with where the title is stored. In some\n * cases it is in the `fullName` property, in others it is in the `fullTitle` property, and in others it is in the `title` property.\n * For cucumber, it is stored in the `pickle.name` property. If none of these are found, it will return ''.\n *\n * @param test The test or world object\n * @returns The title of the test\n */\n private lookupTitle(\n test: Partial\n ): string {\n if (test.fullName) {\n return test.fullName;\n }\n if (test.fullTitle) {\n return test.fullTitle;\n }\n if (!!test.parent && !!test.title) {\n return test.parent + ' ' + test.title;\n }\n if (!!test.pickle && !!test.pickle.name) {\n return test.pickle.name;\n }\n return '';\n }\n\n /**\n * Function to capture assets for a test case. This includes a screenshot, page source, and console log. If the test case failed,\n * the failure screenshot will be attached to the test case.\n *\n * @param resultId The result ID of the test case\n * @param passed Whether the test case passed\n */\n private async captureAssets(\n resultId: string,\n passed: boolean\n ): Promise {\n const assetsToUpload: [string, AssetType, Buffer][] = [];\n try {\n if (!passed) {\n const screenshot = Buffer.from(\n await browser.takeScreenshot(),\n 'base64'\n );\n assetsToUpload.push([\n 'failure_screenshot.png',\n AssetType.FAILURE_SCREENSHOT,\n screenshot,\n ]);\n }\n assetsToUpload.push([\n 'page_source.html',\n AssetType.PAGE_SOURCE,\n Buffer.from(await browser.getPageSource()),\n ]);\n assetsToUpload.push([\n 'console_log.txt',\n AssetType.CONSOLE_LOG,\n Buffer.from(APPLAUSE_LOG_RECORDS.getLogs().join('\\n')),\n ]);\n\n await Promise.allSettled(\n assetsToUpload.map(([name, type, data]) =>\n this.reporter.attachTestCaseAsset(\n resultId,\n name,\n browser.sessionId,\n type,\n data\n )\n )\n );\n } catch (e) {\n this.logger.error('Error capturing assets');\n this.logger.error(e);\n }\n }\n}\n\nexport class ApplausePlatformWdioReporter extends WDIOReporter {\n private publciApi: PublicApi;\n private config: ApplauseConfig;\n private inflightCalls: Promise[] = [];\n private logger: winston.Logger;\n\n constructor(options: Partial) {\n super({ stdout: true, ...options });\n this.config = loadConfig({\n properties: options,\n });\n this.logger =\n (options.logger as winston.Logger) || constructDefaultLogger();\n // Setup the initial maps\n this.publciApi = new PublicApi(this.config, this.logger);\n }\n\n onTestPass(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) passed`);\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.PASSED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestFail(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) failed`);\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.FAILED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestSkip(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) skipped`);\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.SKIPPED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n async onRunnerEnd(): Promise {\n void (await Promise.all(this.inflightCalls));\n }\n\n get isSynchronised(): boolean {\n return this.publciApi.getCallsInFlight === 0;\n }\n}\n"],"names":["WDIOReporter","publciApi","config","inflightCalls","logger","constructor","options","super","stdout","this","loadConfig","properties","constructDefaultLogger","PublicApi","onTestPass","test","applauseTestCaseId","parseTestCaseName","fullTitle","undefined","info","caps","browser","capabilities","push","submitResult","Number","testCycleId","applauseTestCycleId","status","TestRunAutoResultStatus","PASSED","sessionDetailsJson","value","deviceName","orientation","platformName","platformVersion","browserName","browserVersion","onTestFail","FAILED","onTestSkip","SKIPPED","onRunnerEnd","Promise","all","isSynchronised","getCallsInFlight","reporter","activeTest","serviceOptions","ApplauseReporter","beforeTest","title","lookupTitle","startTestCase","providerSessionIds","sessionId","beforeScenario","world","afterCommand","commandName","args","result","startsWith","screenshotName","split","pop","debug","attachTestCaseAsset","AssetType","SCREENSHOT","Buffer","from","afterTest","_context","passed","error","captureAssets","submitTestCaseResult","TestResultStatus","failureReason","exception","afterScenario","fullName","parent","pickle","name","resultId","assetsToUpload","screenshot","takeScreenshot","FAILURE_SCREENSHOT","PAGE_SOURCE","getPageSource","CONSOLE_LOG","APPLAUSE_LOG_RECORDS","getLogs","join","allSettled","map","type","data","e","onPrepare","testRunId","runnerStart","process","env","onComplete","runnerEnd"],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.mjs b/dist/index.mjs index 5cd085c..bb71955 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -1,69 +1,191 @@ import WDIOReporter from '@wdio/reporter'; -import { loadConfig, ApplauseReporter, TestResultStatus, PublicApi, parseTestCaseName, TestRunAutoResultStatus } from 'applause-reporter-common'; +import { constructDefaultLogger, ApplauseReporter, loadConfig, AssetType, TestResultStatus, APPLAUSE_LOG_RECORDS, PublicApi, parseTestCaseName, TestRunAutoResultStatus } from 'applause-reporter-common'; -class ApplauseWdioReporter extends WDIOReporter { +class ApplauseRunService { reporter; - constructor(options) { - super({ stdout: true, ...options }); - const config = loadConfig({ - properties: options, - }); - // Setup the initial maps - this.reporter = new ApplauseReporter(config); + logger; + // @ts-ignore + constructor(serviceOptions) { + this.logger = + serviceOptions['logger'] || constructDefaultLogger(); + this.reporter = new ApplauseReporter(loadConfig(serviceOptions), this.logger); + } + // @ts-ignore + async onPrepare() { + const testRunId = await this.reporter.runnerStart(); + process.env['APPLAUSE_RUN_ID'] = `${testRunId}`; } - onRunnerStart() { - this.reporter.runnerStart(); + // @ts-ignore + async onComplete() { + await this.reporter.runnerEnd(); } - onTestStart(testStats) { - this.reporter.startTestCase(testStats.uid, testStats.fullTitle, { +} +class ApplauseResultService { + reporter; + logger; + activeTest; + // @ts-ignore + constructor(serviceOptions) { + this.logger = + serviceOptions['logger'] || constructDefaultLogger(); + this.reporter = new ApplauseReporter(loadConfig(serviceOptions), this.logger); + } + /** + * Before test hook. This is called for tests executed by the Mocha or Jasmine framework. See beforeScenario for + * execution of Cucumber tests. + * + * @param test The test object + */ + async beforeTest(test) { + const title = this.lookupTitle(test); + this.logger.info('Starting test: ' + title); + this.activeTest = title; + await this.reporter.startTestCase(title, title, { providerSessionIds: [browser.sessionId], }); } - onTestPass(test) { - this.reporter.submitTestCaseResult(test.uid, TestResultStatus.PASSED, { - providerSessionGuids: [browser.sessionId], + /** + * The beforeScenario hook is called before each scenario in a Cucumber test. + * + * @param world The cucumber world object + */ + async beforeScenario(world) { + const title = this.lookupTitle(world); + this.logger.info('Starting Scenario: ' + title); + this.activeTest = title; + await this.reporter.startTestCase(title, title, { + providerSessionIds: [browser.sessionId], }); } - onTestFail(test) { - this.reporter.submitTestCaseResult(test.uid, TestResultStatus.FAILED, { - failureReason: test.error?.message, - providerSessionGuids: [browser.sessionId], - }); + async afterCommand(commandName, args, result) { + if (!this.activeTest) { + return; + } + if (commandName.startsWith('saveScreenshot')) { + const screenshotName = args[0].split('/').pop() || 'screenshot.png'; + this.logger.debug('Capturing screenshot'); + await this.reporter.attachTestCaseAsset(this.activeTest, screenshotName, browser.sessionId, AssetType.SCREENSHOT, Buffer.from(result, 'base64')); + } } - onTestRetry(test) { - this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, { - failureReason: test.error?.message, - providerSessionGuids: [browser.sessionId], + /** + * The afterTest hook is called after each test in a Mocha or Jasmine test. + * + * @param test The test object + * @param _context The context object + * @param result The result object + */ + async afterTest(test, _context, result) { + this.activeTest = undefined; + const title = this.lookupTitle(test); + if (result.passed) { + this.logger.info('Test Passed: ' + title); + } + else { + this.logger.error('Test Failed: ' + title); + } + await this.captureAssets(title, result.passed); + await this.reporter.submitTestCaseResult(title, result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED, { + failureReason: result.exception, }); } - onTestSkip(test) { - this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, { - failureReason: test.error?.message, - providerSessionGuids: [browser.sessionId], + /** + * The afterScenario hook is called after each scenario in a Cucumber test. + * + * @param world The cucumber world object + * @param result The result object + */ + async afterScenario(world, result) { + this.activeTest = undefined; + const title = this.lookupTitle(world); + if (result.passed) { + this.logger.info('Test Passed: ' + title); + } + else { + this.logger.error('Test Failed: ' + title); + } + await this.captureAssets(title, result.passed); + await this.reporter.submitTestCaseResult(title, result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED, { + failureReason: result.exception, }); } - async onRunnerEnd() { - await this.reporter.runnerEnd(); + /** + * Function to lookup the title from a Test or World object. WebdriverIO is inconsistent with where the title is stored. In some + * cases it is in the `fullName` property, in others it is in the `fullTitle` property, and in others it is in the `title` property. + * For cucumber, it is stored in the `pickle.name` property. If none of these are found, it will return ''. + * + * @param test The test or world object + * @returns The title of the test + */ + lookupTitle(test) { + if (test.fullName) { + return test.fullName; + } + if (test.fullTitle) { + return test.fullTitle; + } + if (!!test.parent && !!test.title) { + return test.parent + ' ' + test.title; + } + if (!!test.pickle && !!test.pickle.name) { + return test.pickle.name; + } + return ''; } - get isSynchronised() { - return this.reporter.isSynchronized(); + /** + * Function to capture assets for a test case. This includes a screenshot, page source, and console log. If the test case failed, + * the failure screenshot will be attached to the test case. + * + * @param resultId The result ID of the test case + * @param passed Whether the test case passed + */ + async captureAssets(resultId, passed) { + const assetsToUpload = []; + try { + if (!passed) { + const screenshot = Buffer.from(await browser.takeScreenshot(), 'base64'); + assetsToUpload.push([ + 'failure_screenshot.png', + AssetType.FAILURE_SCREENSHOT, + screenshot, + ]); + } + assetsToUpload.push([ + 'page_source.html', + AssetType.PAGE_SOURCE, + Buffer.from(await browser.getPageSource()), + ]); + assetsToUpload.push([ + 'console_log.txt', + AssetType.CONSOLE_LOG, + Buffer.from(APPLAUSE_LOG_RECORDS.getLogs().join('\n')), + ]); + await Promise.allSettled(assetsToUpload.map(([name, type, data]) => this.reporter.attachTestCaseAsset(resultId, name, browser.sessionId, type, data))); + } + catch (e) { + this.logger.error('Error capturing assets'); + this.logger.error(e); + } } } class ApplausePlatformWdioReporter extends WDIOReporter { publciApi; config; inflightCalls = []; + logger; constructor(options) { super({ stdout: true, ...options }); this.config = loadConfig({ properties: options, }); + this.logger = + options.logger || constructDefaultLogger(); // Setup the initial maps - this.publciApi = new PublicApi(this.config); + this.publciApi = new PublicApi(this.config, this.logger); } onTestPass(test) { const applauseTestCaseId = parseTestCaseName(test.fullTitle).applauseTestCaseId; if (applauseTestCaseId !== undefined) { + this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) passed`); const caps = browser.capabilities; this.inflightCalls.push(this.publciApi.submitResult(Number(applauseTestCaseId), { testCycleId: this.config.applauseTestCycleId, @@ -84,6 +206,7 @@ class ApplausePlatformWdioReporter extends WDIOReporter { onTestFail(test) { const applauseTestCaseId = parseTestCaseName(test.fullTitle).applauseTestCaseId; if (applauseTestCaseId !== undefined) { + this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) failed`); const caps = browser.capabilities; this.inflightCalls.push(this.publciApi.submitResult(Number(applauseTestCaseId), { testCycleId: this.config.applauseTestCycleId, @@ -104,6 +227,7 @@ class ApplausePlatformWdioReporter extends WDIOReporter { onTestSkip(test) { const applauseTestCaseId = parseTestCaseName(test.fullTitle).applauseTestCaseId; if (applauseTestCaseId !== undefined) { + this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) skipped`); const caps = browser.capabilities; this.inflightCalls.push(this.publciApi.submitResult(Number(applauseTestCaseId), { testCycleId: this.config.applauseTestCycleId, @@ -129,5 +253,5 @@ class ApplausePlatformWdioReporter extends WDIOReporter { } } -export { ApplausePlatformWdioReporter, ApplauseWdioReporter }; +export { ApplausePlatformWdioReporter, ApplauseResultService, ApplauseRunService }; //# sourceMappingURL=index.mjs.map diff --git a/dist/index.mjs.map b/dist/index.mjs.map index 07889cb..c628e8f 100644 --- a/dist/index.mjs.map +++ b/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import WDIOReporter, { TestStats } from '@wdio/reporter';\nimport {\n ApplauseReporter,\n ApplauseConfig,\n TestResultStatus,\n loadConfig,\n PublicApi,\n parseTestCaseName,\n TestRunAutoResultStatus,\n} from 'applause-reporter-common';\nimport { Browser } from 'webdriverio';\n\ndeclare let browser: Browser;\n\nexport class ApplauseWdioReporter extends WDIOReporter {\n private reporter: ApplauseReporter;\n\n constructor(options: Partial) {\n super({ stdout: true, ...options });\n const config = loadConfig({\n properties: options,\n });\n // Setup the initial maps\n this.reporter = new ApplauseReporter(config);\n }\n\n onRunnerStart() {\n this.reporter.runnerStart();\n }\n\n onTestStart(testStats: TestStats): void {\n this.reporter.startTestCase(testStats.uid, testStats.fullTitle, {\n providerSessionIds: [browser.sessionId],\n });\n }\n\n onTestPass(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.PASSED, {\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n onTestFail(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.FAILED, {\n failureReason: test.error?.message,\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n onTestRetry(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, {\n failureReason: test.error?.message,\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n onTestSkip(test: TestStats): void {\n this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, {\n failureReason: test.error?.message,\n providerSessionGuids: [browser.sessionId],\n });\n }\n\n async onRunnerEnd(): Promise {\n await this.reporter.runnerEnd();\n }\n\n get isSynchronised(): boolean {\n return this.reporter.isSynchronized();\n }\n}\n\nexport class ApplausePlatformWdioReporter extends WDIOReporter {\n private publciApi: PublicApi;\n private config: ApplauseConfig;\n private inflightCalls: Promise[] = [];\n\n constructor(options: Partial) {\n super({ stdout: true, ...options });\n this.config = loadConfig({\n properties: options,\n });\n // Setup the initial maps\n this.publciApi = new PublicApi(this.config);\n }\n\n onTestPass(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.PASSED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestFail(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.FAILED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestSkip(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.SKIPPED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n async onRunnerEnd(): Promise {\n void (await Promise.all(this.inflightCalls));\n }\n\n get isSynchronised(): boolean {\n return this.publciApi.getCallsInFlight === 0;\n }\n}\n\nexport { ApplauseConfig };\n"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import WDIOReporter, { TestStats } from '@wdio/reporter';\nimport { Services, Frameworks } from '@wdio/types';\nimport {\n APPLAUSE_LOG_RECORDS,\n ApplauseReporter,\n AssetType,\n loadConfig,\n TestResultStatus,\n constructDefaultLogger,\n PublicApi,\n ApplauseConfig,\n parseTestCaseName,\n TestRunAutoResultStatus,\n} from 'applause-reporter-common';\nimport * as winston from 'winston';\n\nexport class ApplauseRunService implements Services.ServiceInstance {\n reporter: ApplauseReporter;\n logger: winston.Logger;\n\n // @ts-ignore\n constructor(serviceOptions: Services.ServiceOption) {\n this.logger =\n (serviceOptions['logger'] as winston.Logger) || constructDefaultLogger();\n this.reporter = new ApplauseReporter(\n loadConfig(serviceOptions),\n this.logger\n );\n }\n\n // @ts-ignore\n async onPrepare() {\n const testRunId = await this.reporter.runnerStart();\n process.env['APPLAUSE_RUN_ID'] = `${testRunId}`;\n }\n\n // @ts-ignore\n async onComplete() {\n await this.reporter.runnerEnd();\n }\n}\nexport class ApplauseResultService implements Services.ServiceInstance {\n reporter: ApplauseReporter;\n logger: winston.Logger;\n activeTest?: string;\n\n // @ts-ignore\n constructor(serviceOptions: Services.ServiceOption) {\n this.logger =\n (serviceOptions['logger'] as winston.Logger) || constructDefaultLogger();\n this.reporter = new ApplauseReporter(\n loadConfig(serviceOptions),\n this.logger\n );\n }\n\n /**\n * Before test hook. This is called for tests executed by the Mocha or Jasmine framework. See beforeScenario for\n * execution of Cucumber tests.\n *\n * @param test The test object\n */\n async beforeTest(test: Frameworks.Test) {\n const title = this.lookupTitle(test);\n this.logger.info('Starting test: ' + title);\n this.activeTest = title;\n await this.reporter.startTestCase(title, title, {\n providerSessionIds: [browser.sessionId],\n });\n }\n\n /**\n * The beforeScenario hook is called before each scenario in a Cucumber test.\n *\n * @param world The cucumber world object\n */\n async beforeScenario(world: Frameworks.World) {\n const title = this.lookupTitle(world);\n this.logger.info('Starting Scenario: ' + title);\n this.activeTest = title;\n await this.reporter.startTestCase(title, title, {\n providerSessionIds: [browser.sessionId],\n });\n }\n\n async afterCommand(\n commandName: string,\n args: any[],\n result: any\n ): Promise {\n if (!this.activeTest) {\n return;\n }\n if (commandName.startsWith('saveScreenshot')) {\n const screenshotName =\n (args[0] as string).split('/').pop() || 'screenshot.png';\n this.logger.debug('Capturing screenshot');\n await this.reporter.attachTestCaseAsset(\n this.activeTest,\n screenshotName,\n browser.sessionId,\n AssetType.SCREENSHOT,\n Buffer.from(result as string, 'base64')\n );\n }\n }\n\n /**\n * The afterTest hook is called after each test in a Mocha or Jasmine test.\n *\n * @param test The test object\n * @param _context The context object\n * @param result The result object\n */\n async afterTest(\n test: Frameworks.Test,\n _context: any,\n result: Frameworks.TestResult\n ) {\n this.activeTest = undefined;\n const title = this.lookupTitle(test);\n if (result.passed) {\n this.logger.info('Test Passed: ' + title);\n } else {\n this.logger.error('Test Failed: ' + title);\n }\n await this.captureAssets(title, result.passed);\n await this.reporter.submitTestCaseResult(\n title,\n result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED,\n {\n failureReason: result.exception,\n }\n );\n }\n\n /**\n * The afterScenario hook is called after each scenario in a Cucumber test.\n *\n * @param world The cucumber world object\n * @param result The result object\n */\n async afterScenario(world: Frameworks.World, result: Frameworks.TestResult) {\n this.activeTest = undefined;\n const title = this.lookupTitle(world);\n if (result.passed) {\n this.logger.info('Test Passed: ' + title);\n } else {\n this.logger.error('Test Failed: ' + title);\n }\n await this.captureAssets(title, result.passed);\n await this.reporter.submitTestCaseResult(\n title,\n result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED,\n {\n failureReason: result.exception,\n }\n );\n }\n\n /**\n * Function to lookup the title from a Test or World object. WebdriverIO is inconsistent with where the title is stored. In some\n * cases it is in the `fullName` property, in others it is in the `fullTitle` property, and in others it is in the `title` property.\n * For cucumber, it is stored in the `pickle.name` property. If none of these are found, it will return ''.\n *\n * @param test The test or world object\n * @returns The title of the test\n */\n private lookupTitle(\n test: Partial\n ): string {\n if (test.fullName) {\n return test.fullName;\n }\n if (test.fullTitle) {\n return test.fullTitle;\n }\n if (!!test.parent && !!test.title) {\n return test.parent + ' ' + test.title;\n }\n if (!!test.pickle && !!test.pickle.name) {\n return test.pickle.name;\n }\n return '';\n }\n\n /**\n * Function to capture assets for a test case. This includes a screenshot, page source, and console log. If the test case failed,\n * the failure screenshot will be attached to the test case.\n *\n * @param resultId The result ID of the test case\n * @param passed Whether the test case passed\n */\n private async captureAssets(\n resultId: string,\n passed: boolean\n ): Promise {\n const assetsToUpload: [string, AssetType, Buffer][] = [];\n try {\n if (!passed) {\n const screenshot = Buffer.from(\n await browser.takeScreenshot(),\n 'base64'\n );\n assetsToUpload.push([\n 'failure_screenshot.png',\n AssetType.FAILURE_SCREENSHOT,\n screenshot,\n ]);\n }\n assetsToUpload.push([\n 'page_source.html',\n AssetType.PAGE_SOURCE,\n Buffer.from(await browser.getPageSource()),\n ]);\n assetsToUpload.push([\n 'console_log.txt',\n AssetType.CONSOLE_LOG,\n Buffer.from(APPLAUSE_LOG_RECORDS.getLogs().join('\\n')),\n ]);\n\n await Promise.allSettled(\n assetsToUpload.map(([name, type, data]) =>\n this.reporter.attachTestCaseAsset(\n resultId,\n name,\n browser.sessionId,\n type,\n data\n )\n )\n );\n } catch (e) {\n this.logger.error('Error capturing assets');\n this.logger.error(e);\n }\n }\n}\n\nexport class ApplausePlatformWdioReporter extends WDIOReporter {\n private publciApi: PublicApi;\n private config: ApplauseConfig;\n private inflightCalls: Promise[] = [];\n private logger: winston.Logger;\n\n constructor(options: Partial) {\n super({ stdout: true, ...options });\n this.config = loadConfig({\n properties: options,\n });\n this.logger =\n (options.logger as winston.Logger) || constructDefaultLogger();\n // Setup the initial maps\n this.publciApi = new PublicApi(this.config, this.logger);\n }\n\n onTestPass(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) passed`);\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.PASSED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestFail(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) failed`);\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.FAILED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n onTestSkip(test: TestStats): void {\n const applauseTestCaseId = parseTestCaseName(\n test.fullTitle\n ).applauseTestCaseId;\n if (applauseTestCaseId !== undefined) {\n this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) skipped`);\n const caps = browser.capabilities as WebdriverIO.Capabilities;\n this.inflightCalls.push(\n this.publciApi.submitResult(Number(applauseTestCaseId), {\n testCycleId: this.config.applauseTestCycleId!,\n status: TestRunAutoResultStatus.SKIPPED,\n sessionDetailsJson: {\n value: {\n deviceName: caps['appium:deviceName'],\n orientation: caps['appium:orientation'],\n platformName: caps.platformName,\n platformVersion: caps['appium:platformVersion'],\n browserName: caps.browserName,\n browserVersion: caps.browserVersion,\n },\n },\n })\n );\n }\n }\n\n async onRunnerEnd(): Promise {\n void (await Promise.all(this.inflightCalls));\n }\n\n get isSynchronised(): boolean {\n return this.publciApi.getCallsInFlight === 0;\n }\n}\n"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index a6a8867..32d311f 100644 --- a/package.json +++ b/package.json @@ -66,10 +66,13 @@ "yarn": "^1.22.19" }, "dependencies": { + "@wdio/globals": "^8.39.1", "@wdio/reporter": "^8.16.3", + "@wdio/types": "^8.39.0", "applause-reporter-common": "github:ApplauseOSS/applause-reporter-common#dev", "axios": "^1.5.0", - "webdriverio": "^8.16.6" + "webdriverio": "^8.16.6", + "winston": "^3.13.1" }, "resolutions": { "strip-ansi": "6.0.1", diff --git a/rollup.config.js b/rollup.config.js index 80c52c7..dd084af 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -41,6 +41,6 @@ const options = [ input: "src/index.ts", output: [{ file: "dist/index.d.ts", format: "es" }], plugins: [dts.default()], - }, + }, ] export default options; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index a842445..c13d65d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,72 +1,239 @@ import WDIOReporter, { TestStats } from '@wdio/reporter'; +import { Services, Frameworks } from '@wdio/types'; import { + APPLAUSE_LOG_RECORDS, ApplauseReporter, - ApplauseConfig, - TestResultStatus, + AssetType, loadConfig, + TestResultStatus, + constructDefaultLogger, PublicApi, + ApplauseConfig, parseTestCaseName, TestRunAutoResultStatus, } from 'applause-reporter-common'; -import { Browser } from 'webdriverio'; +import * as winston from 'winston'; -declare let browser: Browser; +export class ApplauseRunService implements Services.ServiceInstance { + reporter: ApplauseReporter; + logger: winston.Logger; -export class ApplauseWdioReporter extends WDIOReporter { - private reporter: ApplauseReporter; + // @ts-ignore + constructor(serviceOptions: Services.ServiceOption) { + this.logger = + (serviceOptions['logger'] as winston.Logger) || constructDefaultLogger(); + this.reporter = new ApplauseReporter( + loadConfig(serviceOptions), + this.logger + ); + } - constructor(options: Partial) { - super({ stdout: true, ...options }); - const config = loadConfig({ - properties: options, - }); - // Setup the initial maps - this.reporter = new ApplauseReporter(config); + // @ts-ignore + async onPrepare() { + const testRunId = await this.reporter.runnerStart(); + process.env['APPLAUSE_RUN_ID'] = `${testRunId}`; } - onRunnerStart() { - this.reporter.runnerStart(); + // @ts-ignore + async onComplete() { + await this.reporter.runnerEnd(); } +} +export class ApplauseResultService implements Services.ServiceInstance { + reporter: ApplauseReporter; + logger: winston.Logger; + activeTest?: string; - onTestStart(testStats: TestStats): void { - this.reporter.startTestCase(testStats.uid, testStats.fullTitle, { + // @ts-ignore + constructor(serviceOptions: Services.ServiceOption) { + this.logger = + (serviceOptions['logger'] as winston.Logger) || constructDefaultLogger(); + this.reporter = new ApplauseReporter( + loadConfig(serviceOptions), + this.logger + ); + } + + /** + * Before test hook. This is called for tests executed by the Mocha or Jasmine framework. See beforeScenario for + * execution of Cucumber tests. + * + * @param test The test object + */ + async beforeTest(test: Frameworks.Test) { + const title = this.lookupTitle(test); + this.logger.info('Starting test: ' + title); + this.activeTest = title; + await this.reporter.startTestCase(title, title, { providerSessionIds: [browser.sessionId], }); } - onTestPass(test: TestStats): void { - this.reporter.submitTestCaseResult(test.uid, TestResultStatus.PASSED, { - providerSessionGuids: [browser.sessionId], + /** + * The beforeScenario hook is called before each scenario in a Cucumber test. + * + * @param world The cucumber world object + */ + async beforeScenario(world: Frameworks.World) { + const title = this.lookupTitle(world); + this.logger.info('Starting Scenario: ' + title); + this.activeTest = title; + await this.reporter.startTestCase(title, title, { + providerSessionIds: [browser.sessionId], }); } - onTestFail(test: TestStats): void { - this.reporter.submitTestCaseResult(test.uid, TestResultStatus.FAILED, { - failureReason: test.error?.message, - providerSessionGuids: [browser.sessionId], - }); + async afterCommand( + commandName: string, + args: any[], + result: any + ): Promise { + if (!this.activeTest) { + return; + } + if (commandName.startsWith('saveScreenshot')) { + const screenshotName = + (args[0] as string).split('/').pop() || 'screenshot.png'; + this.logger.debug('Capturing screenshot'); + await this.reporter.attachTestCaseAsset( + this.activeTest, + screenshotName, + browser.sessionId, + AssetType.SCREENSHOT, + Buffer.from(result as string, 'base64') + ); + } } - onTestRetry(test: TestStats): void { - this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, { - failureReason: test.error?.message, - providerSessionGuids: [browser.sessionId], - }); + /** + * The afterTest hook is called after each test in a Mocha or Jasmine test. + * + * @param test The test object + * @param _context The context object + * @param result The result object + */ + async afterTest( + test: Frameworks.Test, + _context: any, + result: Frameworks.TestResult + ) { + this.activeTest = undefined; + const title = this.lookupTitle(test); + if (result.passed) { + this.logger.info('Test Passed: ' + title); + } else { + this.logger.error('Test Failed: ' + title); + } + await this.captureAssets(title, result.passed); + await this.reporter.submitTestCaseResult( + title, + result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED, + { + failureReason: result.exception, + } + ); } - onTestSkip(test: TestStats): void { - this.reporter.submitTestCaseResult(test.uid, TestResultStatus.SKIPPED, { - failureReason: test.error?.message, - providerSessionGuids: [browser.sessionId], - }); + /** + * The afterScenario hook is called after each scenario in a Cucumber test. + * + * @param world The cucumber world object + * @param result The result object + */ + async afterScenario(world: Frameworks.World, result: Frameworks.TestResult) { + this.activeTest = undefined; + const title = this.lookupTitle(world); + if (result.passed) { + this.logger.info('Test Passed: ' + title); + } else { + this.logger.error('Test Failed: ' + title); + } + await this.captureAssets(title, result.passed); + await this.reporter.submitTestCaseResult( + title, + result.passed ? TestResultStatus.PASSED : TestResultStatus.FAILED, + { + failureReason: result.exception, + } + ); } - async onRunnerEnd(): Promise { - await this.reporter.runnerEnd(); + /** + * Function to lookup the title from a Test or World object. WebdriverIO is inconsistent with where the title is stored. In some + * cases it is in the `fullName` property, in others it is in the `fullTitle` property, and in others it is in the `title` property. + * For cucumber, it is stored in the `pickle.name` property. If none of these are found, it will return ''. + * + * @param test The test or world object + * @returns The title of the test + */ + private lookupTitle( + test: Partial + ): string { + if (test.fullName) { + return test.fullName; + } + if (test.fullTitle) { + return test.fullTitle; + } + if (!!test.parent && !!test.title) { + return test.parent + ' ' + test.title; + } + if (!!test.pickle && !!test.pickle.name) { + return test.pickle.name; + } + return ''; } - get isSynchronised(): boolean { - return this.reporter.isSynchronized(); + /** + * Function to capture assets for a test case. This includes a screenshot, page source, and console log. If the test case failed, + * the failure screenshot will be attached to the test case. + * + * @param resultId The result ID of the test case + * @param passed Whether the test case passed + */ + private async captureAssets( + resultId: string, + passed: boolean + ): Promise { + const assetsToUpload: [string, AssetType, Buffer][] = []; + try { + if (!passed) { + const screenshot = Buffer.from( + await browser.takeScreenshot(), + 'base64' + ); + assetsToUpload.push([ + 'failure_screenshot.png', + AssetType.FAILURE_SCREENSHOT, + screenshot, + ]); + } + assetsToUpload.push([ + 'page_source.html', + AssetType.PAGE_SOURCE, + Buffer.from(await browser.getPageSource()), + ]); + assetsToUpload.push([ + 'console_log.txt', + AssetType.CONSOLE_LOG, + Buffer.from(APPLAUSE_LOG_RECORDS.getLogs().join('\n')), + ]); + + await Promise.allSettled( + assetsToUpload.map(([name, type, data]) => + this.reporter.attachTestCaseAsset( + resultId, + name, + browser.sessionId, + type, + data + ) + ) + ); + } catch (e) { + this.logger.error('Error capturing assets'); + this.logger.error(e); + } } } @@ -74,14 +241,17 @@ export class ApplausePlatformWdioReporter extends WDIOReporter { private publciApi: PublicApi; private config: ApplauseConfig; private inflightCalls: Promise[] = []; + private logger: winston.Logger; - constructor(options: Partial) { + constructor(options: Partial) { super({ stdout: true, ...options }); this.config = loadConfig({ properties: options, }); + this.logger = + (options.logger as winston.Logger) || constructDefaultLogger(); // Setup the initial maps - this.publciApi = new PublicApi(this.config); + this.publciApi = new PublicApi(this.config, this.logger); } onTestPass(test: TestStats): void { @@ -89,6 +259,7 @@ export class ApplausePlatformWdioReporter extends WDIOReporter { test.fullTitle ).applauseTestCaseId; if (applauseTestCaseId !== undefined) { + this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) passed`); const caps = browser.capabilities as WebdriverIO.Capabilities; this.inflightCalls.push( this.publciApi.submitResult(Number(applauseTestCaseId), { @@ -114,6 +285,7 @@ export class ApplausePlatformWdioReporter extends WDIOReporter { test.fullTitle ).applauseTestCaseId; if (applauseTestCaseId !== undefined) { + this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) failed`); const caps = browser.capabilities as WebdriverIO.Capabilities; this.inflightCalls.push( this.publciApi.submitResult(Number(applauseTestCaseId), { @@ -139,6 +311,7 @@ export class ApplausePlatformWdioReporter extends WDIOReporter { test.fullTitle ).applauseTestCaseId; if (applauseTestCaseId !== undefined) { + this.logger.info(`Test ${test.fullTitle}(${applauseTestCaseId}) skipped`); const caps = browser.capabilities as WebdriverIO.Capabilities; this.inflightCalls.push( this.publciApi.submitResult(Number(applauseTestCaseId), { @@ -167,5 +340,3 @@ export class ApplausePlatformWdioReporter extends WDIOReporter { return this.publciApi.getCallsInFlight === 0; } } - -export { ApplauseConfig }; diff --git a/tsconfig.json b/tsconfig.json index 252e790..462b937 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,7 +27,8 @@ "noUnusedParameters": true, "emitDeclarationOnly": true, "allowImportingTsExtensions": true, - "pretty": true + "pretty": true, + "types": ["node", "@wdio/types", "@wdio/globals/types"], }, "include": [ "@types/**/*", diff --git a/yarn.lock b/yarn.lock index efb24a3..51a3712 100644 --- a/yarn.lock +++ b/yarn.lock @@ -270,6 +270,11 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@colors/colors@1.6.0", "@colors/colors@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -277,6 +282,15 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -627,27 +641,14 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== -"@promptbook/utils@0.58.0": - version "0.58.0" - resolved "https://registry.yarnpkg.com/@promptbook/utils/-/utils-0.58.0.tgz#f85439d56e5c0593b81a1003c9dd0769f89ba76f" - integrity sha512-TglWndmjikWN+OGg9eNOUaMTM7RHr8uFCtgxfWULT1BUjcohywdijf54vS1U4mZ1tBLdHD4/fIrIHtmHzPUIZQ== - dependencies: - spacetrim "0.11.36" - -"@puppeteer/browsers@1.4.6": - version "1.4.6" - resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.4.6.tgz#1f70fd23d5d2ccce9d29b038e5039d7a1049ca77" - integrity sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ== +"@promptbook/utils@0.61.0": + version "0.61.0" + resolved "https://registry.yarnpkg.com/@promptbook/utils/-/utils-0.61.0.tgz#c9bab37d4eebd4e7d940cec69c515f02d52e7775" + integrity sha512-UIc4bQ+9DKwlrRUA7aRhQpo0vzrggTiv70Roy+lEdWam3SwYOcGyCgIk9IAqYEcfeBDsMHgDmBN4NDT97QiBdQ== dependencies: - debug "4.3.4" - extract-zip "2.0.1" - progress "2.0.3" - proxy-agent "6.3.0" - tar-fs "3.0.4" - unbzip2-stream "1.4.3" - yargs "17.7.1" + spacetrim "0.11.37" -"@puppeteer/browsers@^1.6.0": +"@puppeteer/browsers@1.9.1", "@puppeteer/browsers@^1.6.0": version "1.9.1" resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.9.1.tgz#384ee8b09786f0e8f62b1925e4c492424cb549ee" integrity sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA== @@ -885,6 +886,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + "@types/which@^2.0.1": version "2.0.2" resolved "https://registry.yarnpkg.com/@types/which/-/which-2.0.2.tgz#54541d02d6b1daee5ec01ac0d1b37cecf37db1ae" @@ -903,9 +909,9 @@ integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^17.0.8": - version "17.0.32" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" - integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== dependencies: "@types/yargs-parser" "*" @@ -1055,20 +1061,37 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@wdio/config@8.39.0": - version "8.39.0" - resolved "https://registry.yarnpkg.com/@wdio/config/-/config-8.39.0.tgz#3bda79e2f39d66079deb9813147234493468c790" - integrity sha512-yNuGPMPibY91s936gnJCHWlStvIyDrwLwGfLC/NCdTin4F7HL4Gp5iJnHWkJFty1/DfFi8jjoIUBNLM8HEez+A== +"@vitest/snapshot@^1.2.2": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.6.0.tgz#deb7e4498a5299c1198136f56e6e0f692e6af470" + integrity sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ== + dependencies: + magic-string "^0.30.5" + pathe "^1.1.1" + pretty-format "^29.7.0" + +"@wdio/config@8.40.2": + version "8.40.2" + resolved "https://registry.yarnpkg.com/@wdio/config/-/config-8.40.2.tgz#f521a8fb41a7be8dc4b4be107b89e5a076f03fce" + integrity sha512-RED2vcdX5Zdd6r+K+aWcjK4douxjJY4LP/8YvvavgqM0TURd5PDI0Y7IEz7+BIJOT4Uh+3atZawIN9/3yWFeag== dependencies: "@wdio/logger" "8.38.0" "@wdio/types" "8.39.0" - "@wdio/utils" "8.39.0" + "@wdio/utils" "8.40.2" decamelize "^6.0.0" deepmerge-ts "^5.0.0" glob "^10.2.2" import-meta-resolve "^4.0.0" -"@wdio/logger@8.38.0", "@wdio/logger@^8.28.0": +"@wdio/globals@^8.29.3", "@wdio/globals@^8.39.1": + version "8.40.2" + resolved "https://registry.yarnpkg.com/@wdio/globals/-/globals-8.40.2.tgz#9f5d066c106d33444cda4b32e42c541e4b07435f" + integrity sha512-eF47oRE79JY2Cgl0/OCpCLdEAh4eNgU11e4O8fvkPrwbPgW6gcS8xG23ZmNGc3EjhHUZUOzrm7uJ8ymcRPIuoA== + optionalDependencies: + expect-webdriverio "^4.11.2" + webdriverio "8.40.2" + +"@wdio/logger@8.38.0", "@wdio/logger@^8.28.0", "@wdio/logger@^8.38.0": version "8.38.0" resolved "https://registry.yarnpkg.com/@wdio/logger/-/logger-8.38.0.tgz#a96406267e800bef9c58ac95de00f42ab0d3ac5c" integrity sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q== @@ -1101,17 +1124,17 @@ diff "^5.0.0" object-inspect "^1.12.0" -"@wdio/types@8.39.0": +"@wdio/types@8.39.0", "@wdio/types@^8.39.0": version "8.39.0" resolved "https://registry.yarnpkg.com/@wdio/types/-/types-8.39.0.tgz#21032c638ded2dfb72b87114a8086e6777b43aae" integrity sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q== dependencies: "@types/node" "^20.1.0" -"@wdio/utils@8.39.0": - version "8.39.0" - resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-8.39.0.tgz#527f9d3c168672abf8711f510321b8633c834f6b" - integrity sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q== +"@wdio/utils@8.40.2": + version "8.40.2" + resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-8.40.2.tgz#1860cf906739b02f34dad1f2ed31d609850a3762" + integrity sha512-leYcCUSaAdLUCVKqRKNgMCASPOUo/VvOTKETiZ/qpdY2azCBt/KnLugtiycCzakeYg6Kp+VIjx5fkm0M7y4qhA== dependencies: "@puppeteer/browsers" "^1.6.0" "@wdio/logger" "8.38.0" @@ -1127,7 +1150,7 @@ split2 "^4.2.0" wait-port "^1.0.4" -"@zip.js/zip.js@^2.7.44": +"@zip.js/zip.js@^2.7.44", "@zip.js/zip.js@^2.7.48": version "2.7.48" resolved "https://registry.yarnpkg.com/@zip.js/zip.js/-/zip.js-2.7.48.tgz#34e7c0ccb3f644d7aaf3c3f47eb1f39e477f694f" integrity sha512-J7cliimZ2snAbr0IhLx2U8BwfA1pKucahKzTpFtYq4hEgKxwvFJcIjCIVNPwQpfVab7iVP+AKmoH1gidBlyhiQ== @@ -1213,12 +1236,15 @@ anymatch@^3.0.3: picomatch "^2.0.4" "applause-reporter-common@github:ApplauseOSS/applause-reporter-common#dev": - version "0.0.1" - resolved "https://codeload.github.com/ApplauseOSS/applause-reporter-common/tar.gz/007baba5d5a9bb7b17ad1796843b3ff5e08ed95b" + version "1.1.0" + resolved "https://codeload.github.com/ApplauseOSS/applause-reporter-common/tar.gz/51a4cd69f58d763f0aa9969814ec9efb05405f04" dependencies: axios "^1.6.0" + logform "^2.6.0" mailparser "^3.6.5" validator "^13.11.0" + winston "^3.13.0" + winston-transport "^4.7.0" yarn "^1.22.19" archiver-utils@^5.0.0, archiver-utils@^5.0.2: @@ -1531,9 +1557,9 @@ camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001646: - version "1.0.30001646" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001646.tgz#d472f2882259ba032dd73ee069ff01bfd059b25d" - integrity sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw== + version "1.0.30001651" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138" + integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== chalk@^2.4.2: version "2.4.2" @@ -1562,12 +1588,13 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -chromium-bidi@0.4.16: - version "0.4.16" - resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.16.tgz#8a67bfdf6bb8804efc22765a82859d20724b46ab" - integrity sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA== +chromium-bidi@0.5.8: + version "0.5.8" + resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.5.8.tgz#5053038425c062ed34b9bc973e84e79de0a5cef0" + integrity sha512-blqh+1cEQbHBKmok3rVJkBlBxt9beKBgOsxbFgs7UJcoVbbeZ+K7+6liAsjgpc8l1Xd55cQUy14fXZdGSb4zIw== dependencies: - mitt "3.0.0" + mitt "3.0.1" + urlpattern-polyfill "10.0.0" ci-info@^3.2.0: version "3.9.0" @@ -1598,7 +1625,7 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -1617,11 +1644,35 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -1807,15 +1858,15 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -devtools-protocol@0.0.1147663: - version "0.0.1147663" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz#4ec5610b39a6250d1f87e6b9c7e16688ed0ac78e" - integrity sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ== +devtools-protocol@0.0.1232444: + version "0.0.1232444" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1232444.tgz#406345a90a871ba852c530d73482275234936eed" + integrity sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg== -devtools-protocol@^0.0.1302984: - version "0.0.1302984" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1302984.tgz#4d8614264105394bfc39dd268121bd549a877f1a" - integrity sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA== +devtools-protocol@^0.0.1335233: + version "0.0.1335233" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1335233.tgz#c11836b65f7ec9f2e84e82f51d313362de0953c2" + integrity sha512-bNTJw/m+v0JvQEsaI0l+i6mETHHf7VwZbQzT5GNSveGuYjip8uyjeF/qg84bsIPU+lFypnZr10a+cbcee6I8pg== diff-sequences@^29.6.3: version "29.6.3" @@ -1885,14 +1936,15 @@ edge-paths@^3.0.5: which "^2.0.2" edgedriver@^5.5.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/edgedriver/-/edgedriver-5.6.0.tgz#fea8d7ac9b328753fc250aceaeb6d1fbcf33fb87" - integrity sha512-IeJXEczG+DNYBIa9gFgVYTqrawlxmc9SUqUsWU2E98jOsO/amA7wzabKOS8Bwgr/3xWoyXCJ6yGFrbFKrilyyQ== + version "5.6.1" + resolved "https://registry.yarnpkg.com/edgedriver/-/edgedriver-5.6.1.tgz#36971f000aee8756c11f3fb1dc5273f109e860d5" + integrity sha512-3Ve9cd5ziLByUdigw6zovVeWJjVs8QHVmqOB0sJ0WNeVPcwf4p18GnxMmVvlFmYRloUwf5suNuorea4QzwBIOA== dependencies: - "@wdio/logger" "^8.28.0" - "@zip.js/zip.js" "^2.7.44" + "@wdio/logger" "^8.38.0" + "@zip.js/zip.js" "^2.7.48" decamelize "^6.0.0" edge-paths "^3.0.5" + fast-xml-parser "^4.4.1" node-fetch "^3.3.2" which "^4.0.0" @@ -1904,9 +1956,9 @@ ejs@^3.1.10: jake "^10.8.5" electron-to-chromium@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz#cd477c830dd6fca41fbd5465c1ff6ce08ac22343" - integrity sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA== + version "1.5.5" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz#03bfdf422bdd2c05ee2657efedde21264a1a566b" + integrity sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA== emittery@^0.13.1: version "0.13.1" @@ -1918,6 +1970,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + encoding-japanese@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/encoding-japanese/-/encoding-japanese-2.0.0.tgz#fa0226e5469e7b5b69a04fea7d5481bd1fa56936" @@ -2173,6 +2230,20 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== +expect-webdriverio@^4.11.2: + version "4.15.1" + resolved "https://registry.yarnpkg.com/expect-webdriverio/-/expect-webdriverio-4.15.1.tgz#3fa8e7ea2dc2b0548aeeda4daae55f2fdd3505c8" + integrity sha512-xtBSidt7Whs1fsUC+utxVzfmkmaStXWW17b+BcMCiCltx0Yku6l7BTv1Y14DEKX8L6rttaDQobYyRtBKbi4ssg== + dependencies: + "@vitest/snapshot" "^1.2.2" + expect "^29.7.0" + jest-matcher-utils "^29.7.0" + lodash.isequal "^4.5.0" + optionalDependencies: + "@wdio/globals" "^8.29.3" + "@wdio/logger" "^8.28.0" + webdriverio "^8.29.3" + expect@^29.0.0, expect@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" @@ -2236,6 +2307,13 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-xml-parser@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz#86dbf3f18edf8739326447bcaac31b4ae7f6514f" + integrity sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw== + dependencies: + strnum "^1.0.5" + fastq@^1.6.0: version "1.17.1" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" @@ -2257,6 +2335,11 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + fetch-blob@^3.1.2, fetch-blob@^3.1.4: version "3.2.0" resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" @@ -2316,15 +2399,20 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + follow-redirects@^1.15.6: version "1.15.6" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== foreground-child@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7" - integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA== + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" @@ -2593,7 +2681,7 @@ http2-wrapper@^2.1.10: quick-lru "^5.1.1" resolve-alpn "^1.2.0" -https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.2, https-proxy-agent@^7.0.4, https-proxy-agent@^7.0.5: +https-proxy-agent@^7.0.2, https-proxy-agent@^7.0.4, https-proxy-agent@^7.0.5: version "7.0.5" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== @@ -2662,7 +2750,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@~2.0.3: +inherits@2, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2680,6 +2768,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-builtin-module@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" @@ -3272,6 +3365,11 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + ky@^0.33.0: version "0.33.3" resolved "https://registry.yarnpkg.com/ky/-/ky-0.33.3.tgz#bf1ad322a3f2c3428c13cfa4b3af95e6c4a2f543" @@ -3362,11 +3460,11 @@ linkify-it@5.0.0: uc.micro "^2.0.0" locate-app@^2.1.0: - version "2.4.21" - resolved "https://registry.yarnpkg.com/locate-app/-/locate-app-2.4.21.tgz#e719c19067f6400ea79a9d53965a5acb7ea67471" - integrity sha512-ySSBwlUnVKoLgw39q8YaNtvklhaTMoVqBf2+CuY3hkOFuWubHAJ6NJuTjv+jfTV1FuOgKsigRdsYUIeVgKHvNA== + version "2.4.23" + resolved "https://registry.yarnpkg.com/locate-app/-/locate-app-2.4.23.tgz#938852444f469a2737063aab74c25c11e8f71991" + integrity sha512-TdpE0qwBUQfO0jIDu96U+SuQkqXpInQIHYXSHWPGXNncjBur9izuPj7xPoAlTApxvPVVqcBcxoqpYSYEfhjPKA== dependencies: - "@promptbook/utils" "0.58.0" + "@promptbook/utils" "0.61.0" type-fest "2.13.0" userhome "1.0.0" @@ -3389,6 +3487,11 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + lodash.memoize@4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -3409,6 +3512,18 @@ lodash@^4.17.15: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +logform@^2.6.0, logform@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.1.tgz#71403a7d8cae04b2b734147963236205db9b3df0" + integrity sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + loglevel-plugin-prefix@^0.8.4: version "0.8.4" resolved "https://registry.yarnpkg.com/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz#2fe0e05f1a820317d98d8c123e634c1bd84ff644" @@ -3441,7 +3556,7 @@ lru-cache@^7.14.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -magic-string@^0.30.10: +magic-string@^0.30.10, magic-string@^0.30.5: version "0.30.11" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.11.tgz#301a6f93b3e8c2cb13ac1a7a673492c0dfd12954" integrity sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A== @@ -3570,10 +3685,10 @@ minimatch@^9.0.0, minimatch@^9.0.4: resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== -mitt@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd" - integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ== +mitt@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" + integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== mkdirp-classic@^0.5.2: version "0.5.3" @@ -3585,6 +3700,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -3660,6 +3780,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -3717,7 +3844,7 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pac-proxy-agent@^7.0.0, pac-proxy-agent@^7.0.1: +pac-proxy-agent@^7.0.1: version "7.0.2" resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz#0fb02496bd9fb8ae7eb11cfd98386daaac442f58" integrity sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg== @@ -3807,6 +3934,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pathe@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" + integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== + peberminta@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/peberminta/-/peberminta-0.9.0.tgz#8ec9bc0eb84b7d368126e71ce9033501dca2a352" @@ -3888,20 +4020,6 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -proxy-agent@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.0.tgz#72f7bb20eb06049db79f7f86c49342c34f9ba08d" - integrity sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og== - dependencies: - agent-base "^7.0.2" - debug "^4.3.4" - http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.0" - lru-cache "^7.14.1" - pac-proxy-agent "^7.0.0" - proxy-from-env "^1.1.0" - socks-proxy-agent "^8.0.1" - proxy-agent@6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.1.tgz#40e7b230552cf44fd23ffaf7c59024b692612687" @@ -3939,17 +4057,17 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -puppeteer-core@^20.9.0: - version "20.9.0" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-20.9.0.tgz#6f4b420001b64419deab38d398a4d9cd071040e6" - integrity sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg== +puppeteer-core@^21.11.0: + version "21.11.0" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.11.0.tgz#6c60ec350f1a3a2152179c68166da6edfce18a23" + integrity sha512-ArbnyA3U5SGHokEvkfWjW+O8hOxV1RSJxOgriX/3A4xZRqixt9ZFHD0yPgZQF05Qj0oAqi8H/7stDorjoHY90Q== dependencies: - "@puppeteer/browsers" "1.4.6" - chromium-bidi "0.4.16" + "@puppeteer/browsers" "1.9.1" + chromium-bidi "0.5.8" cross-fetch "4.0.0" debug "4.3.4" - devtools-protocol "0.0.1147663" - ws "8.13.0" + devtools-protocol "0.0.1232444" + ws "8.16.0" pure-rand@^6.0.0: version "6.1.0" @@ -4001,6 +4119,15 @@ readable-stream@^2.0.5, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.4.0, readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@^4.0.0: version "4.5.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" @@ -4134,6 +4261,11 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-stable-stringify@^2.3.1: + version "2.4.3" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -4197,6 +4329,13 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -4217,7 +4356,7 @@ smob@^1.0.0: resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig== -socks-proxy-agent@^8.0.1, socks-proxy-agent@^8.0.2, socks-proxy-agent@^8.0.4: +socks-proxy-agent@^8.0.2, socks-proxy-agent@^8.0.4: version "8.0.4" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz#9071dca17af95f483300316f4b063578fa0db08c" integrity sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw== @@ -4255,10 +4394,10 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -spacetrim@0.11.36: - version "0.11.36" - resolved "https://registry.yarnpkg.com/spacetrim/-/spacetrim-0.11.36.tgz#798ac5cdf15fcd38a446e89fc28f95518c9fbb30" - integrity sha512-jqv5aAfMLkBnFK+38QUtEGgU7x1KrfpDnCdjX4+W1IEVgA8Kf3tk8K9je8j2nkCSXdIngjda53fuXERr4/61kw== +spacetrim@0.11.37: + version "0.11.37" + resolved "https://registry.yarnpkg.com/spacetrim/-/spacetrim-0.11.37.tgz#9a7e8918fdb645e8b72db16ae3deb51e3b876d7f" + integrity sha512-OmoOQm5m8TXqmyPWVJpqwDiksWP3W9l8cXPPeCHz3GnkzhqNFt1KT6YykaBPt39oSvvSr2/YxnyoQ1MTarM7qA== split2@^4.2.0: version "4.2.0" @@ -4275,6 +4414,11 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -4319,7 +4463,7 @@ string-width@4.2.2, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2. is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string_decoder@^1.3.0: +string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -4355,6 +4499,11 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -4419,9 +4568,9 @@ tar-stream@^3.0.0, tar-stream@^3.1.5: streamx "^2.15.0" terser@^5.17.4: - version "5.31.3" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.3.tgz#b24b7beb46062f4653f049eea4f0cd165d0f0c38" - integrity sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA== + version "5.31.5" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.5.tgz#e48b7c65f32d2808e7dad803e4586a0bc3829b87" + integrity sha512-YPmas0L0rE1UyLL/llTWA0SiDOqIcAQYLeUj7cJYzXHlRTAnMSg9pPe4VJ5PlKvTrPQsdVFuiRiwyeNlYgwh2Q== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -4444,6 +4593,11 @@ text-decoder@^1.1.0: dependencies: b4a "^1.6.4" +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -4481,6 +4635,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + ts-api-utils@^1.0.1: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" @@ -4617,12 +4776,17 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +urlpattern-polyfill@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz#f0a03a97bfb03cdf33553e5e79a2aadd22cac8ec" + integrity sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg== + userhome@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/userhome/-/userhome-1.0.0.tgz#b6491ff12d21a5e72671df9ccc8717e1c6688c0b" integrity sha512-ayFKY3H+Pwfy4W98yPdtH1VqH4psDeyW8lYYFzfecR9d6hqLpqhecktvYR3SEEXt7vG0S1JEpciI3g94pMErig== -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -4667,40 +4831,40 @@ web-streams-polyfill@^3.0.3: resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== -webdriver@8.39.0: - version "8.39.0" - resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-8.39.0.tgz#ccb5362e53593e23f16a3951d70b7b32a1073fd1" - integrity sha512-Kc3+SfiH4ufyrIht683VT2vnJocx0pfH8rYdyPvEh1b2OYewtFTHK36k9rBDHZiBmk6jcSXs4M2xeFgOuon9Lg== +webdriver@8.40.2: + version "8.40.2" + resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-8.40.2.tgz#f578a482cd249dd21328cab09a31a6e78894a255" + integrity sha512-GoRR94m3yL8tWC9Myf+xIBSdVK8fi1ilZgEZZaYT8+XIWewR02dvrC6rml+/2ZjXUQzeee0RFGDwk9IC7cyYrg== dependencies: "@types/node" "^20.1.0" "@types/ws" "^8.5.3" - "@wdio/config" "8.39.0" + "@wdio/config" "8.40.2" "@wdio/logger" "8.38.0" "@wdio/protocols" "8.38.0" "@wdio/types" "8.39.0" - "@wdio/utils" "8.39.0" + "@wdio/utils" "8.40.2" deepmerge-ts "^5.1.0" got "^12.6.1" ky "^0.33.0" ws "^8.8.0" -webdriverio@^8.16.6: - version "8.39.1" - resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-8.39.1.tgz#605af5a79a7805bd08a36d16d078e618360f8aa9" - integrity sha512-dPwLgLNtP+l4vnybz+YFxxH8nBKOP7j6VVzKtfDyTLDQg9rz3U8OA4xMMQCBucnrVXy3KcKxGqlnMa+c4IfWCQ== +webdriverio@8.40.2, webdriverio@^8.16.6, webdriverio@^8.29.3: + version "8.40.2" + resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-8.40.2.tgz#f6d163365952c4ca6b6fb5cdbfbd75dc1e2700eb" + integrity sha512-6yuzUlE064qNuMy98Du1+8QHbXk0st8qTWF7MDZRgYK19FGoy+KhQbaUv1wlFJuFHM0PiAYuduTURL4ub6HvzQ== dependencies: "@types/node" "^20.1.0" - "@wdio/config" "8.39.0" + "@wdio/config" "8.40.2" "@wdio/logger" "8.38.0" "@wdio/protocols" "8.38.0" "@wdio/repl" "8.24.12" "@wdio/types" "8.39.0" - "@wdio/utils" "8.39.0" + "@wdio/utils" "8.40.2" archiver "^7.0.0" aria-query "^5.0.0" css-shorthand-properties "^1.1.1" css-value "^0.0.1" - devtools-protocol "^0.0.1302984" + devtools-protocol "^0.0.1335233" grapheme-splitter "^1.0.2" import-meta-resolve "^4.0.0" is-plain-obj "^4.1.0" @@ -4708,12 +4872,12 @@ webdriverio@^8.16.6: lodash.clonedeep "^4.5.0" lodash.zip "^4.2.0" minimatch "^9.0.0" - puppeteer-core "^20.9.0" + puppeteer-core "^21.11.0" query-selector-shadow-dom "^1.0.0" resq "^1.9.1" rgb2hex "0.2.5" serialize-error "^11.0.1" - webdriver "8.39.0" + webdriver "8.40.2" webidl-conversions@^3.0.0: version "3.0.1" @@ -4742,6 +4906,32 @@ which@^4.0.0: dependencies: isexe "^3.1.1" +winston-transport@^4.7.0: + version "4.7.1" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.1.tgz#52ff1bcfe452ad89991a0aaff9c3b18e7f392569" + integrity sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA== + dependencies: + logform "^2.6.1" + readable-stream "^3.6.2" + triple-beam "^1.3.0" + +winston@^3.13.0, winston@^3.13.1: + version "3.14.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.14.0.tgz#589e5dd6b458ae4ef0a4dd0190a6c077488f1cee" + integrity sha512-XEJvmKJglhTW2TgfpKdkpj0119Yn5AClR7LJ0rBNUQFx20mNQj3s1ukTA1i77q+YBaHYbcKtXpxgPqfdUPCIYA== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.6.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.7.0" + word-wrap@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" @@ -4769,10 +4959,10 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@8.13.0: - version "8.13.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" - integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== +ws@8.16.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== ws@^8.8.0: version "8.18.0" @@ -4794,19 +4984,6 @@ yargs-parser@^21.0.1, yargs-parser@^21.1.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@17.7.1: - version "17.7.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" - integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - yargs@17.7.2, yargs@^17.3.1: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"