187 lines
7.7 KiB
TypeScript
187 lines
7.7 KiB
TypeScript
import { fileURLToPath } from 'url'
|
|
import path from 'path'
|
|
import fs from 'fs'
|
|
|
|
import { describe, expect, test } from 'vitest'
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
const fixturesDir = path.join(__dirname, 'orphaned-features', 'fixtures')
|
|
|
|
// Import the actual helper functions from the orphaned features script
|
|
const { getVariableFiles, getReusableFiles } = await import(
|
|
'@/data-directory/scripts/find-orphaned-features/find.js'
|
|
)
|
|
|
|
describe('orphaned features detection', () => {
|
|
test('getVariableFiles finds all yml files in variables directory', () => {
|
|
const variablesDir = path.join(fixturesDir, 'data', 'variables')
|
|
const variableFiles = getVariableFiles(variablesDir)
|
|
|
|
// Should find our test.yml file
|
|
expect(variableFiles).toHaveLength(1)
|
|
expect(variableFiles[0]).toMatch(/test\.yml$/)
|
|
|
|
// Verify the file exists and contains expected content
|
|
const testVariableContent = fs.readFileSync(variableFiles[0], 'utf-8')
|
|
expect(testVariableContent).toContain('used-in-variables')
|
|
expect(testVariableContent).toContain('ifversion')
|
|
})
|
|
|
|
test('getReusableFiles finds all md files in reusables directory', () => {
|
|
const reusablesDir = path.join(fixturesDir, 'data', 'reusables')
|
|
const reusableFiles = getReusableFiles(reusablesDir)
|
|
|
|
// Should find our test.md file
|
|
expect(reusableFiles).toHaveLength(1)
|
|
expect(reusableFiles[0]).toMatch(/test\.md$/)
|
|
|
|
// Verify the file exists and contains expected content
|
|
const testReusableContent = fs.readFileSync(reusableFiles[0], 'utf-8')
|
|
expect(testReusableContent).toContain('used-in-reusables')
|
|
expect(testReusableContent).toContain('ifversion')
|
|
})
|
|
|
|
test('variables files contain feature references that should be detected', () => {
|
|
const variablesDir = path.join(fixturesDir, 'data', 'variables')
|
|
const testVariableFile = path.join(variablesDir, 'test.yml')
|
|
|
|
expect(fs.existsSync(testVariableFile)).toBe(true)
|
|
|
|
const content = fs.readFileSync(testVariableFile, 'utf-8')
|
|
|
|
// Verify the test file has the expected feature usage patterns
|
|
expect(content).toContain('{% ifversion used-in-variables %}')
|
|
expect(content).toContain('test_variable_with_feature')
|
|
expect(content).toContain('complex_variable')
|
|
})
|
|
|
|
test('helper functions handle nested directories', () => {
|
|
// Create a temporary nested structure to test
|
|
const tempDir = path.join(__dirname, 'temp-nested-test')
|
|
const nestedVariablesDir = path.join(tempDir, 'variables', 'nested')
|
|
const nestedReusablesDir = path.join(tempDir, 'reusables', 'nested')
|
|
|
|
// Create directories
|
|
fs.mkdirSync(nestedVariablesDir, { recursive: true })
|
|
fs.mkdirSync(nestedReusablesDir, { recursive: true })
|
|
|
|
// Create test files
|
|
fs.writeFileSync(path.join(nestedVariablesDir, 'nested.yml'), 'test: value')
|
|
fs.writeFileSync(path.join(nestedReusablesDir, 'nested.md'), '# Test content')
|
|
fs.writeFileSync(path.join(tempDir, 'variables', 'root.yml'), 'root: value')
|
|
fs.writeFileSync(path.join(tempDir, 'reusables', 'root.md'), '# Root content')
|
|
|
|
try {
|
|
// Test getVariableFiles with nested structure
|
|
const variableFiles = getVariableFiles(path.join(tempDir, 'variables'))
|
|
expect(variableFiles).toHaveLength(2)
|
|
expect(variableFiles.some((f) => f.includes('nested.yml'))).toBe(true)
|
|
expect(variableFiles.some((f) => f.includes('root.yml'))).toBe(true)
|
|
|
|
// Test getReusableFiles with nested structure
|
|
const reusableFiles = getReusableFiles(path.join(tempDir, 'reusables'))
|
|
expect(reusableFiles).toHaveLength(2)
|
|
expect(reusableFiles.some((f) => f.includes('nested.md'))).toBe(true)
|
|
expect(reusableFiles.some((f) => f.includes('root.md'))).toBe(true)
|
|
} finally {
|
|
// Clean up
|
|
fs.rmSync(tempDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('helper functions ignore non-target files', () => {
|
|
// Create a temporary directory with mixed file types
|
|
const tempDir = path.join(__dirname, 'temp-mixed-files')
|
|
fs.mkdirSync(tempDir, { recursive: true })
|
|
|
|
// Create various file types
|
|
fs.writeFileSync(path.join(tempDir, 'test.yml'), 'yml: content')
|
|
fs.writeFileSync(path.join(tempDir, 'test.md'), '# MD content')
|
|
fs.writeFileSync(path.join(tempDir, 'test.json'), '{"json": true}')
|
|
fs.writeFileSync(path.join(tempDir, 'test.txt'), 'text content')
|
|
fs.writeFileSync(path.join(tempDir, 'README.yml'), 'readme: content')
|
|
fs.writeFileSync(path.join(tempDir, 'README.md'), '# README')
|
|
|
|
try {
|
|
// getVariableFiles should only find .yml files (excluding README.yml)
|
|
const variableFiles = getVariableFiles(tempDir)
|
|
expect(variableFiles).toHaveLength(1)
|
|
expect(variableFiles[0]).toMatch(/test\.yml$/)
|
|
|
|
// getReusableFiles should only find .md files (excluding README.md)
|
|
const reusableFiles = getReusableFiles(tempDir)
|
|
expect(reusableFiles).toHaveLength(1)
|
|
expect(reusableFiles[0]).toMatch(/test\.md$/)
|
|
} finally {
|
|
// Clean up
|
|
fs.rmSync(tempDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('verify fix addresses the original issue scenario', () => {
|
|
// This test simulates the original issue where features were used only in variables
|
|
// but not detected by the orphaned features script
|
|
|
|
const variablesDir = path.join(fixturesDir, 'data', 'variables')
|
|
const featuresDir = path.join(fixturesDir, 'data', 'features')
|
|
|
|
// Verify our test setup has the scenario described in the issue
|
|
expect(fs.existsSync(path.join(featuresDir, 'used-in-variables.yml'))).toBe(true)
|
|
expect(fs.existsSync(path.join(featuresDir, 'truly-orphaned.yml'))).toBe(true)
|
|
|
|
// Check that the variable file references the feature
|
|
const variableContent = fs.readFileSync(path.join(variablesDir, 'test.yml'), 'utf-8')
|
|
expect(variableContent).toContain('used-in-variables')
|
|
|
|
// Verify that the getVariableFiles function would find this file
|
|
const variableFiles = getVariableFiles(variablesDir)
|
|
expect(variableFiles.length).toBeGreaterThan(0)
|
|
|
|
// This proves that the fix would catch features used in variables files
|
|
// because the orphaned features script now scans these files
|
|
const foundFeatureUsage = variableFiles.some((filePath) => {
|
|
const content = fs.readFileSync(filePath, 'utf-8')
|
|
return content.includes('used-in-variables')
|
|
})
|
|
|
|
expect(foundFeatureUsage).toBe(true)
|
|
})
|
|
|
|
test('functions correctly identify different file types in same directory', () => {
|
|
// Create a directory with both .yml and .md files to ensure each function
|
|
// only picks up its target file types
|
|
const tempDir = path.join(__dirname, 'temp-mixed-target-files')
|
|
fs.mkdirSync(tempDir, { recursive: true })
|
|
|
|
// Create files that both functions might encounter
|
|
fs.writeFileSync(
|
|
path.join(tempDir, 'variables.yml'),
|
|
'var: {% ifversion test-feature %}enabled{% endif %}',
|
|
)
|
|
fs.writeFileSync(
|
|
path.join(tempDir, 'reusable.md'),
|
|
'{% ifversion test-feature %}Reusable content{% endif %}',
|
|
)
|
|
fs.writeFileSync(path.join(tempDir, 'other.txt'), 'other content')
|
|
|
|
try {
|
|
// Each function should only find its target file type
|
|
const variableFiles = getVariableFiles(tempDir)
|
|
const reusableFiles = getReusableFiles(tempDir)
|
|
|
|
expect(variableFiles).toHaveLength(1)
|
|
expect(variableFiles[0]).toMatch(/variables\.yml$/)
|
|
|
|
expect(reusableFiles).toHaveLength(1)
|
|
expect(reusableFiles[0]).toMatch(/reusable\.md$/)
|
|
|
|
// Verify no cross-contamination
|
|
expect(variableFiles.some((f) => f.endsWith('.md'))).toBe(false)
|
|
expect(reusableFiles.some((f) => f.endsWith('.yml'))).toBe(false)
|
|
} finally {
|
|
// Clean up
|
|
fs.rmSync(tempDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
})
|