eslint-plugin-traceability 1.0.1 → 1.0.2

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.
package/.voder/plan.md CHANGED
@@ -1,15 +1,12 @@
1
1
  ## NOW
2
- Create `user-docs/api-reference.md` containing a skeleton outline of the plugin’s public API (listing each exported rule and config).
2
+ Standardize all test file headers under `tests/` to use JSDoc block comments with proper `@story` and `@req` annotations, replacing any inline comments for traceability.
3
3
 
4
4
  ## NEXT
5
- - Populate `user-docs/api-reference.md` with detailed descriptions, options, default values, and JSDoc‐style examples for every rule and config.
6
- - Add `user-docs/examples.md` with runnable end-to-end ESLint configurations and CLI invocation scenarios.
7
- - Update `README.md` to link to the new API reference and examples under `user-docs/`.
8
- - Replace the separate `ci.yml` and `deploy.yml` workflows with a single `.github/workflows/ci-cd.yml` that on every push to `main` runs build, lint, type-check, test, audit, and then publishes to npm.
9
- - Remove or disable the old `deploy.yml` and adjust any branch/tag filters so only `ci-cd.yml` handles publishing.
5
+ - Refactor test bodies to adopt explicit GIVEN-WHEN-THEN (Arrange-Act-Assert) structure and eliminate any custom logic (e.g. sorting/flatMap) in expectations.
6
+ - Add a post-deployment smoke-test job to `.github/workflows/ci-cd.yml` that installs the freshly published package in a clean workspace and executes the `cli-integration.js` script.
7
+ - Incorporate `cli-integration.js` into the CI “quality-checks” job so the pipeline mirrors the Husky pre-push behavior.
10
8
 
11
9
  ## LATER
12
- - In `ci-cd.yml`, add a smoke-test job that installs the freshly published package in a clean workspace and exercises basic CLI commands.
13
- - Record the unified CI/CD and documentation decisions in ADRs (e.g. `docs/decisions/ADR-unified-cicd.md`, `docs/decisions/ADR-api-reference.md`).
14
- - Migrate to semantic-release (or GitHub Releases) to automate version bumps and changelog updates.
15
- - Introduce a scheduled dependency/vulnerability audit job in CI to catch new advisories early.
10
+ - Write additional edge-case unit tests to cover any uncovered branches in the maintenance utilities.
11
+ - Monitor and optimize test execution times to keep unit tests fast (<100 ms each).
12
+ - Once testing and version-control improvements push both support areas above 90%, perform a full functionality reassessment.
Binary file
@@ -32,3 +32,4 @@ overall,functionality,code_quality,testing,execution,documentation,dependencies,
32
32
  77.5,,77,60,93,95,100,100,95
33
33
  76.875,,93,92,95,85,100,95,55
34
34
  89.6,,90,90,95,82,100,95,75
35
+ 91,,93,87,95,85,100,95,85
@@ -31,3 +31,4 @@
31
31
  77.5
32
32
  76.875
33
33
  89.6
