Skip to content

Commit 4ffdce6

Browse files
sarahsCopilot
andauthored
Integration tests for the content linter (#58547)
Co-authored-by: Copilot <[email protected]>
1 parent 46e3e82 commit 4ffdce6

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/**
2+
* Integration tests for the content linter CLI script.
3+
*
4+
* These tests verify the actual end-to-end behavior of the lint-content script
5+
* by running it via npm commands and checking the output. Unlike unit tests that
6+
* test individual functions in isolation, these tests catch issues in the full
7+
* CLI workflow including:
8+
*
9+
* - Command-line argument parsing
10+
* - File discovery and processing logic
11+
* - Rule configuration and filtering
12+
* - Error reporting and exit codes
13+
*
14+
* Test file structure:
15+
* - Test files are created in content/test-integration/ during tests
16+
* - This ensures the linter actually processes them (it only processes files in content/ or data/)
17+
* - Files are cleaned up after each test
18+
*
19+
* These tests serve as regression protection and verify that the linter
20+
* continues to work as expected when changes are made to the CLI logic.
21+
*/
22+
23+
import { execSync } from 'child_process'
24+
import { beforeEach, afterEach, describe, test, expect } from 'vitest'
25+
import fs from 'fs/promises'
26+
import path from 'path'
27+
28+
const rootDir = path.join(__dirname, '../../../..')
29+
const testContentDir = path.join(rootDir, 'content/test-integration')
30+
31+
describe('Content Linter CLI Integration Tests', () => {
32+
// Run all tests in sequence to avoid npm process conflicts
33+
beforeEach(async () => {
34+
// Create test directory
35+
await fs.mkdir(testContentDir, { recursive: true })
36+
})
37+
38+
afterEach(async () => {
39+
// Clean up test files
40+
await fs.rm(testContentDir, { recursive: true, force: true })
41+
})
42+
43+
// Helper function to run linter commands
44+
async function runLinter(args: string): Promise<{ output: string; exitCode: number }> {
45+
let output = ''
46+
let exitCode = 0
47+
48+
try {
49+
output = execSync(`npm run lint-content -- ${args}`, {
50+
encoding: 'utf8',
51+
cwd: rootDir,
52+
stdio: 'pipe',
53+
timeout: 10000, // 10 second timeout
54+
})
55+
} catch (error: any) {
56+
output = error.stdout + error.stderr
57+
exitCode = error.status || 1
58+
}
59+
60+
return { output, exitCode }
61+
}
62+
63+
describe('Linter functionality verification', () => {
64+
test('should detect errors when explicitly running search-replace rule', async () => {
65+
// Baseline test - ensures the linter can detect errors
66+
const testFile = path.join(testContentDir, 'baseline-test.md')
67+
const testContent = `---
68+
title: Baseline Test
69+
shortTitle: TODOCS This should definitely be caught
70+
intro: Testing basic linter functionality
71+
versions:
72+
feature: test
73+
topics:
74+
- Test
75+
---
76+
77+
TODOCS This placeholder should definitely be detected.
78+
`
79+
80+
await fs.writeFile(testFile, testContent)
81+
82+
const { output, exitCode } = await runLinter(`--paths "${testFile}" --rules search-replace`)
83+
84+
// This MUST work - if it doesn't, the linter is completely broken
85+
expect(exitCode).toBe(1)
86+
expect(output).toContain('todocs-placeholder')
87+
expect(output).toContain('ERROR')
88+
})
89+
})
90+
91+
describe('Default linter behavior', () => {
92+
test('should verify default rule execution behavior', async () => {
93+
// This test verifies that all rules run by default when no --rules are specified
94+
// It serves as regression protection against the TODOCS bug where no rules would run
95+
const testFile = path.join(testContentDir, 'default-behavior-test.md')
96+
const testContent = `---
97+
title: Test Article
98+
shortTitle: TODOCS Test title
99+
intro: This is a test article
100+
versions:
101+
feature: test
102+
topics:
103+
- Test
104+
---
105+
106+
TODOCS This is placeholder content that should now be detected by default.
107+
108+
### This heading skips H2 which should be a heading-increment error
109+
110+
`
111+
112+
await fs.writeFile(testFile, testContent)
113+
114+
const { output, exitCode } = await runLinter(`--paths "${testFile}"`)
115+
116+
// Verify that the linter properly detects errors when no --rules are specified
117+
expect(exitCode).toBe(1) // Should exit with error due to TODOCS
118+
expect(output).toContain('todocs-placeholder') // TODOCS should be detected by default
119+
expect(output).toContain('ERROR') // Errors should be detected
120+
})
121+
122+
test('should respect rule filtering when specific rules are provided', async () => {
123+
const testFile = path.join(testContentDir, 'multi-error-file.md')
124+
const testContent = `---
125+
title: Test Article
126+
shortTitle: TODOCS Test title
127+
intro: This is a test article
128+
versions:
129+
feature: test
130+
topics:
131+
- Test
132+
---
133+
134+
TODOCS This file has multiple error types.
135+
136+
### This heading skips H2 (heading-increment error)
137+
`
138+
139+
await fs.writeFile(testFile, testContent)
140+
141+
const { output, exitCode } = await runLinter(
142+
`--paths "${testFile}" --rules heading-increment`,
143+
)
144+
145+
expect(exitCode).toBe(0) // heading-increment rule behavior with filtering
146+
expect(output).not.toContain('ERROR')
147+
expect(output).not.toContain('todocs-placeholder')
148+
})
149+
})
150+
})

0 commit comments

Comments
 (0)