vitest-plugin-steps 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ import type { Plugin } from 'vite';
2
+ import { StepReporter } from "./reporter.js";
3
+ export { step, type Step } from './setup.js';
4
+ export interface VitestStepsOptions {
5
+ /**
6
+ * Whether to use the custom reporter that displays steps.
7
+ * @default true
8
+ */
9
+ reporter?: boolean;
10
+ }
11
+ /**
12
+ * Vitest plugin that adds Playwright-style test.step() support.
13
+ */
14
+ export default function vitestSteps(options?: VitestStepsOptions): Plugin;
15
+ export { StepReporter };
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ import { StepReporter } from "./reporter.js";
2
+ export { step } from './setup.js';
3
+ /**
4
+ * Vitest plugin that adds Playwright-style test.step() support.
5
+ */
6
+ export default function vitestSteps(options = {}) {
7
+ const { reporter = true } = options;
8
+ return {
9
+ name: 'vitest-plugin-steps',
10
+ config() {
11
+ return {
12
+ test: {
13
+ setupFiles: ['vitest-plugin-steps/setup'],
14
+ reporters: reporter ? [new StepReporter()] : undefined
15
+ }
16
+ };
17
+ }
18
+ };
19
+ }
20
+ export { StepReporter };
@@ -0,0 +1,9 @@
1
+ import { DefaultReporter } from 'vitest/reporters';
2
+ import type { TestCase, Vitest } from 'vitest/node';
3
+ export declare class StepReporter extends DefaultReporter {
4
+ onInit(ctx: Vitest): void;
5
+ printTestCase(moduleState: 'pending' | 'passed' | 'failed', testCase: TestCase): void;
6
+ private printSteps;
7
+ private getIndentationLevel;
8
+ private getStepIcon;
9
+ }
@@ -0,0 +1,50 @@
1
+ import { DefaultReporter } from 'vitest/reporters';
2
+ export class StepReporter extends DefaultReporter {
3
+ onInit(ctx) {
4
+ super.onInit(ctx);
5
+ this.renderSucceed = true;
6
+ }
7
+ printTestCase(moduleState, testCase) {
8
+ super.printTestCase(moduleState, testCase);
9
+ const meta = testCase.meta();
10
+ const steps = meta.steps;
11
+ if (!steps || steps.length === 0) {
12
+ return;
13
+ }
14
+ const baseLevel = this.getIndentationLevel(testCase) + 1;
15
+ this.printSteps(steps, baseLevel);
16
+ }
17
+ printSteps(steps, indentLevel) {
18
+ const indent = ' '.repeat(indentLevel);
19
+ for (const s of steps) {
20
+ const icon = this.getStepIcon(s.status);
21
+ const duration = s.duration !== undefined ? ` \x1b[2m(${s.duration.toFixed(0)}ms)\x1b[0m` : '';
22
+ this.log(` ${indent}${icon} ${s.error ? `\x1b[31m` : ``}${s.name}${s.error ? `\x1b[0m` : ``}${duration}`);
23
+ // if (s.error) {
24
+ // this.log(` ${indent} \x1b[31mError: ${s.error.message}\x1b[0m`)
25
+ // }
26
+ if (!s.error && s.children && s.children.length > 0) {
27
+ this.printSteps(s.children, indentLevel + 1);
28
+ }
29
+ }
30
+ }
31
+ getIndentationLevel(testCase) {
32
+ let level = 1;
33
+ let parent = testCase.parent;
34
+ while (parent && 'parent' in parent) {
35
+ level++;
36
+ parent = parent.parent;
37
+ }
38
+ return level;
39
+ }
40
+ getStepIcon(status) {
41
+ switch (status) {
42
+ case 'passed':
43
+ return '\x1b[32m✓\x1b[0m';
44
+ case 'failed':
45
+ return '\x1b[31m✗\x1b[0m';
46
+ default:
47
+ return '\x1b[33m○\x1b[0m';
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,14 @@
1
+ export interface Step {
2
+ name: string;
3
+ status: 'passed' | 'failed' | 'running';
4
+ duration?: number;
5
+ error?: Error;
6
+ children?: Step[];
7
+ }
8
+ declare module 'vitest' {
9
+ interface TaskMeta {
10
+ steps?: Step[];
11
+ _currentStep?: Step | null;
12
+ }
13
+ }
14
+ export declare function step<T>(name: string, fn: () => T | Promise<T>): Promise<T>;
package/dist/setup.js ADDED
@@ -0,0 +1,35 @@
1
+ import { getCurrentTest } from 'vitest/suite';
2
+ // Step function implementation
3
+ export async function step(name, fn) {
4
+ const currentTest = getCurrentTest();
5
+ if (!currentTest) {
6
+ return fn();
7
+ }
8
+ currentTest.meta.steps ??= [];
9
+ const stepData = { name, status: 'running' };
10
+ const parentStep = currentTest.meta._currentStep;
11
+ if (parentStep) {
12
+ parentStep.children ??= [];
13
+ parentStep.children.push(stepData);
14
+ }
15
+ else {
16
+ currentTest.meta.steps.push(stepData);
17
+ }
18
+ currentTest.meta._currentStep = stepData;
19
+ const start = performance.now();
20
+ try {
21
+ const result = await fn();
22
+ stepData.status = 'passed';
23
+ stepData.duration = performance.now() - start;
24
+ return result;
25
+ }
26
+ catch (error) {
27
+ stepData.status = 'failed';
28
+ stepData.duration = performance.now() - start;
29
+ stepData.error = error;
30
+ throw error;
31
+ }
32
+ finally {
33
+ currentTest.meta._currentStep = parentStep;
34
+ }
35
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "vitest-plugin-steps",
3
+ "version": "1.0.0",
4
+ "description": "Vitest plugin that adds Playwright-style step() support",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./setup": {
14
+ "types": "./dist/setup.d.ts",
15
+ "import": "./dist/setup.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "peerDependencies": {
22
+ "vitest": ">=4.0.0"
23
+ },
24
+ "devDependencies": {
25
+ "typescript": "5.9.3",
26
+ "vite": "7.3.0",
27
+ "vitest": "4.0.16"
28
+ },
29
+ "scripts": {
30
+ "build": "tsc",
31
+ "dev": "tsc --watch"
32
+ }
33
+ }