34
+ 91
@@ -0,0 +1,165 @@
1
+ ---
2
+ status: "proposed"
3
+ date: 2025-11-17
4
+ decision-makers: [Development Team]
5
+ consulted:
6
+ [
7
+ npm Documentation,
8
+ GitHub Actions Best Practices,
9
+ Semantic Versioning Specification,
10
+ ]
11
+ informed: [Project Stakeholders, CI/CD Pipeline Maintainers]
12
+ ---
13
+
14
+ # Automated Version Bumping for CI/CD Publishing
15
+
16
+ ## Context and Problem Statement
17
+
18
+ The current CI/CD pipeline attempts to publish the package to npm on every push to the main branch, but lacks any mechanism to automatically increment the package version. This causes publish failures when the same version number already exists on npm, as npm does not allow republishing the same version. The pipeline fails with errors like "You cannot publish over the previously published versions" or similar npm publish conflicts.
19
+
20
+ Currently, version bumping requires manual intervention through direct package.json edits, which is error-prone, interrupts the automated delivery flow, and creates a disconnect between the continuous integration process and package publishing. This breaks the principle of continuous delivery and creates friction in the development workflow.
21
+
22
+ ## Decision Drivers
23
+
24
+ - Need for reliable automated publishing without manual intervention
25
+ - Prevention of npm publish failures due to version conflicts
26
+ - Alignment with semantic versioning principles for clear change communication
27
+ - Integration with existing CI/CD pipeline and GitHub workflow
28
+ - Maintainability of version history and changelog automation
29
+ - Support for different types of releases (patch, minor, major)
30
+ - Traceability of version changes to specific commits or pull requests
31
+ - Minimal friction for developers while maintaining version discipline
32
+
33
+ ## Considered Options
34
+
35
+ - npm version command with automated execution in CI/CD
36
+ - Semantic Release with automated version detection
37
+ - Manual version bumping with CI/CD workflow triggers
38
+ - Version bumping through GitHub Actions with npm version
39
+
40
+ ## Decision Outcome
41
+
42
+ Chosen option: "npm version command with automated execution in CI/CD", because it provides direct integration with npm tooling, maintains simplicity in the CI/CD pipeline, allows for both automated and manual control when needed, and follows established npm ecosystem practices without requiring complex semantic analysis tooling.
43
+
44
+ ### Implementation Strategy
45
+
46
+ The CI/CD pipeline will be modified to:
47
+
48
+ 1. **Pre-publish Version Check**: Before attempting to publish, check if the current package.json version already exists on npm
49
+ 2. **Automatic Patch Increment**: If the version exists, automatically increment the patch version using `npm version patch`
50
+ 3. **Commit and Tag**: Create a version commit and git tag as part of the pipeline
51
+ 4. **Publish with New Version**: Proceed with npm publish using the incremented version
52
+ 5. **Changelog Update**: Automatically update CHANGELOG.md with the new version entry
53
+
54
+ ### Consequences
55
+
56
+ - Good, because prevents all npm publish failures due to version conflicts
57
+ - Good, because maintains automated delivery without manual intervention
58
+ - Good, because creates proper git tags and version history
59
+ - Good, because uses standard npm tooling that developers understand
60
+ - Good, because allows for emergency manual version bumps when needed
61
+ - Good, because integrates cleanly with existing CI/CD infrastructure
62
+ - Neutral, because requires CI/CD pipeline to have git write access
63
+ - Neutral, because creates additional commits in the main branch for version bumps
64
+ - Bad, because does not automatically determine semantic version type (major/minor/patch)
65
+ - Bad, because may create noise in git history with automated version commits
66
+
67
+ ### Confirmation
68
+
69
+ Implementation compliance will be confirmed through:
70
+
71
+ - CI/CD pipeline successfully publishes without version conflicts
72
+ - Git repository contains version tags matching published npm versions
73
+ - CHANGELOG.md automatically updated with version entries
74
+ - No manual intervention required for routine publishing
75
+ - Version bumps traceable through git commit history
76
+ - package.json version always synchronized with published npm version
77
+
78
+ ## Pros and Cons of the Options
79
+
80
+ ### npm version command with automated execution in CI/CD
81
+
82
+ Standard npm tooling with CI/CD automation provides reliable version management with minimal complexity.
83
+
84
+ - Good, because uses native npm version management tools
85
+ - Good, because creates proper git tags and version commits automatically
86
+ - Good, because simple to understand and maintain in CI/CD
87
+ - Good, because allows manual override for major/minor version bumps
88
+ - Good, because integrates with existing npm publish workflow
89
+ - Good, because provides immediate resolution to publish failures
90
+ - Good, because maintains compatibility with npm ecosystem tools
91
+ - Neutral, because requires configuration of git credentials in CI/CD
92
+ - Neutral, because creates automated commits that may clutter history
93
+ - Bad, because defaults to patch-level increments only
94
+ - Bad, because does not analyze commit messages for semantic versioning
95
+
96
+ ### Semantic Release with automated version detection
97
+
98
+ Automated semantic versioning based on commit message analysis and release automation.
99
+
100
+ - Good, because fully automated semantic version determination
101
+ - Good, because analyzes commit messages for version type
102
+ - Good, because comprehensive release note generation
103
+ - Good, because follows semantic versioning specification strictly
104
+ - Good, because popular in open source ecosystem
105
+ - Neutral, because requires standardized commit message format
106
+ - Bad, because adds significant complexity to CI/CD pipeline
107
+ - Bad, because requires team discipline for commit message formatting
108
+ - Bad, because may be overkill for the current project size
109
+ - Bad, because introduces external dependency on semantic-release tool
110
+ - Bad, because harder to override for exceptional cases
111
+
112
+ ### Manual version bumping with CI/CD workflow triggers
113
+
114
+ Requiring manual version increments before publishing with workflow validation.
115
+
116
+ - Good, because provides full developer control over versioning
117
+ - Good, because ensures deliberate version decisions
118
+ - Good, because no automated commits or git history noise
119
+ - Good, because simple to understand and implement
120
+ - Neutral, because requires developer discipline for version management
121
+ - Bad, because breaks continuous delivery principle
122
+ - Bad, because requires manual intervention for every release
123
+ - Bad, because prone to human error and forgotten version bumps
124
+ - Bad, because does not solve the original npm publish failure problem
125
+ - Bad, because creates friction in development workflow
126
+
127
+ ### Version bumping through GitHub Actions with npm version
128
+
129
+ GitHub Actions-specific tooling for automated version management within the existing platform.
130
+
131
+ - Good, because native integration with GitHub workflow ecosystem
132
+ - Good, because can leverage GitHub-specific features like releases
133
+ - Good, because may provide better integration with pull request workflows
134
+ - Good, because uses familiar GitHub Actions patterns
135
+ - Neutral, because similar capabilities to npm version approach
136
+ - Bad, because locks solution to GitHub Actions platform specifically
137
+ - Bad, because may require additional GitHub Actions marketplace dependencies
138
+ - Bad, because potentially less portable to other CI/CD systems
139
+ - Bad, because npm version command is more universally understood
140
+
141
+ ## More Information
142
+
143
+ This decision addresses the immediate CI/CD publish failures while establishing a foundation for reliable automated delivery. The implementation should be flexible enough to support future migration to semantic release if the project grows to require more sophisticated version management.
144
+
145
+ Key implementation considerations:
146
+
147
+ - Configure CI/CD pipeline with appropriate git credentials for version commits
148
+ - Set up git user configuration for automated commits
149
+ - Ensure version tags follow consistent naming convention (v1.0.0 format)
150
+ - Update CHANGELOG.md generation to work with automated version increments
151
+ - Consider branch protection rules that allow CI/CD version commits
152
+ - Document manual override process for major/minor version bumps
153
+
154
+ This decision should be re-evaluated if:
155
+
156
+ - Project adopts semantic versioning discipline across the team
157
+ - Commit message standardization becomes feasible
158
+ - Publishing frequency increases significantly requiring more sophisticated automation
159
+ - The simple patch increment approach becomes insufficient for change communication
160
+
161
+ Related resources:
162
+
163
+ - [npm version command documentation](https://docs.npmjs.com/cli/v9/commands/npm-version)
164
+ - [GitHub Actions CI/CD Best Practices](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments)
165
+ - [Semantic Versioning Specification](https://semver.org/)
@@ -34,7 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  /**
37
- * Tests for basic plugin structure
37
+ * Tests for: docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
38
38
  * @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
39
39
  * @req REQ-PLUGIN-STRUCTURE - plugin exports rules and configs
40
40
  */
@@ -45,6 +45,7 @@ describe("Plugin Default Export and Configs (Story 001.0-DEV-PLUGIN-SETUP)", ()
45
45
  expect(index_1.default.configs).toBe(index_1.configs);
46
46
  });
47
47
  it("[REQ-PLUGIN-STRUCTURE] rules object has correct rule names", () => {
48
+ // Arrange: expected rule names in insertion order
48
49
  const expected = [
49
50
  "require-story-annotation",
50
51
  "require-req-annotation",
@@ -53,7 +54,10 @@ describe("Plugin Default Export and Configs (Story 001.0-DEV-PLUGIN-SETUP)", ()
53
54
  "valid-story-reference",
54
55
  "valid-req-reference",
55
56
  ];
56
- expect(Object.keys(index_1.rules).sort()).toEqual(expected.sort());
57
+ // Act: get actual rule names from plugin
58
+ const actual = Object.keys(index_1.rules);
59
+ // Assert: actual matches expected
60
+ expect(actual).toEqual(expected);
57
61
  });
58
62
  it("[REQ-RULE-REGISTRY] configs.recommended contains correct rule configuration", () => {
59
63
  const recommendedRules = index_1.configs.recommended[0].rules;
@@ -15,11 +15,10 @@ const eslintBin = path_1.default.resolve(__dirname, "../../node_modules/.bin/esl
15
15
  const configPath = path_1.default.resolve(__dirname, "../../eslint.config.js");
16
16
  describe("File and Req Validation CLI Integration (Story 006.0-DEV-FILE-VALIDATION)", () => {
17
17
  function runLint(code, rules) {
18
- const ruleArgs = [
19
- "--rule",
20
- "no-unused-vars:off",
21
- ...rules.flatMap((r) => ["--rule", r]),
22
- ];
18
+ const ruleArgs = ["--rule", "no-unused-vars:off"];
19
+ for (const r of rules) {
20
+ ruleArgs.push("--rule", r);
21
+ }
23
22
  return (0, child_process_1.spawnSync)("node", [
24
23
  eslintBin,
25
24
  "--no-config-lookup",
@@ -35,26 +34,38 @@ describe("File and Req Validation CLI Integration (Story 006.0-DEV-FILE-VALIDATI
35
34
  });
36
35
  }
37
36
  it("[REQ-FILE-EXISTENCE] reports missing story file via CLI", () => {
37
+ // Arrange
38
38
  const code = "// @story docs/stories/missing-file.story.md";
39
+ // Act
39
40
  const res = runLint(code, ["traceability/valid-story-reference:error"]);
41
+ // Assert
40
42
  expect(res.status).toBe(1);
41
43
  expect(res.stdout).toContain("Story file");
42
44
  });
43
45
  it("[REQ-EXTENSION] reports invalid extension via CLI", () => {
46
+ // Arrange
44
47
  const code = "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.md";
48
+ // Act
45
49
  const res = runLint(code, ["traceability/valid-story-reference:error"]);
50
+ // Assert
46
51
  expect(res.status).toBe(1);
47
52
  expect(res.stdout).toContain("Invalid story file extension");
48
53
  });
49
54
  it("[REQ-DEEP-PARSE] reports missing requirement via CLI", () => {
55
+ // Arrange
50
56
  const code = "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md\n// @req REQ-UNKNOWN";
57
+ // Act
51
58
  const res = runLint(code, ["traceability/valid-req-reference:error"]);
59
+ // Assert
52
60
  expect(res.status).toBe(1);
53
61
  expect(res.stdout).toContain("Requirement 'REQ-UNKNOWN' not found");
54
62
  });
55
63
  it("[REQ-DEEP-MATCH] valid story and requirement via CLI", () => {
64
+ // Arrange
56
65
  const code = "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md\n// @req REQ-PLUGIN-STRUCTURE";
66
+ // Act
57
67
  const res = runLint(code, ["traceability/valid-req-reference:error"]);
68
+ // Assert
58
69
  expect(res.status).toBe(0);
59
70
  });
60
71
  });
@@ -11,67 +11,73 @@ Object.defineProperty(exports, "__esModule", { value: true });
11
11
  /* eslint-env node, jest */
12
12
  const child_process_1 = require("child_process");
13
13
  const path_1 = __importDefault(require("path"));
14
+ // Ensure ESLint CLI uses built plugin
14
15
  const eslintBin = path_1.default.resolve(__dirname, "../../node_modules/.bin/eslint");
15
16
  const configPath = path_1.default.resolve(__dirname, "../../eslint.config.js");
16
- function runEslint(code, rule) {
17
- const args = [
18
- "--no-config-lookup",
19
- "--config",
20
- configPath,
21
- "--stdin",
22
- "--stdin-filename",
23
- "foo.js",
24
- "--rule",
25
- "no-unused-vars:off",
26
- "--rule",
27
- rule,
28
- ];
29
- // Use Node to run the ESLint CLI script
30
- return (0, child_process_1.spawnSync)("node", [eslintBin, ...args], {
31
- encoding: "utf-8",
32
- input: code,
33
- });
34
- }
35
- const cliTests = [
36
- {
37
- name: "[REQ-PLUGIN-STRUCTURE] reports error when @story annotation is missing",
38
- code: "function foo() {}",
39
- rule: "traceability/require-story-annotation:error",
40
- expectedStatus: 1,
41
- stdoutRegex: /require-story-annotation/,
42
- },
43
- {
44
- name: "does not report error when @story annotation is present",
45
- code: `
46
- /**
47
- * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
48
- */
49
- function foo() {}
50
- `,
51
- rule: "traceability/require-story-annotation:error",
52
- expectedStatus: 0,
53
- },
54
- {
55
- name: "Require Req Annotation CLI (Story 003.0-DEV-FUNCTION-ANNOTATIONS)",
56
- code: "function foo() {}",
57
- rule: "traceability/require-req-annotation:error",
58
- expectedStatus: 1,
59
- stdoutRegex: /require-req-annotation/,
60
- },
61
- {
62
- name: "Require Branch Annotation CLI (Story 004.0-DEV-BRANCH-ANNOTATIONS)",
63
- code: "if (condition) {}",
64
- rule: "traceability/require-branch-annotation:error",
65
- expectedStatus: 1,
66
- stdoutRegex: /require-branch-annotation/,
67
- },
68
- ];
69
17
  describe("ESLint CLI Integration (Story 001.0-DEV-PLUGIN-SETUP)", () => {
70
- test.each(cliTests)("$name", ({ code, rule, expectedStatus, stdoutRegex }) => {
18
+ /**
19
+ * Helper to run ESLint CLI with the traceability plugin and custom rule
20
+ * @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
21
+ * @req REQ-PLUGIN-STRUCTURE - Invoke ESLint CLI for integration testing
22
+ */
23
+ function runEslint(code, rule) {
24
+ const args = [
25
+ "--no-config-lookup",
26
+ "--config",
27
+ configPath,
28
+ "--stdin",
29
+ "--stdin-filename",
30
+ "foo.js",
31
+ "--rule",
32
+ "no-unused-vars:off",
33
+ "--rule",
34
+ rule,
35
+ ];
36
+ return (0, child_process_1.spawnSync)("node", [eslintBin, ...args], {
37
+ encoding: "utf-8",
38
+ input: code,
39
+ });
40
+ }
41
+ it("[REQ-PLUGIN-STRUCTURE] reports error when @story annotation is missing", () => {
42
+ // Arrange
43
+ const code = "function foo() {}";
44
+ const rule = "traceability/require-story-annotation:error";
45
+ // Act
46
+ const result = runEslint(code, rule);
47
+ // Assert
48
+ expect(result.status).toBe(1);
49
+ expect(result.stdout).toMatch(/require-story-annotation/);
50
+ });
51
+ it("[REQ-PLUGIN-STRUCTURE] does not report error when @story annotation is present", () => {
52
+ // Arrange
53
+ const code = `/**
54
+ * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
55
+ */
56
+ function foo() {}`;
57
+ const rule = "traceability/require-story-annotation:error";
58
+ // Act
59
+ const result = runEslint(code, rule);
60
+ // Assert
61
+ expect(result.status).toBe(0);
62
+ });
63
+ it("[REQ-REQ-CLI] reports error when @req annotation is missing", () => {
64
+ // Arrange
65
+ const code = "function foo() {}";
66
+ const rule = "traceability/require-req-annotation:error";
67
+ // Act
68
+ const result = runEslint(code, rule);
69
+ // Assert
70
+ expect(result.status).toBe(1);
71
+ expect(result.stdout).toMatch(/require-req-annotation/);
72
+ });
73
+ it("[REQ-BRANCH-CLI] reports error when branch annotations missing", () => {
74
+ // Arrange
75
+ const code = "if (true) {}";
76
+ const rule = "traceability/require-branch-annotation:error";
77
+ // Act
71
78
  const result = runEslint(code, rule);
72
- expect(result.status).toBe(expectedStatus);
73
- if (stdoutRegex) {
74
- expect(result.stdout).toMatch(stdoutRegex);
75
- }
79
+ // Assert
80
+ expect(result.status).toBe(1);
81
+ expect(result.stdout).toMatch(/require-branch-annotation/);
76
82
  });
77
83
  });
@@ -48,6 +48,7 @@ describe("detectStaleAnnotations isolated (Story 009.0-DEV-MAINTENANCE-TOOLS)",
48
48
  expect(result).toEqual([]);
49
49
  });
50
50
  it("[REQ-MAINT-DETECT] detects stale annotations in nested directories", () => {
51
+ // Arrange
51
52
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "tmp-nested-"));
52
53
  const nestedDir = path.join(tmpDir, "nested");
53
54
  fs.mkdirSync(nestedDir);
@@ -65,8 +66,12 @@ describe("detectStaleAnnotations isolated (Story 009.0-DEV-MAINTENANCE-TOOLS)",
65
66
  */
66
67
  `;
67
68
  fs.writeFileSync(filePath2, content2, "utf8");
69
+ // Act
68
70
  const result = (0, detect_1.detectStaleAnnotations)(tmpDir);
69
- expect(result.sort()).toEqual(["stale1.story.md", "stale2.story.md"].sort());
71
+ // Assert
72
+ expect(result).toHaveLength(2);
73
+ expect(result).toContain("stale1.story.md");
74
+ expect(result).toContain("stale2.story.md");
70
75
  });
71
76
  it("[REQ-MAINT-DETECT] throws error on permission denied", () => {
72
77
  const tmpDir2 = fs.mkdtempSync(path.join(os.tmpdir(), "tmp-perm-"));
@@ -3,9 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- // Tests for: docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
7
- // @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
8
- // @req REQ-BRANCH-DETECTION - Verify require-branch-annotation rule enforces branch annotations
6
+ /**
7
+ * Tests for: docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
8
+ * @story docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md
9
+ * @req REQ-BRANCH-DETECTION - Verify require-branch-annotation rule enforces branch annotations
10
+ */
9
11
  const eslint_1 = require("eslint");
10
12
  const require_branch_annotation_1 = __importDefault(require("../../src/rules/require-branch-annotation"));
11
13
  const ruleTester = new eslint_1.RuleTester({
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  /**
7
7
  * Tests for: docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
8
8
  * @story docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md
9
+ * @req REQ-ANNOTATION-REQUIRED - Verify require-story-annotation rule enforces @story annotation on functions
9
10
  */
10
11
  const eslint_1 = require("eslint");
11
12
  const require_story_annotation_1 = __importDefault(require("../../src/rules/require-story-annotation"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-traceability",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tests for basic plugin structure
2
+ * Tests for: docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
3
3
  * @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md
4
4
  * @req REQ-PLUGIN-STRUCTURE - plugin exports rules and configs
5
5
  */
@@ -12,6 +12,7 @@ describe("Plugin Default Export and Configs (Story 001.0-DEV-PLUGIN-SETUP)", ()
12
12
  });
13
13
 
14
14
  it("[REQ-PLUGIN-STRUCTURE] rules object has correct rule names", () => {
15
+ // Arrange: expected rule names in insertion order
15
16
  const expected = [
16
17
  "require-story-annotation",
17
18
  "require-req-annotation",
@@ -20,7 +21,10 @@ describe("Plugin Default Export and Configs (Story 001.0-DEV-PLUGIN-SETUP)", ()
20
21
  "valid-story-reference",
21
22
  "valid-req-reference",
22
23
  ];
23
- expect(Object.keys(rules).sort()).toEqual(expected.sort());
24
+ // Act: get actual rule names from plugin
25
+ const actual = Object.keys(rules);
26
+ // Assert: actual matches expected
27
+ expect(actual).toEqual(expected);
24
28
  });
25
29
 
26
30
  it("[REQ-RULE-REGISTRY] configs.recommended contains correct rule configuration", () => {
@@ -12,11 +12,10 @@ const configPath = path.resolve(__dirname, "../../eslint.config.js");
12
12
 
13
13
  describe("File and Req Validation CLI Integration (Story 006.0-DEV-FILE-VALIDATION)", () => {
14
14
  function runLint(code: string, rules: string[]) {
15
- const ruleArgs = [
16
- "--rule",
17
- "no-unused-vars:off",
18
- ...rules.flatMap((r) => ["--rule", r]),
19
- ];
15
+ const ruleArgs = ["--rule", "no-unused-vars:off"];
16
+ for (const r of rules) {
17
+ ruleArgs.push("--rule", r);
18
+ }
20
19
  return spawnSync(
21
20
  "node",
22
21
  [
@@ -37,31 +36,43 @@ describe("File and Req Validation CLI Integration (Story 006.0-DEV-FILE-VALIDATI
37
36
  }
38
37
 
39
38
  it("[REQ-FILE-EXISTENCE] reports missing story file via CLI", () => {
39
+ // Arrange
40
40
  const code = "// @story docs/stories/missing-file.story.md";
41
+ // Act
41
42
  const res = runLint(code, ["traceability/valid-story-reference:error"]);
43
+ // Assert
42
44
  expect(res.status).toBe(1);
43
45
  expect(res.stdout).toContain("Story file");
44
46
  });
45
47
 
46
48
  it("[REQ-EXTENSION] reports invalid extension via CLI", () => {
49
+ // Arrange
47
50
  const code = "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.md";
51
+ // Act
48
52
  const res = runLint(code, ["traceability/valid-story-reference:error"]);
53
+ // Assert
49
54
  expect(res.status).toBe(1);
50
55
  expect(res.stdout).toContain("Invalid story file extension");
51
56
  });
52
57
 
53
58
  it("[REQ-DEEP-PARSE] reports missing requirement via CLI", () => {
59
+ // Arrange
54
60
  const code =
55
61
  "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md\n// @req REQ-UNKNOWN";
62
+ // Act
56
63
  const res = runLint(code, ["traceability/valid-req-reference:error"]);
64
+ // Assert
57
65
  expect(res.status).toBe(1);
58
66
  expect(res.stdout).toContain("Requirement 'REQ-UNKNOWN' not found");
59
67
  });
60
68
 
61
69
  it("[REQ-DEEP-MATCH] valid story and requirement via CLI", () => {
70
+ // Arrange
62
71
  const code =
63
72
  "// @story docs/stories/001.0-DEV-PLUGIN-SETUP.story.md\n// @req REQ-PLUGIN-STRUCTURE";
73
+ // Act
64
74
  const res = runLint(code, ["traceability/valid-req-reference:error"]);
75
+ // Assert
65
76
  expect(res.status).toBe(0);
66
77
  });
67
78
  });