From f191aa8d0f81ffabc75c4c9eb205966d3d76d79d Mon Sep 17 00:00:00 2001 From: Alex Neo Date: Tue, 17 Sep 2024 10:46:40 +0300 Subject: [PATCH 1/5] (feat): define own tags matcher --- .gitignore | 1 + README.md | 43 ++++ package.json | 3 +- src/playwright-azure-reporter.ts | 41 +++- tests/reporter/playwright.config.ts | 5 + tests/reporter/reporter-constructor.spec.ts | 241 +++++++++++++++++++- yarn.lock | 188 +++++++++++---- 7 files changed, 470 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index 1583118..18adbd1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ dist yarn-error.log .vscode .taskkey +.env diff --git a/README.md b/README.md index 198da92..58d90fc 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ const config: PlaywrightTestConfig = { publishTestResultsMode: 'testRun', uploadAttachments: true, attachmentsType: ['screenshot', 'video', 'trace'], + tagsMatcher: /@\[(\d+)\]/, testRunConfig: { owner: { displayName: 'Alex Neo', @@ -210,6 +211,48 @@ Reporter options (\* - required): > **Note:** If you use `isExistingTestRun` mode, test run doesn't complete automatically. You should complete it manually. +- `tagsMatcher` [string|RegExp|string[]|RegExp[]] - A string or a regular expression to match the name of the test case to extract the test case id. Default: `/\[([\d,\s]+)\]/` + + #### Example Test Titles + + - Test title: `Test case @tag1=123` + + - `tagsMatcher: /@tag1=(\d+)/` + - Extracted tags: `['123']` + + - Test title: `Test case @TestCase=123 [@TestCase=456]` + + - `tagsMatcher: /@TestCase=(\d+)/` + - Extracted tags: `['123', '456']` + + - Test title: `Test case test123 TEST456` + - `tagsMatcher: [/[a-z]+(\d+)/, /[A-Z]+(\d+)/]` + - Extracted tags: `['123', '456']` + - Test title: `Test case @tag1=123 @tag2=456` + - `tagsMatcher: ['@tag1=(\\d+)', '@tag2=(\\d+)']` + - Extracted tags: `['123', '456']` + + #### Error Handling + + If an invalid `tagsMatcher` is provided, an error will be thrown. For example: + + ```typescript + reporter: [ + ['list'], + [ + '@alex_neo/playwright-azure-reporter', + { + orgUrl: 'http://localhost:4000', + projectName: 'SampleProject', + planId: 4, + token: 'your-token', + isDisabled: false, + tagsMatcher: 1234, // Invalid pattern + } + ], + // This will throw an error: "Invalid tagsMatcher. Must be a string or RegExp. Actual: 1234" + ``` + ## Usefulness - **AZURE_PW_TEST_RUN_ID** - Id of current test run. It will be set in environment variables after test run created. Can be accessed by `process.env.AZURE_PW_TEST_RUN_ID`. Pay attention what `publishTestResultsMode` configuration you use. If you use `testResult` mode - this variable will be set when test run created, at the start of tests execution, if you use `testRun` mode - this variable will be set when test run completed, at the end of tests execution. diff --git a/package.json b/package.json index 93c8764..a9936b9 100644 --- a/package.json +++ b/package.json @@ -38,10 +38,11 @@ }, "license": "ISC", "dependencies": { - "azure-devops-node-api": "^12.0.0", + "azure-devops-node-api": "^14.0.2", "azure-pipelines-task-lib": "^4.15.0", "chalk": "4.1.2", "debug": "^4.3.4", + "dotenv": "^16.4.5", "mime": "^3.0.0" }, "devDependencies": { diff --git a/src/playwright-azure-reporter.ts b/src/playwright-azure-reporter.ts index 59e9a2a..0f13dbb 100644 --- a/src/playwright-azure-reporter.ts +++ b/src/playwright-azure-reporter.ts @@ -12,6 +12,7 @@ import * as Test from 'azure-devops-node-api/TestApi'; import { setVariable } from 'azure-pipelines-task-lib'; import chalk from 'chalk'; import { existsSync, readFileSync } from 'fs'; +import { isRegExp } from 'util/types'; import Logger from './logger'; import { createGuid, getExtensionFromContentType, getExtensionFromFilename, shortID } from './utils'; @@ -55,6 +56,7 @@ export interface AzureReporterOptions { testPointMapper?: (testCase: TestCase, testPoints: TestPoint[]) => Promise; isExistingTestRun?: boolean; testRunId?: number; + tagsMatcher?: string | RegExp | Array; } interface TestResultsToTestRun { @@ -142,6 +144,7 @@ class AzureDevOpsReporter implements Reporter { private _publishTestResultsMode: TPublishTestResults = 'testResult'; private _testRunId: number | undefined; private _isExistingTestRun = false; + private _tagsMatcher: string | RegExp | Array = new RegExp(/\[([\d,\s]+)\]/, 'g'); public constructor(options: AzureReporterOptions) { this._runIdPromise = new Promise((resolve, reject) => { @@ -259,6 +262,7 @@ class AzureDevOpsReporter implements Reporter { this._testPointMapper = options.testPointMapper; } this._isExistingTestRun = options.isExistingTestRun || false; + this._tagsMatcher = options.tagsMatcher || new RegExp(/\[([\d,\s]+)\]/, 'g'); } async onBegin(): Promise { @@ -396,10 +400,9 @@ class AzureDevOpsReporter implements Reporter { } private _anonymizeObject(obj: any, keys: string[]): any { - if (typeof obj !== 'object') return obj; - if (Array.isArray(obj)) { - return obj.map((item) => this._anonymizeObject(item, keys)); - } + if (typeof obj !== 'object' || obj === null) return obj; + if (Array.isArray(obj)) return obj.map((item) => this._anonymizeObject(item, keys)); + if (isRegExp(obj)) return obj.toString(); const result: any = {}; for (const key in obj) { if (keys.includes(key)) { @@ -412,14 +415,37 @@ class AzureDevOpsReporter implements Reporter { } private _extractMatches(text: string): string[] { - const regex = new RegExp(/\[([\d,\s]+)\]/, 'gm'); - const matchesAll = text.matchAll(regex); - return [...matchesAll].map((match) => match[1]); + const reList = (Array.isArray(this._tagsMatcher) ? this._tagsMatcher : [this._tagsMatcher]).map((re) => { + if (typeof re === 'string') { + return new RegExp(re, 'g'); + } else if (!isRegExp(re)) { + throw new Error(`Invalid tagsMatcher. Must be a string or RegExp. Actual: ${re}`); + } + return re; + }); + + this._logger?.debug(`Extracting matches from text: ${text}`); + this._logger?.debug(`Using matchers: ${reList}`); + + const matchesResult: string[] = []; + for (const re of reList) { + this._logger?.debug(`Using matcher: ${re}`); + const matchesAll = text.matchAll(new RegExp(re, 'g')); + for (const match of matchesAll) { + this._logger?.debug(`[_extractMatches] Whole matches found: ${match}`); + if (match && match[1]) { + this._logger?.debug(`[_extractMatches] Matches found: ${match[1]}`); + matchesResult.push(match[1]); + } + } + } + return matchesResult; } private _getCaseIds(test: TestCase): string[] { const result: string[] = []; const matches = this._extractMatches(test.title); + this._logger?.debug(`[_getCaseIds] Matches found: ${matches}`); matches.forEach((match) => { const ids = match.split(',').map((id) => id.trim()); result.push(...ids); @@ -427,6 +453,7 @@ class AzureDevOpsReporter implements Reporter { if (test.tags) { test.tags.forEach((tag) => { const ids = this._extractMatches(tag); + this._logger?.debug(`[_getCaseIds] Matches found in tag: ${ids}`); ids.forEach((id) => { result.push(id); }); diff --git a/tests/reporter/playwright.config.ts b/tests/reporter/playwright.config.ts index c8bd891..b200ec3 100644 --- a/tests/reporter/playwright.config.ts +++ b/tests/reporter/playwright.config.ts @@ -1,4 +1,9 @@ import { defineConfig } from '@playwright/test'; +import dotenv from 'dotenv'; + +dotenv.config({ + path: require.resolve('../../.env'), +}); export default defineConfig({ testDir: __dirname, diff --git a/tests/reporter/reporter-constructor.spec.ts b/tests/reporter/reporter-constructor.spec.ts index 439a1ab..419a5ef 100644 --- a/tests/reporter/reporter-constructor.spec.ts +++ b/tests/reporter/reporter-constructor.spec.ts @@ -1,6 +1,8 @@ import path from 'path'; +import { isRegExp } from 'util/types'; -import { setHeaders } from '../config/utils'; +import AzureDevOpsReporter from '../../dist/playwright-azure-reporter'; +import { getRequestBody, setHeaders } from '../config/utils'; import azureAreas from './assets/azure-reporter/azureAreas'; import headers from './assets/azure-reporter/azureHeaders'; import location from './assets/azure-reporter/azureLocationOptionsResponse.json'; @@ -36,6 +38,44 @@ const CREATE_RUN_INVALID_RESPONSE_PATH = path.join( 'createRunInvalidResponse.json' ); +const CREATE_RUN_VALID_RESPONSE_PATH = path.join( + __dirname, + '.', + 'assets', + 'azure-reporter', + 'createRunValidResponse.json' +); +const POINTS_3_VALID_RESPONSE_PATH = path.join(__dirname, '.', 'assets', 'azure-reporter', 'points3Response.json'); +const POINTS_7_VALID_RESPONSE_PATH = path.join(__dirname, '.', 'assets', 'azure-reporter', 'points7Response.json'); +const COMPLETE_RUN_VALID_RESPONSE_PATH = path.join( + __dirname, + '.', + 'assets', + 'azure-reporter', + 'completeRunValidResponse.json' +); +const TEST_RUN_RESULTS_3_VALID_RESPONSE_PATH = path.join( + __dirname, + '.', + 'assets', + 'azure-reporter', + 'testRunResults3ValidResponse.json' +); +const TEST_RUN_RESULTS_7_VALID_RESPONSE_PATH = path.join( + __dirname, + '.', + 'assets', + 'azure-reporter', + 'testRunResults7ValidResponse.json' +); +const RUN_RESULTS_ATTACHMENTS_VALID_RESPONSE_PATH = path.join( + __dirname, + '.', + 'assets', + 'azure-reporter', + 'runResultsAttachmentsResponse.json' +); + test.describe('Reporter constructor', () => { test("'orgUrl' in config expected", async ({ runInlineTest }) => { const result = await runInlineTest( @@ -337,3 +377,202 @@ test.describe('Reporter constructor', () => { expect(result.passed).toBe(1); }); }); + +let tagsMatchers: { + tagsMatcher?: RegExp | RegExp[] | string | string[] | undefined; + testTitle: string; + tagsSection?: string; + expected: string[]; +}[] = [ + { + tagsMatcher: /@tag1=(\d+)/, + testTitle: 'Test case @tag1=123', + tagsSection: "['@tag1=7']", + expected: ['123'], + }, + { + tagsMatcher: /@TestCase=(\d+)/, + testTitle: 'Test case @TestCase=123 [@TestCase=456]', + tagsSection: "['@TestCase=7', '@TestCase=7']", + expected: ['123', '456'], + }, + { + tagsMatcher: [/[a-z]+(\d+)/, /[A-Z]+(\d+)/], + testTitle: 'Test case test123 TEST456', + tagsSection: "['@test7', '@TEST7']", + expected: ['123', '456'], + }, + { + tagsMatcher: ['@tag1=(\\d+)', '@tag2=(\\d+)'], + testTitle: 'Test case @tag1=123 @tag2=456', + tagsSection: "['@tag1=7', '@tag2=7']", + expected: ['123', '456'], + }, + { + tagsMatcher: undefined, + testTitle: 'Test case [12345]', + tagsSection: "['@[7]']", + expected: ['12345'], + }, +]; + +tagsMatchers.forEach((item) => { + test(`_extractMatches should return ${item.expected} for ${item.testTitle}`, () => { + const reporter = new AzureDevOpsReporter({ + orgUrl: 'http://localhost:4000', + projectName: 'SampleSample', + planId: 4, + token: 'token', + isDisabled: false, + tagsMatcher: item.tagsMatcher, + }); + + const matches = (reporter as any)._extractMatches(item.testTitle); + expect.soft(matches).toEqual(item.expected); + }); + + test(`match tags with own tags matcher for ${item.tagsSection}`, async ({ runInlineTest, server }) => { + server.setRoute('/_apis/Location', (_, res) => { + setHeaders(res, headers); + res.end(JSON.stringify(location)); + }); + + server.setRoute('/_apis/ResourceAreas', (_, res) => { + setHeaders(res, headers); + res.end(JSON.stringify(azureAreas(server.PORT))); + }); + + server.setRoute('/_apis/Test', (req, res) => { + setHeaders(res, headers); + server.serveFile(req, res, TEST_OPTIONS_RESPONSE_PATH); + }); + + server.setRoute('/_apis/core', (req, res) => { + setHeaders(res, headers); + server.serveFile(req, res, CORE_OPTIONS_RESPONSE_PATH); + }); + + server.setRoute('/_apis/projects/SampleSample', (req, res) => { + setHeaders(res, headers); + server.serveFile(req, res, PROJECT_INVALID_RESPONSE_PATH); + }); + + server.setRoute('/SampleSample/_apis/test/Runs', (req, res) => { + setHeaders(res, headers); + server.serveFile(req, res, CREATE_RUN_VALID_RESPONSE_PATH); + }); + + server.setRoute('/SampleSample/_apis/test/Points', async (req, res) => { + const body = await getRequestBody(req); + setHeaders(res, headers); + expect(body.pointsFilter?.testcaseIds[0]).toBeDefined(); + if (body.pointsFilter?.testcaseIds[0] === 3) server.serveFile(req, res, POINTS_3_VALID_RESPONSE_PATH); + else if (body.pointsFilter?.testcaseIds[0] === 7) server.serveFile(req, res, POINTS_7_VALID_RESPONSE_PATH); + }); + + server.setRoute('/SampleSample/_apis/test/Runs/150/Results', async (req, res) => { + const body = await getRequestBody(req); + setHeaders(res, headers); + expect(body[0].testPoint?.id).toBeDefined(); + if (body[0].testPoint?.id === '1') server.serveFile(req, res, TEST_RUN_RESULTS_3_VALID_RESPONSE_PATH); + else if (body[0].testPoint?.id === '2') server.serveFile(req, res, TEST_RUN_RESULTS_7_VALID_RESPONSE_PATH); + }); + + server.setRoute('/SampleSample/_apis/test/Runs/150/Results/100001/Attachments', async (req, res) => { + setHeaders(res, headers); + server.serveFile(req, res, RUN_RESULTS_ATTACHMENTS_VALID_RESPONSE_PATH); + }); + + server.setRoute('/SampleSample/_apis/test/Runs/150', (req, res) => { + setHeaders(res, headers); + server.serveFile(req, res, COMPLETE_RUN_VALID_RESPONSE_PATH); + }); + + const result = await runInlineTest( + { + 'playwright.config.ts': ` + module.exports = { + use: { + screenshot: 'only-on-failure', + trace: 'retain-on-failure', + video: 'retain-on-failure', + }, + reporter: [ + ['dot'], + ['${reporterPath}', { + orgUrl: 'http://localhost:${server.PORT}', + projectName: 'SampleSample', + planId: 4, + token: 'token', + uploadAttachments: true, + logging: true, + ${ + item.tagsMatcher + ? `tagsMatcher: ${ + Array.isArray(item.tagsMatcher) + ? `[${item.tagsMatcher + .map((tag) => `${isRegExp(tag) ? tag.toString() : `'${tag.replace(/\\/g, '\\\\')}'`}`) + .join(',')}]` + : `[${item.tagsMatcher}]` + }` + : '' + } + }] + ] + }; + `, + 'a.spec.js': ` + import { test, expect } from '@playwright/test'; + test('[7] with screenshot', ${ + item.tagsMatcher !== undefined ? `{ tag: ${item.tagsSection} }, ` : '' + } async ({ page }) => { + await page.goto('https://playwright.dev/') + await page.locator('text=Get started').click() + await expect(page).toHaveTitle(/Getting sttttarted/) + }); + `, + }, + { reporter: '' } + ); + + expect(result.output).not.toContain('Failed request: (401)'); + expect(result.output).toContain( + "'attachmentsType' is not set. Attachments Type will be set to 'screenshot' by default." + ); + expect(result.output).toMatch(/azure:pw:log Using run (\d.*) to publish test results/); + expect(result.output).toContain(`azure:pw:log [7] with screenshot - failed`); + expect(result.output).toContain('azure:pw:log Start publishing: [7] with screenshot'); + expect(result.output).toContain('azure:pw:log Uploading attachments for test: [7] with screenshot'); + expect(result.output).toContain('azure:pw:log Uploaded attachment'); + expect(result.output).toContain('azure:pw:log Result published: [7] with screenshot'); + expect(result.output).toMatch(/azure:pw:log Run (\d.*) - Completed/); + expect(result.exitCode).toBe(1); + expect(result.failed).toBe(1); + }); +}); + +tagsMatchers = [ + { + //@ts-ignore + tagsMatcher: [3432, 3944], + testTitle: 'Test case [12345]', + expected: ['12345'], + }, +]; + +tagsMatchers.forEach((tagsMatcher) => { + test(`Test should throw an error for invalid tagsMatcher: ${tagsMatcher.tagsMatcher}`, () => { + try { + new AzureDevOpsReporter({ + orgUrl: 'http://localhost:4000', + projectName: 'SampleSample', + planId: 4, + token: 'token', + isDisabled: false, + tagsMatcher: tagsMatcher.tagsMatcher, + }); + } catch (error) { + expect(error.message).toContain('Invalid tagsMatcher. Must be a string or RegExp. Actual: 3432'); + } + }); +}); diff --git a/yarn.lock b/yarn.lock index 91e5e39..95f7400 100644 --- a/yarn.lock +++ b/yarn.lock @@ -85,7 +85,7 @@ "@playwright/test@^1.44.1": version "1.45.3" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.45.3.tgz#22e9c38b3081d6674b28c6e22f784087776c72e5" + resolved "https://registry.npmjs.org/@playwright/test/-/test-1.45.3.tgz" integrity sha512-UKF4XsBfy+u3MFWEH44hva1Q8Da28G6RFtR2+5saw+jgAFQV5yYnB1fu68Mz7fO+5GJF3wgwAIs0UelU8TxFrA== dependencies: playwright "1.45.3" @@ -232,12 +232,12 @@ acorn@^8.8.0: adm-zip@^0.5.10: version "0.5.14" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.14.tgz#2c557c0bf12af4311cf6d32970f4060cf8133b2a" + resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.14.tgz" integrity sha512-DnyqqifT4Jrcvb8USYjp6FHtBpEIz1mnXu6pTRHZ0RL69LbQYiO+0lDFg5+OKA7U29oWSs3a/i8fhn8ZcceIWg== agent-base@6: version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" @@ -323,17 +323,17 @@ available-typed-arrays@^1.0.5: resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -azure-devops-node-api@^12.0.0: - version "12.0.0" - resolved "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.0.0.tgz" - integrity sha512-S6Il++7dQeMlZDokBDWw7YVoPeb90tWF10pYxnoauRMnkuL91jq9M7SOYRVhtO3FUC5URPkB/qzGa7jTLft0Xw== +azure-devops-node-api@^14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/azure-devops-node-api/-/azure-devops-node-api-14.0.2.tgz#8370a7e4af741b59a8f264ae1ccf28aaf8fb2e34" + integrity sha512-TwjAEnWnOSZ2oypkDyqppgvJw43qArEfPiJtEWLL3NBgdvAuOuB0xgFz/Eiz4H6Dk0Yv52wCodZxtZvAMhJXwQ== dependencies: tunnel "0.0.6" - typed-rest-client "^1.8.4" + typed-rest-client "^2.0.1" azure-pipelines-task-lib@^4.15.0: version "4.15.0" - resolved "https://registry.yarnpkg.com/azure-pipelines-task-lib/-/azure-pipelines-task-lib-4.15.0.tgz#f4f087226077bf78f421bd4c483fd9174883ee77" + resolved "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-4.15.0.tgz" integrity sha512-Y72FjLTE2CAM9KrBXzc6vjelTBCpdYb2NkyFB0hwksTrhA3q8nsF680dofuTeXztQ94UTpkK27hpgSHnqYf5ZA== dependencies: adm-zip "^0.5.10" @@ -386,6 +386,17 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" @@ -463,7 +474,7 @@ cycle@1.0.x: debug@4: version "4.3.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz" integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== dependencies: ms "2.1.2" @@ -487,6 +498,15 @@ deep-is@^0.1.3: resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + define-properties@^1.1.3, define-properties@^1.1.4: version "1.2.0" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz" @@ -495,6 +515,14 @@ define-properties@^1.1.3, define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +des.js@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" @@ -516,6 +544,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dotenv@^16.4.5: + version "16.4.5" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + es-abstract@^1.19.0, es-abstract@^1.20.4: version "1.21.2" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz" @@ -556,6 +589,18 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: unbox-primitive "^1.0.2" which-typed-array "^1.1.9" +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz" @@ -882,7 +927,7 @@ flatted@^3.1.0: follow-redirects@^1.15.6: version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== for-each@^0.3.3: @@ -909,7 +954,7 @@ function-bind@^1.1.1: function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== function.prototype.name@^1.1.5: @@ -936,6 +981,17 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has "^1.0.3" has-symbols "^1.0.3" +get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" @@ -1035,6 +1091,13 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + has-proto@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" @@ -1059,16 +1122,16 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hasown@^2.0.2: +hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" https-proxy-agent@^5.0.0: version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== dependencies: agent-base "6" @@ -1105,7 +1168,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@^2.0.1: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1121,7 +1184,7 @@ internal-slot@^1.0.5: interpret@^1.0.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== ipv6@*: @@ -1171,7 +1234,7 @@ is-core-module@^2.11.0, is-core-module@^2.9.0: is-core-module@^2.13.0: version "2.15.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz" integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== dependencies: hasown "^2.0.2" @@ -1274,6 +1337,11 @@ isstream@0.1.x: resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== +js-md4@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/js-md4/-/js-md4-0.3.2.tgz#cd3b3dc045b0c404556c81ddb5756c23e59d7cf5" + integrity sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA== + js-sdsl@^4.1.4: version "4.4.0" resolved "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz" @@ -1355,12 +1423,12 @@ micromatch@^4.0.4: mime-db@1.52.0: version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-types@^2.1.27: version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" @@ -1370,9 +1438,14 @@ mime@^3.0.0: resolved "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz" integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + minimatch@3.0.5: version "3.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.5.tgz#4da8f1290ee0f0f8e83d60ca69f8f134068604a3" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz" integrity sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw== dependencies: brace-expansion "^1.1.7" @@ -1423,7 +1496,7 @@ natural-compare@^1.4.0: nodejs-file-downloader@^4.11.1: version "4.13.0" - resolved "https://registry.yarnpkg.com/nodejs-file-downloader/-/nodejs-file-downloader-4.13.0.tgz#da87c30081de5ff4e8b864062c98cdec03e66ad0" + resolved "https://registry.npmjs.org/nodejs-file-downloader/-/nodejs-file-downloader-4.13.0.tgz" integrity sha512-nI2fKnmJWWFZF6SgMPe1iBodKhfpztLKJTtCtNYGhm/9QXmWa/Pk9Sv00qHgzEvNLe1x7hjGDRor7gcm/ChaIQ== dependencies: follow-redirects "^1.15.6" @@ -1436,6 +1509,11 @@ object-inspect@^1.12.3, object-inspect@^1.9.0: resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" @@ -1545,12 +1623,12 @@ pkginfo@0.3.x: playwright-core@1.45.3: version "1.45.3" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.45.3.tgz#e77bc4c78a621b96c3e629027534ee1d25faac93" + resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.3.tgz" integrity sha512-+ym0jNbcjikaOwwSZycFbwkWgfruWvYlJfThKYAlImbxUgdWFO2oW70ojPm4OpE4t6TAo2FY/smM+hpVTtkhDA== playwright@1.45.3: version "1.45.3" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.45.3.tgz#75143f73093a6e1467f7097083d2f0846fb8dd2f" + resolved "https://registry.npmjs.org/playwright/-/playwright-1.45.3.tgz" integrity sha512-QhVaS+lpluxCaioejDZ95l4Y4jSFCsBvl2UZkpeXlzxmqS+aABr5c82YmfMHrL6x27nvrvykJAFpkzT2eWdJww== dependencies: playwright-core "1.45.3" @@ -1574,15 +1652,15 @@ punycode@^2.1.0: q@^1.5.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@^6.9.1: - version "6.11.1" - resolved "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz" - integrity sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ== +qs@^6.10.3: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" queue-microtask@^1.2.2: version "1.2.3" @@ -1591,7 +1669,7 @@ queue-microtask@^1.2.2: rechoir@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz" integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== dependencies: resolve "^1.1.6" @@ -1617,7 +1695,7 @@ resolve-from@^4.0.0: resolve@^1.1.6: version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" @@ -1663,14 +1741,14 @@ safe-regex-test@^1.0.0: sanitize-filename@^1.6.3: version "1.6.3" - resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378" + resolved "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz" integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg== dependencies: truncate-utf8-bytes "^1.0.0" semver@^5.1.0: version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== semver@^6.3.0: @@ -1685,6 +1763,18 @@ semver@^7.0.0, semver@^7.3.7, semver@^7.3.8: dependencies: lru-cache "^6.0.0" +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -1699,7 +1789,7 @@ shebang-regex@^3.0.0: shelljs@^0.8.5: version "0.8.5" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz" integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== dependencies: glob "^7.0.0" @@ -1715,6 +1805,16 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + slash@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" @@ -1825,7 +1925,7 @@ to-regex-range@^5.0.1: truncate-utf8-bytes@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" + resolved "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz" integrity sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ== dependencies: utf8-byte-length "^1.0.1" @@ -1878,12 +1978,14 @@ typed-array-length@^1.0.4: for-each "^0.3.3" is-typed-array "^1.1.9" -typed-rest-client@^1.8.4: - version "1.8.9" - resolved "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz" - integrity sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g== +typed-rest-client@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-2.0.2.tgz#82d451b9a219bf8fa688b698b2581327be4b920d" + integrity sha512-rmAQM2gZw/PQpK5+5aSs+I6ZBv4PFC2BT1o+0ADS1SgSejA+14EmbI2Lt8uXwkX7oeOMkwFmg0pHKwe8D9IT5A== dependencies: - qs "^6.9.1" + des.js "^1.1.0" + js-md4 "^0.3.2" + qs "^6.10.3" tunnel "0.0.6" underscore "^1.12.1" @@ -1921,12 +2023,12 @@ uri-js@^4.2.2: utf8-byte-length@^1.0.1: version "1.0.5" - resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz#f9f63910d15536ee2b2d5dd4665389715eac5c1e" + resolved "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz" integrity sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA== uuid@^3.0.1: version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== which-boxed-primitive@^1.0.2: From a8679081f92277443379d766652aaa94cd67f026 Mon Sep 17 00:00:00 2001 From: Alex Neo Date: Tue, 17 Sep 2024 11:03:38 +0300 Subject: [PATCH 2/5] v1.11.0-beta.0 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3541fb..6998999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# [1.11.0-beta.0](https://github.com/alexneo2003/playwright-azure-reporter/compare/v1.10.1...v1.11.0-beta.0) (2024-09-17) + + + ## [1.10.1](https://github.com/alexneo2003/playwright-azure-reporter/compare/v1.10.0...v1.10.1) (2024-08-09) diff --git a/package.json b/package.json index a9936b9..8b55674 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@alex_neo/playwright-azure-reporter", - "version": "1.10.1", + "version": "1.11.0-beta.0", "description": "Playwright Azure Reporter", "main": "./dist/playwright-azure-reporter.js", "types": "./dist/playwright-azure-reporter.d.js", From 9d80d0c381bf8523b7df88094f4d2f49bf1b3836 Mon Sep 17 00:00:00 2001 From: Alex Neo Date: Thu, 19 Sep 2024 09:58:26 +0300 Subject: [PATCH 3/5] v1.11.0 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6998999..9f4f1a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# [1.11.0](https://github.com/alexneo2003/playwright-azure-reporter/compare/v1.11.0-beta.0...v1.11.0) (2024-09-19) + + + # [1.11.0-beta.0](https://github.com/alexneo2003/playwright-azure-reporter/compare/v1.10.1...v1.11.0-beta.0) (2024-09-17) diff --git a/package.json b/package.json index 8b55674..166b74e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@alex_neo/playwright-azure-reporter", - "version": "1.11.0-beta.0", + "version": "1.11.0", "description": "Playwright Azure Reporter", "main": "./dist/playwright-azure-reporter.js", "types": "./dist/playwright-azure-reporter.d.js", From 43490e0f5ab664a377c82d1973efa07e1cec79e1 Mon Sep 17 00:00:00 2001 From: Alex Neo Date: Thu, 19 Sep 2024 10:08:41 +0300 Subject: [PATCH 4/5] (fix): rename config parameter --- README.md | 18 ++++----- src/playwright-azure-reporter.ts | 22 ++++++----- tests/reporter/reporter-constructor.spec.ts | 42 ++++++++++----------- 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 58d90fc..4b7640e 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ const config: PlaywrightTestConfig = { publishTestResultsMode: 'testRun', uploadAttachments: true, attachmentsType: ['screenshot', 'video', 'trace'], - tagsMatcher: /@\[(\d+)\]/, + testCaseIdMatcher: /@\[(\d+)\]/, testRunConfig: { owner: { displayName: 'Alex Neo', @@ -211,30 +211,30 @@ Reporter options (\* - required): > **Note:** If you use `isExistingTestRun` mode, test run doesn't complete automatically. You should complete it manually. -- `tagsMatcher` [string|RegExp|string[]|RegExp[]] - A string or a regular expression to match the name of the test case to extract the test case id. Default: `/\[([\d,\s]+)\]/` +- `testCaseIdMatcher` [string|RegExp|string[]|RegExp[]] - A string or a regular expression to match the name of the test case to extract the test case id. Default: `/\[([\d,\s]+)\]/` #### Example Test Titles - Test title: `Test case @tag1=123` - - `tagsMatcher: /@tag1=(\d+)/` + - `testCaseIdMatcher: /@tag1=(\d+)/` - Extracted tags: `['123']` - Test title: `Test case @TestCase=123 [@TestCase=456]` - - `tagsMatcher: /@TestCase=(\d+)/` + - `testCaseIdMatcher: /@TestCase=(\d+)/` - Extracted tags: `['123', '456']` - Test title: `Test case test123 TEST456` - - `tagsMatcher: [/[a-z]+(\d+)/, /[A-Z]+(\d+)/]` + - `testCaseIdMatcher: [/[a-z]+(\d+)/, /[A-Z]+(\d+)/]` - Extracted tags: `['123', '456']` - Test title: `Test case @tag1=123 @tag2=456` - - `tagsMatcher: ['@tag1=(\\d+)', '@tag2=(\\d+)']` + - `testCaseIdMatcher: ['@tag1=(\\d+)', '@tag2=(\\d+)']` - Extracted tags: `['123', '456']` #### Error Handling - If an invalid `tagsMatcher` is provided, an error will be thrown. For example: + If an invalid `testCaseIdMatcher` is provided, an error will be thrown. For example: ```typescript reporter: [ @@ -247,10 +247,10 @@ Reporter options (\* - required): planId: 4, token: 'your-token', isDisabled: false, - tagsMatcher: 1234, // Invalid pattern + testCaseIdMatcher: 1234, // Invalid pattern } ], - // This will throw an error: "Invalid tagsMatcher. Must be a string or RegExp. Actual: 1234" + // This will throw an error: "Invalid testCaseIdMatcher. Must be a string or RegExp. Actual: 1234" ``` ## Usefulness diff --git a/src/playwright-azure-reporter.ts b/src/playwright-azure-reporter.ts index 0f13dbb..30d7121 100644 --- a/src/playwright-azure-reporter.ts +++ b/src/playwright-azure-reporter.ts @@ -56,7 +56,7 @@ export interface AzureReporterOptions { testPointMapper?: (testCase: TestCase, testPoints: TestPoint[]) => Promise; isExistingTestRun?: boolean; testRunId?: number; - tagsMatcher?: string | RegExp | Array; + testCaseIdMatcher?: string | RegExp | Array; } interface TestResultsToTestRun { @@ -144,7 +144,7 @@ class AzureDevOpsReporter implements Reporter { private _publishTestResultsMode: TPublishTestResults = 'testResult'; private _testRunId: number | undefined; private _isExistingTestRun = false; - private _tagsMatcher: string | RegExp | Array = new RegExp(/\[([\d,\s]+)\]/, 'g'); + private _testCaseIdMatcher: string | RegExp | Array = new RegExp(/\[([\d,\s]+)\]/, 'g'); public constructor(options: AzureReporterOptions) { this._runIdPromise = new Promise((resolve, reject) => { @@ -262,7 +262,7 @@ class AzureDevOpsReporter implements Reporter { this._testPointMapper = options.testPointMapper; } this._isExistingTestRun = options.isExistingTestRun || false; - this._tagsMatcher = options.tagsMatcher || new RegExp(/\[([\d,\s]+)\]/, 'g'); + this._testCaseIdMatcher = options.testCaseIdMatcher || new RegExp(/\[([\d,\s]+)\]/, 'g'); } async onBegin(): Promise { @@ -415,14 +415,16 @@ class AzureDevOpsReporter implements Reporter { } private _extractMatches(text: string): string[] { - const reList = (Array.isArray(this._tagsMatcher) ? this._tagsMatcher : [this._tagsMatcher]).map((re) => { - if (typeof re === 'string') { - return new RegExp(re, 'g'); - } else if (!isRegExp(re)) { - throw new Error(`Invalid tagsMatcher. Must be a string or RegExp. Actual: ${re}`); + const reList = (Array.isArray(this._testCaseIdMatcher) ? this._testCaseIdMatcher : [this._testCaseIdMatcher]).map( + (re) => { + if (typeof re === 'string') { + return new RegExp(re, 'g'); + } else if (!isRegExp(re)) { + throw new Error(`Invalid testCaseIdMatcher. Must be a string or RegExp. Actual: ${re}`); + } + return re; } - return re; - }); + ); this._logger?.debug(`Extracting matches from text: ${text}`); this._logger?.debug(`Using matchers: ${reList}`); diff --git a/tests/reporter/reporter-constructor.spec.ts b/tests/reporter/reporter-constructor.spec.ts index 419a5ef..5626bc8 100644 --- a/tests/reporter/reporter-constructor.spec.ts +++ b/tests/reporter/reporter-constructor.spec.ts @@ -378,45 +378,45 @@ test.describe('Reporter constructor', () => { }); }); -let tagsMatchers: { - tagsMatcher?: RegExp | RegExp[] | string | string[] | undefined; +let testCaseIdMatchers: { + testCaseIdMatcher?: RegExp | RegExp[] | string | string[] | undefined; testTitle: string; tagsSection?: string; expected: string[]; }[] = [ { - tagsMatcher: /@tag1=(\d+)/, + testCaseIdMatcher: /@tag1=(\d+)/, testTitle: 'Test case @tag1=123', tagsSection: "['@tag1=7']", expected: ['123'], }, { - tagsMatcher: /@TestCase=(\d+)/, + testCaseIdMatcher: /@TestCase=(\d+)/, testTitle: 'Test case @TestCase=123 [@TestCase=456]', tagsSection: "['@TestCase=7', '@TestCase=7']", expected: ['123', '456'], }, { - tagsMatcher: [/[a-z]+(\d+)/, /[A-Z]+(\d+)/], + testCaseIdMatcher: [/[a-z]+(\d+)/, /[A-Z]+(\d+)/], testTitle: 'Test case test123 TEST456', tagsSection: "['@test7', '@TEST7']", expected: ['123', '456'], }, { - tagsMatcher: ['@tag1=(\\d+)', '@tag2=(\\d+)'], + testCaseIdMatcher: ['@tag1=(\\d+)', '@tag2=(\\d+)'], testTitle: 'Test case @tag1=123 @tag2=456', tagsSection: "['@tag1=7', '@tag2=7']", expected: ['123', '456'], }, { - tagsMatcher: undefined, + testCaseIdMatcher: undefined, testTitle: 'Test case [12345]', tagsSection: "['@[7]']", expected: ['12345'], }, ]; -tagsMatchers.forEach((item) => { +testCaseIdMatchers.forEach((item) => { test(`_extractMatches should return ${item.expected} for ${item.testTitle}`, () => { const reporter = new AzureDevOpsReporter({ orgUrl: 'http://localhost:4000', @@ -424,7 +424,7 @@ tagsMatchers.forEach((item) => { planId: 4, token: 'token', isDisabled: false, - tagsMatcher: item.tagsMatcher, + testCaseIdMatcher: item.testCaseIdMatcher, }); const matches = (reporter as any)._extractMatches(item.testTitle); @@ -507,13 +507,13 @@ tagsMatchers.forEach((item) => { uploadAttachments: true, logging: true, ${ - item.tagsMatcher - ? `tagsMatcher: ${ - Array.isArray(item.tagsMatcher) - ? `[${item.tagsMatcher + item.testCaseIdMatcher + ? `testCaseIdMatcher: ${ + Array.isArray(item.testCaseIdMatcher) + ? `[${item.testCaseIdMatcher .map((tag) => `${isRegExp(tag) ? tag.toString() : `'${tag.replace(/\\/g, '\\\\')}'`}`) .join(',')}]` - : `[${item.tagsMatcher}]` + : `[${item.testCaseIdMatcher}]` }` : '' } @@ -524,7 +524,7 @@ tagsMatchers.forEach((item) => { 'a.spec.js': ` import { test, expect } from '@playwright/test'; test('[7] with screenshot', ${ - item.tagsMatcher !== undefined ? `{ tag: ${item.tagsSection} }, ` : '' + item.testCaseIdMatcher !== undefined ? `{ tag: ${item.tagsSection} }, ` : '' } async ({ page }) => { await page.goto('https://playwright.dev/') await page.locator('text=Get started').click() @@ -551,17 +551,17 @@ tagsMatchers.forEach((item) => { }); }); -tagsMatchers = [ +testCaseIdMatchers = [ { //@ts-ignore - tagsMatcher: [3432, 3944], + testCaseIdMatcher: [3432, 3944], testTitle: 'Test case [12345]', expected: ['12345'], }, ]; -tagsMatchers.forEach((tagsMatcher) => { - test(`Test should throw an error for invalid tagsMatcher: ${tagsMatcher.tagsMatcher}`, () => { +testCaseIdMatchers.forEach((testCaseIdMatcher) => { + test(`Test should throw an error for invalid testCaseIdMatcher: ${testCaseIdMatcher.testCaseIdMatcher}`, () => { try { new AzureDevOpsReporter({ orgUrl: 'http://localhost:4000', @@ -569,10 +569,10 @@ tagsMatchers.forEach((tagsMatcher) => { planId: 4, token: 'token', isDisabled: false, - tagsMatcher: tagsMatcher.tagsMatcher, + testCaseIdMatcher: testCaseIdMatcher.testCaseIdMatcher, }); } catch (error) { - expect(error.message).toContain('Invalid tagsMatcher. Must be a string or RegExp. Actual: 3432'); + expect(error.message).toContain('Invalid testCaseIdMatcher. Must be a string or RegExp. Actual: 3432'); } }); }); From d5a94aa99aaeac75c76867390177630333dd8075 Mon Sep 17 00:00:00 2001 From: Alex Neo Date: Thu, 19 Sep 2024 10:36:25 +0300 Subject: [PATCH 5/5] test: fixing .env file missing error --- tests/reporter/playwright.config.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/reporter/playwright.config.ts b/tests/reporter/playwright.config.ts index b200ec3..da8d24e 100644 --- a/tests/reporter/playwright.config.ts +++ b/tests/reporter/playwright.config.ts @@ -1,9 +1,15 @@ import { defineConfig } from '@playwright/test'; import dotenv from 'dotenv'; +import * as fs from 'fs'; +import * as path from 'path'; -dotenv.config({ - path: require.resolve('../../.env'), -}); +const envPath = path.resolve(__dirname, '../../.env'); + +if (fs.existsSync(envPath)) { + dotenv.config({ path: envPath }); +} else { + console.warn(`.env file not found at ${envPath}, skipping dotenv configuration.`); +} export default defineConfig({ testDir: __dirname,