| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { describe, it, expect, beforeAll } from 'vitest'; |
| import * as fs from 'fs'; |
| import * as path from 'path'; |
|
|
| describe('worktree-panel.tsx prop integrity', () => { |
| const filePath = path.resolve( |
| __dirname, |
| '../../../src/components/views/board-view/worktree-panel/worktree-panel.tsx' |
| ); |
|
|
| let sourceCode: string; |
|
|
| beforeAll(() => { |
| sourceCode = fs.readFileSync(filePath, 'utf-8'); |
| }); |
|
|
| it('should not have duplicate isDevServerStarting props within any single JSX element', () => { |
| |
| |
| |
| const lines = sourceCode.split('\n'); |
| let inElement = false; |
| let propCount = 0; |
| let elementName = ''; |
| const violations: string[] = []; |
|
|
| for (let i = 0; i < lines.length; i++) { |
| const trimmed = lines[i].trimStart(); |
|
|
| const elementStart = trimmed.match(/^<(\w+)\b/); |
| if (elementStart && !trimmed.startsWith('</')) { |
| inElement = true; |
| propCount = 0; |
| elementName = elementStart[1]; |
| } |
|
|
| if (inElement && trimmed.includes('isDevServerStarting=')) { |
| propCount++; |
| if (propCount > 1) { |
| violations.push(`Duplicate isDevServerStarting in <${elementName}> at line ${i + 1}`); |
| } |
| } |
|
|
| if ( |
| inElement && |
| (trimmed.includes('/>') || (trimmed.endsWith('>') && !trimmed.includes('='))) |
| ) { |
| inElement = false; |
| } |
| } |
|
|
| expect(violations).toEqual([]); |
| |
| expect(sourceCode).toContain('isDevServerStarting='); |
| }); |
|
|
| it('should not have duplicate isStartingAnyDevServer props within any single JSX element', () => { |
| const lines = sourceCode.split('\n'); |
| let inElement = false; |
| let propCount = 0; |
| let elementName = ''; |
| const violations: string[] = []; |
|
|
| for (let i = 0; i < lines.length; i++) { |
| const trimmed = lines[i].trimStart(); |
|
|
| const elementStart = trimmed.match(/^<(\w+)\b/); |
| if (elementStart && !trimmed.startsWith('</')) { |
| inElement = true; |
| propCount = 0; |
| elementName = elementStart[1]; |
| } |
|
|
| if (inElement && trimmed.includes('isStartingAnyDevServer=')) { |
| propCount++; |
| if (propCount > 1) { |
| violations.push(`Duplicate isStartingAnyDevServer in <${elementName}> at line ${i + 1}`); |
| } |
| } |
|
|
| if ( |
| inElement && |
| (trimmed.includes('/>') || (trimmed.endsWith('>') && !trimmed.includes('='))) |
| ) { |
| inElement = false; |
| } |
| } |
|
|
| expect(violations).toEqual([]); |
| }); |
|
|
| it('should not have any JSX element with duplicate prop names', () => { |
| |
| |
| const lines = sourceCode.split('\n'); |
|
|
| |
| |
| let currentJsxProps: Map<string, number[]> = new Map(); |
| let inJsxElement = false; |
| let _elementIndent = 0; |
|
|
| const duplicates: Array<{ prop: string; line: number; element: string }> = []; |
|
|
| for (let i = 0; i < lines.length; i++) { |
| const line = lines[i]; |
| const trimmed = line.trimStart(); |
| const indent = line.length - trimmed.length; |
|
|
| |
| if (trimmed.startsWith('<') && !trimmed.startsWith('</') && !trimmed.startsWith('{')) { |
| const elementMatch = trimmed.match(/^<(\w+)/); |
| if (elementMatch) { |
| inJsxElement = true; |
| _elementIndent = indent; |
| currentJsxProps = new Map(); |
| } |
| } |
|
|
| if (inJsxElement) { |
| |
| const propMatches = trimmed.matchAll(/\b(\w+)=\{/g); |
| for (const match of propMatches) { |
| const propName = match[1]; |
| if (!currentJsxProps.has(propName)) { |
| currentJsxProps.set(propName, []); |
| } |
| currentJsxProps.get(propName)!.push(i + 1); |
|
|
| |
| if (currentJsxProps.get(propName)!.length > 1) { |
| duplicates.push({ |
| prop: propName, |
| line: i + 1, |
| element: trimmed.substring(0, 50), |
| }); |
| } |
| } |
|
|
| |
| if (trimmed.includes('/>') || (trimmed.endsWith('>') && !trimmed.includes('='))) { |
| inJsxElement = false; |
| currentJsxProps = new Map(); |
| } |
| } |
| } |
|
|
| expect(duplicates).toEqual([]); |
| }); |
| }); |
|
|
| describe('worktree-panel.tsx uses both isStartingAnyDevServer and isDevServerStarting', () => { |
| const filePath = path.resolve( |
| __dirname, |
| '../../../src/components/views/board-view/worktree-panel/worktree-panel.tsx' |
| ); |
|
|
| let sourceCode: string; |
|
|
| beforeAll(() => { |
| sourceCode = fs.readFileSync(filePath, 'utf-8'); |
| }); |
|
|
| it('should use isStartingAnyDevServer from the useDevServers hook', () => { |
| |
| expect(sourceCode).toContain('isStartingAnyDevServer'); |
| }); |
|
|
| it('should use isDevServerStarting from the useDevServers hook', () => { |
| |
| expect(sourceCode).toContain('isDevServerStarting'); |
| }); |
|
|
| it('isStartingAnyDevServer and isDevServerStarting should be distinct concepts', () => { |
| |
| |
| |
| const hookDestructuring = sourceCode.match( |
| /const\s*\{[^}]*isStartingAnyDevServer[^}]*isDevServerStarting[^}]*\}/s |
| ); |
| expect(hookDestructuring).not.toBeNull(); |
| }); |
| }); |
|
|