Skip to content

Commit 0fa44f8

Browse files
authored
Add ability to filter log plugin entries (#217)
1 parent ba64a89 commit 0fa44f8

File tree

8 files changed

+390
-258
lines changed

8 files changed

+390
-258
lines changed

allurerc.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default defineConfig({
1818
log: {
1919
options: {
2020
groupBy: "none",
21+
filter: ({ status }) => status === "failed" || status === "broken",
2122
},
2223
},
2324
},

packages/plugin-log/src/model.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import type { TestResult } from "@allurereport/core-api";
2+
13
export type LogPluginOptions = {
24
allSteps?: boolean;
35
withTrace?: boolean;
46
groupBy?: "suites" | "features" | "packages" | "none";
7+
filter?: (testResult: TestResult) => boolean;
58
};

packages/plugin-log/src/plugin.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,25 @@ export class LogPlugin implements Plugin {
88
constructor(readonly options: LogPluginOptions = {}) {}
99

1010
done = async (context: PluginContext, store: AllureStore) => {
11-
const { groupBy = "suite" } = this.options ?? {};
11+
const { groupBy = "suite", filter = () => true } = this.options ?? {};
1212
const allTestResults = await store.allTestResults();
13+
const filteredTestResults = allTestResults.filter(filter);
1314

1415
if (groupBy === "none") {
15-
allTestResults.forEach((test) => {
16+
filteredTestResults.forEach((test) => {
1617
printTest(test, this.options);
1718
});
1819

1920
console.log("");
2021

21-
printSummary(Array.from(allTestResults));
22+
printSummary(filteredTestResults, { total: allTestResults.length, filtered: filteredTestResults.length });
2223
return;
2324
}
2425

2526
const groupedTests = await store.testResultsByLabel(groupBy);
2627

2728
Object.keys(groupedTests).forEach((key) => {
28-
const tests = groupedTests[key];
29+
const tests = groupedTests[key].filter(filter);
2930

3031
if (tests.length === 0) {
3132
// skip empty groups
@@ -45,6 +46,9 @@ export class LogPlugin implements Plugin {
4546
console.log("");
4647
});
4748

48-
printSummary(Array.from(allTestResults));
49+
printSummary(filteredTestResults, {
50+
total: allTestResults.length,
51+
filtered: filteredTestResults.length,
52+
});
4953
};
5054
}

packages/plugin-log/src/utils.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ export const printStep = (step: DefaultTestStepResult, options?: PrintFunctionOp
117117
});
118118
};
119119

120-
export const printSummary = (results: TestResult[]) => {
120+
export const printSummary = (results: TestResult[], options: { total: number; filtered: number }) => {
121+
const { total, filtered } = options;
121122
const statsCounters = {
122123
passed: 0,
123124
failed: 0,
@@ -168,7 +169,12 @@ export const printSummary = (results: TestResult[]) => {
168169
return;
169170
}
170171

171-
console.info(`Total tests: ${results.length}`);
172+
if (total === filtered) {
173+
console.info(`Total tests: ${filtered}`);
174+
} else {
175+
console.info(`Total tests: ${filtered} (of ${total})`);
176+
}
177+
172178
console.info(`Tests: ${stringifiedCounters.join(" | ")}`);
173179
console.info(`Duration: ${yellow((totalDuration / 1000).toString())}s`);
174180
};

packages/plugin-log/test/__snapshots__/index.test.ts.snap

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`stringifyStepResultTitle > returns title with status, name and duration 1`] = `"[32m✓[39m step [33m100ms[39m"`;
3+
exports[`utils > printTest > prints error trace if \`withTrace\` is true 1`] = `""`;
44

5-
exports[`stringifyTestResultTitle > returns title with status, name and duration 1`] = `"✓ 100ms"`;
5+
exports[`utils > printTest > prints the test with all steps if \`allSteps\` is true 1`] = `""`;
6+
7+
exports[`utils > printTest > prints the test with all steps if allSteps is true 1`] = `""`;
8+
9+
exports[`utils > printTest > prints the test without passed steps 1`] = `""`;
10+
11+
exports[`utils > printTest > prints the test without steps if there are no failed steps 1`] = `""`;
12+
13+
exports[`utils > stringifyStepResultTitle > returns title with status, name and duration 1`] = `"✓ step 100ms"`;
14+
15+
exports[`utils > stringifyTestResultTitle > returns title with status, name and duration 1`] = `"✓ 100ms"`;
Lines changed: 96 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,180 +1,116 @@
11
/* eslint-disable no-console */
22
import type { TestResult } from "@allurereport/core-api";
3-
import type { MockedFunction } from "vitest";
4-
import { describe, expect, it, vi } from "vitest";
5-
import { printTest } from "../src/utils.js";
6-
7-
const glueConsoleCalls = (calls: any[]) => calls.flatMap((args: any[]) => args[0]).join("\n");
8-
9-
describe("printTest", () => {
10-
it("prints the test without steps if there are no failed steps", () => {
11-
vi.spyOn(console, "info");
12-
13-
const fixture = {
14-
name: "Test name",
3+
import type { AllureStore, PluginContext } from "@allurereport/plugin-api";
4+
import { beforeEach, describe, expect, it, vi } from "vitest";
5+
import { LogPlugin } from "../src/plugin.js";
6+
import { printSummary, printTest } from "../src/utils.js";
7+
8+
const fixtures = {
9+
testResults: [
10+
{
11+
name: "Test A",
1512
status: "passed",
16-
duration: 100,
17-
steps: [
18-
{
19-
name: "step 1",
20-
status: "passed",
21-
steps: [
22-
{
23-
name: "step 1.1",
24-
status: "passed",
25-
},
26-
],
27-
},
28-
],
29-
} as TestResult;
30-
31-
printTest(fixture);
32-
33-
const result = glueConsoleCalls((console.info as MockedFunction<any>).mock.calls);
34-
35-
expect(result).toMatchSnapshot();
36-
});
37-
38-
it("prints the test without passed steps", () => {
39-
vi.spyOn(console, "info");
40-
41-
const fixture = {
42-
name: "Test name",
43-
status: "passed",
44-
duration: 100,
45-
steps: [
46-
{
47-
name: "step 1",
48-
status: "passed",
49-
steps: [
50-
{
51-
name: "step 1.1",
52-
status: "passed",
53-
},
54-
],
55-
},
56-
{
57-
name: "step 2",
58-
status: "failed",
59-
},
60-
{
61-
name: "step 3",
62-
status: "broken",
63-
},
64-
],
65-
} as TestResult;
66-
67-
printTest(fixture);
13+
},
14+
{
15+
name: "Test B",
16+
status: "failed",
17+
},
18+
] as TestResult[],
19+
};
20+
21+
vi.mock("../src/utils.js", async () => {
22+
return {
23+
...(await vi.importActual("../src/utils.js")),
24+
printTest: vi.fn(),
25+
printSummary: vi.fn(),
26+
};
27+
});
6828

69-
const result = glueConsoleCalls((console.info as MockedFunction<any>).mock.calls);
29+
beforeEach(() => {
30+
vi.clearAllMocks();
31+
});
7032

71-
expect(result).toMatchSnapshot();
33+
describe("plugin", () => {
34+
it("prints all tests when filter is not provided", async () => {
35+
const store = {
36+
allTestResults: vi.fn().mockResolvedValue(fixtures.testResults),
37+
testResultsByLabel: vi.fn().mockResolvedValue({
38+
_: [...fixtures.testResults],
39+
}),
40+
} as unknown as AllureStore;
41+
const plugin = new LogPlugin({});
42+
43+
await plugin.done({} as PluginContext, store);
44+
45+
expect(printTest).toHaveBeenCalledTimes(fixtures.testResults.length);
46+
expect(printSummary).toHaveBeenCalledTimes(1);
47+
expect(printSummary).toHaveBeenCalledWith(fixtures.testResults, {
48+
total: fixtures.testResults.length,
49+
filtered: fixtures.testResults.length,
50+
});
7251
});
7352

74-
it("prints the test with all steps if allSteps is true", () => {
75-
vi.spyOn(console, "info");
76-
77-
const fixture = {
78-
name: "Test name",
79-
status: "passed",
80-
duration: 100,
81-
steps: [
82-
{
83-
name: "step 1",
84-
status: "passed",
85-
steps: [
86-
{
87-
name: "step 1.1",
88-
status: "passed",
89-
},
90-
{
91-
name: "step 1.2",
92-
status: "passed",
93-
steps: [
94-
{
95-
name: "step 1.2.1",
96-
status: "passed",
97-
},
98-
],
99-
},
100-
],
101-
},
102-
],
103-
} as TestResult;
104-
105-
printTest(fixture, { allSteps: true });
53+
it("prints all tests when filter is not provided and tests are not groupped", async () => {
54+
const store = {
55+
allTestResults: vi.fn().mockResolvedValue(fixtures.testResults),
56+
testResultsByLabel: vi.fn().mockResolvedValue({
57+
_: [...fixtures.testResults],
58+
}),
59+
} as unknown as AllureStore;
60+
const plugin = new LogPlugin({
61+
groupBy: "none",
62+
});
10663

107-
const result = glueConsoleCalls((console.info as MockedFunction<any>).mock.calls);
64+
await plugin.done({} as PluginContext, store);
10865

109-
expect(result).toMatchSnapshot();
66+
expect(printTest).toHaveBeenCalledTimes(fixtures.testResults.length);
67+
expect(printSummary).toHaveBeenCalledTimes(1);
68+
expect(printSummary).toHaveBeenCalledWith(fixtures.testResults, {
69+
total: fixtures.testResults.length,
70+
filtered: fixtures.testResults.length,
71+
});
11072
});
11173

112-
it("prints the test with all steps if `allSteps` is true", () => {
113-
vi.spyOn(console, "info");
114-
115-
const fixture = {
116-
name: "Test name",
117-
status: "failed",
118-
duration: 100,
119-
steps: [
120-
{
121-
name: "step 1",
122-
status: "failed",
123-
steps: [
124-
{
125-
name: "step 1.1",
126-
status: "failed",
127-
},
128-
{
129-
name: "step 1.2",
130-
status: "failed",
131-
steps: [
132-
{
133-
name: "step 1.2.1",
134-
status: "failed",
135-
error: {
136-
message: "Error message",
137-
},
138-
},
139-
],
140-
},
141-
],
142-
},
143-
],
144-
} as TestResult;
145-
146-
printTest(fixture);
74+
it("prints only filtered tests when filter is provided", async () => {
75+
const store = {
76+
allTestResults: vi.fn().mockResolvedValue(fixtures.testResults),
77+
testResultsByLabel: vi.fn().mockResolvedValue({
78+
_: [...fixtures.testResults],
79+
}),
80+
} as unknown as AllureStore;
81+
const plugin = new LogPlugin({
82+
filter: (test) => test.status === "failed",
83+
});
14784

148-
const result = glueConsoleCalls((console.info as MockedFunction<any>).mock.calls);
85+
await plugin.done({} as PluginContext, store);
14986

150-
expect(result).toMatchSnapshot();
87+
expect(printTest).toHaveBeenCalledTimes(1);
88+
expect(printSummary).toHaveBeenCalledTimes(1);
89+
expect(printSummary).toHaveBeenCalledWith([fixtures.testResults[1]], {
90+
total: fixtures.testResults.length,
91+
filtered: 1,
92+
});
15193
});
15294

153-
it("prints error trace if `withTrace` is true", () => {
154-
vi.spyOn(console, "info");
155-
156-
const fixture = {
157-
name: "Test name",
158-
status: "failed",
159-
duration: 100,
160-
steps: [
161-
{
162-
name: "step 1",
163-
status: "failed",
164-
error: {
165-
message: "Error message",
166-
trace: "Error trace",
167-
},
168-
},
169-
],
170-
} as TestResult;
171-
172-
printTest(fixture, {
173-
withTrace: true,
95+
it("prints only filtered tests when filter is provided and tests are not groupped", async () => {
96+
const store = {
97+
allTestResults: vi.fn().mockResolvedValue(fixtures.testResults),
98+
testResultsByLabel: vi.fn().mockResolvedValue({
99+
_: [...fixtures.testResults],
100+
}),
101+
} as unknown as AllureStore;
102+
const plugin = new LogPlugin({
103+
groupBy: "none",
104+
filter: (test) => test.status === "failed",
174105
});
175106

176-
const result = glueConsoleCalls((console.info as MockedFunction<any>).mock.calls);
107+
await plugin.done({} as PluginContext, store);
177108

178-
expect(result).toMatchSnapshot();
109+
expect(printTest).toHaveBeenCalledTimes(1);
110+
expect(printSummary).toHaveBeenCalledTimes(1);
111+
expect(printSummary).toHaveBeenCalledWith([fixtures.testResults[1]], {
112+
total: fixtures.testResults.length,
113+
filtered: 1,
114+
});
179115
});
180116
});

0 commit comments

Comments
 (0)