From e2bf54aaa82e152bc5d03a4ae29dc1e6c307427f Mon Sep 17 00:00:00 2001 From: epszaw Date: Tue, 21 Jan 2025 16:10:59 +0100 Subject: [PATCH 1/4] add support for spaces in title metadata labels --- packages/allure-js-commons/src/sdk/utils.ts | 84 +++++++++++++++---- .../allure-js-commons/test/sdk/utils.spec.ts | 43 ++++++++++ 2 files changed, 109 insertions(+), 18 deletions(-) diff --git a/packages/allure-js-commons/src/sdk/utils.ts b/packages/allure-js-commons/src/sdk/utils.ts index dfdf3a068..f042f09bd 100644 --- a/packages/allure-js-commons/src/sdk/utils.ts +++ b/packages/allure-js-commons/src/sdk/utils.ts @@ -44,7 +44,14 @@ export const stripAnsi = (str: string): string => { return str.replace(regex, ""); }; -export const getMessageAndTraceFromError = (error: Error | { message?: string; stack?: string }): StatusDetails => { +export const getMessageAndTraceFromError = ( + error: + | Error + | { + message?: string; + stack?: string; + }, +): StatusDetails => { const { message, stack } = error; const actual = "actual" in error && error.actual !== undefined ? { actual: serialize(error.actual) } : {}; const expected = "expected" in error && error.expected !== undefined ? { expected: serialize(error.expected) } : {}; @@ -56,13 +63,34 @@ export const getMessageAndTraceFromError = (error: Error | { message?: string; s }; }; +type AllureTitleMetadataMatch = { + groups: { + type?: string; + v1?: string; + v2?: string; + v3?: string; + v4?: string; + }; +}; + +export const allureTitleMetadataRegexp = + /@?allure\.(?[^\s]+)[:=]("(?[^"]+)"|'(?[^']+)'|`(?[^`]+)`|(?[^\s]+))/; +export const allureTitleMetadataRegexpGlobal = new RegExp(allureTitleMetadataRegexp, "g"); export const allureIdRegexp = /(?:^|\s)@?allure\.id[:=](?[^\s]+)/; -export const allureIdRegexpGlobal = new RegExp(allureIdRegexp, "g"); export const allureLabelRegexp = /(?:^|\s)@?allure\.label\.(?[^:=\s]+)[:=](?[^\s]+)/; -export const allureLabelRegexpGlobal = new RegExp(allureLabelRegexp, "g"); + +export const getTypeFromAllureTitleMetadataMatch = (match: AllureTitleMetadataMatch) => { + return match.groups?.type; +}; + +export const getValueFromAllureTitleMetadataMatch = (match: AllureTitleMetadataMatch) => { + const { v1, v2, v3, v4 } = match.groups ?? {}; + + return v1 || v2 || v3 || v4; +}; export const isMetadataTag = (tag: string) => { - return allureIdRegexp.test(tag) || allureLabelRegexp.test(tag); + return allureTitleMetadataRegexp.test(tag); }; export const extractMetadataFromString = ( @@ -72,25 +100,45 @@ export const extractMetadataFromString = ( cleanTitle: string; } => { const labels = [] as Label[]; - - title.split(" ").forEach((val) => { - const idValue = val.match(allureIdRegexp)?.groups?.id; - - if (idValue) { - labels.push({ name: LabelName.ALLURE_ID, value: idValue }); + const metadata = title.matchAll(allureTitleMetadataRegexpGlobal); + const cleanTitle = title + .replaceAll(allureTitleMetadataRegexpGlobal, "") + .split(" ") + .filter(Boolean) + .reduce((acc, word) => { + if (/^[\n\r]/.test(word)) { + return acc + word; + } + + return `${acc} ${word}`; + }, "") + .trim(); + + for (const m of metadata) { + const match = m as AllureTitleMetadataMatch; + const type = getTypeFromAllureTitleMetadataMatch(match); + const value = getValueFromAllureTitleMetadataMatch(match); + + if (!type || !value) { + continue; } - const labelMatch = val.match(allureLabelRegexp); - const { name, value } = labelMatch?.groups || {}; + const [subtype, name] = type.split("."); - if (name && value) { - labels?.push({ name, value }); + switch (subtype) { + case "id": + labels.push({ name: LabelName.ALLURE_ID, value }); + break; + case "label": + labels.push({ name, value }); + break; } - }); - - const cleanTitle = title.replace(allureLabelRegexpGlobal, "").replace(allureIdRegexpGlobal, "").trim(); + } - return { labels, cleanTitle }; + return { + labels, + cleanTitle, + }; }; export const isAnyStepFailed = (item: StepResult | TestResult | FixtureResult): boolean => { diff --git a/packages/allure-js-commons/test/sdk/utils.spec.ts b/packages/allure-js-commons/test/sdk/utils.spec.ts index b19d1715c..569d2d567 100644 --- a/packages/allure-js-commons/test/sdk/utils.spec.ts +++ b/packages/allure-js-commons/test/sdk/utils.spec.ts @@ -296,6 +296,49 @@ describe("extractMetadataFromString", () => { ], }); }); + + it("should support values in single quotes", () => { + expect( + extractMetadataFromString("foo @allure.label.l1='foo bar baz' and bar @allure.id=beep @allure.label.l1=boop"), + ).toEqual({ + cleanTitle: "foo and bar", + labels: [ + { name: "l1", value: "foo bar baz" }, + { name: LabelName.ALLURE_ID, value: "beep" }, + { name: "l1", value: "boop" }, + ], + }); + }); + + it("should support values in double quotes", () => { + expect(extractMetadataFromString('foo @allure.label.l1="foo bar baz"')).toEqual({ + cleanTitle: "foo", + labels: [{ name: "l1", value: "foo bar baz" }], + }); + }); + + it("should support values in backticks", () => { + expect(extractMetadataFromString("foo @allure.label.l1=`foo bar baz`")).toEqual({ + cleanTitle: "foo", + labels: [{ name: "l1", value: "foo bar baz" }], + }); + }); + + it("should support mixed values at the same time", () => { + expect( + extractMetadataFromString( + "foo @allure.label.l1=foo @allure.label.l1=`foo 1` bar @allure.label.l1='foo 2' baz @allure.label.l1=\"foo 3\"", + ), + ).toEqual({ + cleanTitle: "foo bar baz", + labels: [ + { name: "l1", value: "foo" }, + { name: "l1", value: "foo 1" }, + { name: "l1", value: "foo 2" }, + { name: "l1", value: "foo 3" }, + ], + }); + }); }); describe("isMetadataTag", () => { From ce81631c75c3f1a0cff24e5ffea68e096e2f5a13 Mon Sep 17 00:00:00 2001 From: epszaw Date: Wed, 22 Jan 2025 10:56:54 +0100 Subject: [PATCH 2/4] fix problem with title metadata regexp groups --- packages/allure-js-commons/src/sdk/utils.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/allure-js-commons/src/sdk/utils.ts b/packages/allure-js-commons/src/sdk/utils.ts index f042f09bd..93067d332 100644 --- a/packages/allure-js-commons/src/sdk/utils.ts +++ b/packages/allure-js-commons/src/sdk/utils.ts @@ -63,7 +63,7 @@ export const getMessageAndTraceFromError = ( }; }; -type AllureTitleMetadataMatch = { +type AllureTitleMetadataMatch = RegExpMatchArray & { groups: { type?: string; v1?: string; @@ -74,19 +74,17 @@ type AllureTitleMetadataMatch = { }; export const allureTitleMetadataRegexp = - /@?allure\.(?[^\s]+)[:=]("(?[^"]+)"|'(?[^']+)'|`(?[^`]+)`|(?[^\s]+))/; + /@?allure\.(?\S+)[:=]("[^"]+"|'[^']+'|`[^`]+`|\S+)/; export const allureTitleMetadataRegexpGlobal = new RegExp(allureTitleMetadataRegexp, "g"); -export const allureIdRegexp = /(?:^|\s)@?allure\.id[:=](?[^\s]+)/; +export const allureIdRegexp = /(?:^|\s)@?allure\.id[:=](?\S+)/; export const allureLabelRegexp = /(?:^|\s)@?allure\.label\.(?[^:=\s]+)[:=](?[^\s]+)/; export const getTypeFromAllureTitleMetadataMatch = (match: AllureTitleMetadataMatch) => { - return match.groups?.type; + return match?.[1]; }; export const getValueFromAllureTitleMetadataMatch = (match: AllureTitleMetadataMatch) => { - const { v1, v2, v3, v4 } = match.groups ?? {}; - - return v1 || v2 || v3 || v4; + return match?.[2]?.replace?.(/['"`]/g, ""); }; export const isMetadataTag = (tag: string) => { From 2f9d04b8f390ceec844025a34f058f85410047ed Mon Sep 17 00:00:00 2001 From: epszaw Date: Wed, 22 Jan 2025 11:02:04 +0100 Subject: [PATCH 3/4] fix linters issues --- packages/allure-js-commons/src/sdk/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/allure-js-commons/src/sdk/utils.ts b/packages/allure-js-commons/src/sdk/utils.ts index 93067d332..c27e19235 100644 --- a/packages/allure-js-commons/src/sdk/utils.ts +++ b/packages/allure-js-commons/src/sdk/utils.ts @@ -73,8 +73,7 @@ type AllureTitleMetadataMatch = RegExpMatchArray & { }; }; -export const allureTitleMetadataRegexp = - /@?allure\.(?\S+)[:=]("[^"]+"|'[^']+'|`[^`]+`|\S+)/; +export const allureTitleMetadataRegexp = /@?allure\.(?\S+)[:=]("[^"]+"|'[^']+'|`[^`]+`|\S+)/; export const allureTitleMetadataRegexpGlobal = new RegExp(allureTitleMetadataRegexp, "g"); export const allureIdRegexp = /(?:^|\s)@?allure\.id[:=](?\S+)/; export const allureLabelRegexp = /(?:^|\s)@?allure\.label\.(?[^:=\s]+)[:=](?[^\s]+)/; From f133c1ea8c1cd1c98cea4284d339a9c5ac941645 Mon Sep 17 00:00:00 2001 From: epszaw Date: Fri, 24 Jan 2025 11:16:02 +0100 Subject: [PATCH 4/4] fix review issues --- packages/allure-js-commons/src/sdk/utils.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/allure-js-commons/src/sdk/utils.ts b/packages/allure-js-commons/src/sdk/utils.ts index c27e19235..15754f741 100644 --- a/packages/allure-js-commons/src/sdk/utils.ts +++ b/packages/allure-js-commons/src/sdk/utils.ts @@ -73,7 +73,7 @@ type AllureTitleMetadataMatch = RegExpMatchArray & { }; }; -export const allureTitleMetadataRegexp = /@?allure\.(?\S+)[:=]("[^"]+"|'[^']+'|`[^`]+`|\S+)/; +export const allureTitleMetadataRegexp = /(?:^|\s)@?allure\.(?\S+)[:=]("[^"]+"|'[^']+'|`[^`]+`|\S+)/; export const allureTitleMetadataRegexpGlobal = new RegExp(allureTitleMetadataRegexp, "g"); export const allureIdRegexp = /(?:^|\s)@?allure\.id[:=](?\S+)/; export const allureLabelRegexp = /(?:^|\s)@?allure\.label\.(?[^:=\s]+)[:=](?[^\s]+)/; @@ -83,7 +83,16 @@ export const getTypeFromAllureTitleMetadataMatch = (match: AllureTitleMetadataMa }; export const getValueFromAllureTitleMetadataMatch = (match: AllureTitleMetadataMatch) => { - return match?.[2]?.replace?.(/['"`]/g, ""); + const quotesRegexp = /['"`]/; + const quoteOpenRegexp = new RegExp(`^${quotesRegexp.source}`); + const quoteCloseRegexp = new RegExp(`${quotesRegexp.source}$`); + const matchedValue = match?.[2] ?? ""; + + if (quoteOpenRegexp.test(matchedValue) && quoteCloseRegexp.test(matchedValue)) { + return matchedValue.slice(1, -1); + } + + return matchedValue; }; export const isMetadataTag = (tag: string) => {