baseguard 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.
- package/.eslintrc.json +25 -0
- package/.prettierrc +8 -0
- package/README.md +94 -0
- package/bin/base.js +494 -0
- package/dist/ai/fix-manager.d.ts +67 -0
- package/dist/ai/fix-manager.d.ts.map +1 -0
- package/dist/ai/fix-manager.js +326 -0
- package/dist/ai/fix-manager.js.map +1 -0
- package/dist/ai/gemini-analyzer.d.ts +116 -0
- package/dist/ai/gemini-analyzer.d.ts.map +1 -0
- package/dist/ai/gemini-analyzer.js +572 -0
- package/dist/ai/gemini-analyzer.js.map +1 -0
- package/dist/ai/index.d.ts +4 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +5 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/jules-implementer.d.ts +115 -0
- package/dist/ai/jules-implementer.d.ts.map +1 -0
- package/dist/ai/jules-implementer.js +387 -0
- package/dist/ai/jules-implementer.js.map +1 -0
- package/dist/commands/automation.d.ts +5 -0
- package/dist/commands/automation.d.ts.map +1 -0
- package/dist/commands/automation.js +305 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/check.d.ts +9 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +113 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/config.d.ts +11 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +324 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/fix.d.ts +9 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +207 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +125 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/core/api-key-manager.d.ts +83 -0
- package/dist/core/api-key-manager.d.ts.map +1 -0
- package/dist/core/api-key-manager.js +244 -0
- package/dist/core/api-key-manager.js.map +1 -0
- package/dist/core/baseguard.d.ts +46 -0
- package/dist/core/baseguard.d.ts.map +1 -0
- package/dist/core/baseguard.js +132 -0
- package/dist/core/baseguard.js.map +1 -0
- package/dist/core/baseline-checker.d.ts +63 -0
- package/dist/core/baseline-checker.d.ts.map +1 -0
- package/dist/core/baseline-checker.js +502 -0
- package/dist/core/baseline-checker.js.map +1 -0
- package/dist/core/cache-manager.d.ts +88 -0
- package/dist/core/cache-manager.d.ts.map +1 -0
- package/dist/core/cache-manager.js +213 -0
- package/dist/core/cache-manager.js.map +1 -0
- package/dist/core/configuration.d.ts +140 -0
- package/dist/core/configuration.d.ts.map +1 -0
- package/dist/core/configuration.js +474 -0
- package/dist/core/configuration.js.map +1 -0
- package/dist/core/directory-filter.d.ts +90 -0
- package/dist/core/directory-filter.d.ts.map +1 -0
- package/dist/core/directory-filter.js +319 -0
- package/dist/core/directory-filter.js.map +1 -0
- package/dist/core/error-handler.d.ts +110 -0
- package/dist/core/error-handler.d.ts.map +1 -0
- package/dist/core/error-handler.js +392 -0
- package/dist/core/error-handler.js.map +1 -0
- package/dist/core/file-processor.d.ts +80 -0
- package/dist/core/file-processor.d.ts.map +1 -0
- package/dist/core/file-processor.js +259 -0
- package/dist/core/file-processor.js.map +1 -0
- package/dist/core/gitignore-manager.d.ts +44 -0
- package/dist/core/gitignore-manager.d.ts.map +1 -0
- package/dist/core/gitignore-manager.js +147 -0
- package/dist/core/gitignore-manager.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lazy-loader.d.ts +68 -0
- package/dist/core/lazy-loader.d.ts.map +1 -0
- package/dist/core/lazy-loader.js +260 -0
- package/dist/core/lazy-loader.js.map +1 -0
- package/dist/core/memory-manager.d.ts +1 -0
- package/dist/core/memory-manager.d.ts.map +1 -0
- package/dist/core/memory-manager.js +2 -0
- package/dist/core/memory-manager.js.map +1 -0
- package/dist/core/startup-optimizer.d.ts +45 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -0
- package/dist/core/startup-optimizer.js +140 -0
- package/dist/core/startup-optimizer.js.map +1 -0
- package/dist/git/automation-engine.d.ts +58 -0
- package/dist/git/automation-engine.d.ts.map +1 -0
- package/dist/git/automation-engine.js +318 -0
- package/dist/git/automation-engine.js.map +1 -0
- package/dist/git/github-manager.d.ts +71 -0
- package/dist/git/github-manager.d.ts.map +1 -0
- package/dist/git/github-manager.js +226 -0
- package/dist/git/github-manager.js.map +1 -0
- package/dist/git/hook-manager.d.ts +43 -0
- package/dist/git/hook-manager.d.ts.map +1 -0
- package/dist/git/hook-manager.js +191 -0
- package/dist/git/hook-manager.js.map +1 -0
- package/dist/git/index.d.ts +4 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +5 -0
- package/dist/git/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/feature-validator.d.ts +60 -0
- package/dist/parsers/feature-validator.d.ts.map +1 -0
- package/dist/parsers/feature-validator.js +483 -0
- package/dist/parsers/feature-validator.js.map +1 -0
- package/dist/parsers/index.d.ts +8 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +9 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/parser-manager.d.ts +103 -0
- package/dist/parsers/parser-manager.d.ts.map +1 -0
- package/dist/parsers/parser-manager.js +321 -0
- package/dist/parsers/parser-manager.js.map +1 -0
- package/dist/parsers/parser.d.ts +23 -0
- package/dist/parsers/parser.d.ts.map +1 -0
- package/dist/parsers/parser.js +6 -0
- package/dist/parsers/parser.js.map +1 -0
- package/dist/parsers/react-parser.d.ts +22 -0
- package/dist/parsers/react-parser.d.ts.map +1 -0
- package/dist/parsers/react-parser.js +307 -0
- package/dist/parsers/react-parser.js.map +1 -0
- package/dist/parsers/svelte-parser.d.ts +33 -0
- package/dist/parsers/svelte-parser.d.ts.map +1 -0
- package/dist/parsers/svelte-parser.js +408 -0
- package/dist/parsers/svelte-parser.js.map +1 -0
- package/dist/parsers/vanilla-parser.d.ts +31 -0
- package/dist/parsers/vanilla-parser.d.ts.map +1 -0
- package/dist/parsers/vanilla-parser.js +590 -0
- package/dist/parsers/vanilla-parser.js.map +1 -0
- package/dist/parsers/vue-parser.d.ts +9 -0
- package/dist/parsers/vue-parser.d.ts.map +1 -0
- package/dist/parsers/vue-parser.js +16 -0
- package/dist/parsers/vue-parser.js.map +1 -0
- package/dist/terminal-header.d.ts +12 -0
- package/dist/terminal-header.js +45 -0
- package/dist/types/index.d.ts +83 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/components.d.ts +133 -0
- package/dist/ui/components.d.ts.map +1 -0
- package/dist/ui/components.js +482 -0
- package/dist/ui/components.js.map +1 -0
- package/dist/ui/help.d.ts +11 -0
- package/dist/ui/help.d.ts.map +1 -0
- package/dist/ui/help.js +161 -0
- package/dist/ui/help.js.map +1 -0
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +5 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/prompts.d.ts +63 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +611 -0
- package/dist/ui/prompts.js.map +1 -0
- package/dist/ui/terminal-header.d.ts +13 -0
- package/dist/ui/terminal-header.d.ts.map +1 -0
- package/dist/ui/terminal-header.js +46 -0
- package/dist/ui/terminal-header.js.map +1 -0
- package/package.json +80 -0
- package/src/ai/__tests__/gemini-analyzer.test.ts +181 -0
- package/src/ai/fix-manager.ts +362 -0
- package/src/ai/gemini-analyzer.ts +671 -0
- package/src/ai/index.ts +4 -0
- package/src/ai/jules-implementer.ts +459 -0
- package/src/commands/automation.ts +344 -0
- package/src/commands/check.ts +299 -0
- package/src/commands/config.ts +365 -0
- package/src/commands/fix.ts +234 -0
- package/src/commands/index.ts +6 -0
- package/src/commands/init.ts +142 -0
- package/src/commands/status.ts +0 -0
- package/src/core/api-key-manager.ts +298 -0
- package/src/core/baseguard.ts +742 -0
- package/src/core/baseline-checker.ts +563 -0
- package/src/core/cache-manager.ts +270 -0
- package/src/core/configuration-recovery.ts +676 -0
- package/src/core/configuration.ts +559 -0
- package/src/core/debug-logger.ts +590 -0
- package/src/core/directory-filter.ts +421 -0
- package/src/core/error-handler.ts +517 -0
- package/src/core/file-processor.ts +331 -0
- package/src/core/gitignore-manager.ts +169 -0
- package/src/core/graceful-degradation-manager.ts +596 -0
- package/src/core/index.ts +13 -0
- package/src/core/lazy-loader.ts +307 -0
- package/src/core/logger.ts +0 -0
- package/src/core/memory-manager.ts +294 -0
- package/src/core/startup-optimizer.ts +173 -0
- package/src/core/system-error-handler.ts +746 -0
- package/src/git/automation-engine.ts +361 -0
- package/src/git/github-manager.ts +260 -0
- package/src/git/hook-manager.ts +210 -0
- package/src/git/index.ts +4 -0
- package/src/index.ts +8 -0
- package/src/parsers/feature-validator.ts +559 -0
- package/src/parsers/index.ts +8 -0
- package/src/parsers/parser-manager.ts +419 -0
- package/src/parsers/parser.ts +26 -0
- package/src/parsers/react-parser-optimized.ts +161 -0
- package/src/parsers/react-parser.ts +359 -0
- package/src/parsers/svelte-parser.ts +506 -0
- package/src/parsers/vanilla-parser.ts +682 -0
- package/src/parsers/vue-parser.ts +472 -0
- package/src/types/index.ts +92 -0
- package/src/ui/components.ts +567 -0
- package/src/ui/help.ts +193 -0
- package/src/ui/index.ts +4 -0
- package/src/ui/prompts.ts +688 -0
- package/src/ui/terminal-header.ts +59 -0
- package/test-config-commands.js +56 -0
- package/test-header-simple.js +33 -0
- package/test-terminal-header.js +12 -0
- package/test-ui.js +29 -0
- package/tests/e2e/baseguard.e2e.test.ts +516 -0
- package/tests/e2e/cross-platform.e2e.test.ts +420 -0
- package/tests/e2e/git-integration.e2e.test.ts +487 -0
- package/tests/fixtures/react-project/package.json +14 -0
- package/tests/fixtures/react-project/src/App.css +76 -0
- package/tests/fixtures/react-project/src/App.tsx +77 -0
- package/tests/fixtures/svelte-project/package.json +11 -0
- package/tests/fixtures/svelte-project/src/App.svelte +369 -0
- package/tests/fixtures/vanilla-project/index.html +76 -0
- package/tests/fixtures/vanilla-project/script.js +331 -0
- package/tests/fixtures/vanilla-project/styles.css +359 -0
- package/tests/fixtures/vue-project/package.json +12 -0
- package/tests/fixtures/vue-project/src/App.vue +216 -0
- package/tsconfig.json +36 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { execSync, spawn } from 'child_process';
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
// Test configuration
|
|
11
|
+
const TEST_TIMEOUT = 30000; // 30 seconds for E2E tests
|
|
12
|
+
const FIXTURES_DIR = path.join(__dirname, '../fixtures');
|
|
13
|
+
const TEMP_DIR = path.join(__dirname, '../temp');
|
|
14
|
+
|
|
15
|
+
// Helper function to run BaseGuard commands
|
|
16
|
+
async function runBaseGuard(args: string[], cwd: string = TEMP_DIR): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
const basePath = path.join(__dirname, '../../bin/base.js');
|
|
19
|
+
const child = spawn('node', [basePath, ...args], {
|
|
20
|
+
cwd,
|
|
21
|
+
stdio: 'pipe',
|
|
22
|
+
env: { ...process.env, NODE_ENV: 'test' }
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
let stdout = '';
|
|
26
|
+
let stderr = '';
|
|
27
|
+
|
|
28
|
+
child.stdout?.on('data', (data) => {
|
|
29
|
+
stdout += data.toString();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
child.stderr?.on('data', (data) => {
|
|
33
|
+
stderr += data.toString();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
child.on('close', (code) => {
|
|
37
|
+
resolve({
|
|
38
|
+
stdout,
|
|
39
|
+
stderr,
|
|
40
|
+
exitCode: code || 0
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Kill process after timeout
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
child.kill();
|
|
47
|
+
resolve({
|
|
48
|
+
stdout,
|
|
49
|
+
stderr,
|
|
50
|
+
exitCode: 1
|
|
51
|
+
});
|
|
52
|
+
}, TEST_TIMEOUT);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Helper function to copy fixture to temp directory
|
|
57
|
+
async function copyFixture(fixtureName: string, tempName: string): Promise<string> {
|
|
58
|
+
const sourcePath = path.join(FIXTURES_DIR, fixtureName);
|
|
59
|
+
const destPath = path.join(TEMP_DIR, tempName);
|
|
60
|
+
|
|
61
|
+
await fs.mkdir(destPath, { recursive: true });
|
|
62
|
+
await copyDirectory(sourcePath, destPath);
|
|
63
|
+
|
|
64
|
+
return destPath;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Helper function to recursively copy directory
|
|
68
|
+
async function copyDirectory(src: string, dest: string): Promise<void> {
|
|
69
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
70
|
+
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
const srcPath = path.join(src, entry.name);
|
|
73
|
+
const destPath = path.join(dest, entry.name);
|
|
74
|
+
|
|
75
|
+
if (entry.isDirectory()) {
|
|
76
|
+
await fs.mkdir(destPath, { recursive: true });
|
|
77
|
+
await copyDirectory(srcPath, destPath);
|
|
78
|
+
} else {
|
|
79
|
+
await fs.copyFile(srcPath, destPath);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Helper function to create test configuration
|
|
85
|
+
async function createTestConfig(projectPath: string, config: any): Promise<void> {
|
|
86
|
+
const configPath = path.join(projectPath, '.baseguardrc.json');
|
|
87
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
describe('BaseGuard End-to-End Tests', () => {
|
|
91
|
+
beforeEach(async () => {
|
|
92
|
+
// Clean up temp directory
|
|
93
|
+
try {
|
|
94
|
+
await fs.rm(TEMP_DIR, { recursive: true, force: true });
|
|
95
|
+
} catch (error) {
|
|
96
|
+
// Directory might not exist
|
|
97
|
+
}
|
|
98
|
+
await fs.mkdir(TEMP_DIR, { recursive: true });
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
afterEach(async () => {
|
|
102
|
+
// Clean up temp directory after each test
|
|
103
|
+
try {
|
|
104
|
+
await fs.rm(TEMP_DIR, { recursive: true, force: true });
|
|
105
|
+
} catch (error) {
|
|
106
|
+
// Ignore cleanup errors
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('React Project Testing', () => {
|
|
111
|
+
it('should detect compatibility violations in React project', async () => {
|
|
112
|
+
const projectPath = await copyFixture('react-project', 'react-test');
|
|
113
|
+
|
|
114
|
+
// Create test configuration targeting older browsers
|
|
115
|
+
await createTestConfig(projectPath, {
|
|
116
|
+
version: '1.0.0',
|
|
117
|
+
targets: [
|
|
118
|
+
{ browser: 'safari', minVersion: '15' },
|
|
119
|
+
{ browser: 'chrome', minVersion: '90' }
|
|
120
|
+
],
|
|
121
|
+
apiKeys: {
|
|
122
|
+
jules: null,
|
|
123
|
+
gemini: null
|
|
124
|
+
},
|
|
125
|
+
automation: {
|
|
126
|
+
enabled: false,
|
|
127
|
+
trigger: 'pre-commit',
|
|
128
|
+
autoAnalyze: false,
|
|
129
|
+
autoFix: false,
|
|
130
|
+
blockCommit: true
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const result = await runBaseGuard(['check', '--strict'], projectPath);
|
|
135
|
+
|
|
136
|
+
// Should find violations
|
|
137
|
+
expect(result.exitCode).toBe(1);
|
|
138
|
+
expect(result.stdout).toContain('compatibility violations found');
|
|
139
|
+
|
|
140
|
+
// Should detect specific modern features
|
|
141
|
+
expect(result.stdout).toContain('container-type');
|
|
142
|
+
expect(result.stdout).toContain('dialog');
|
|
143
|
+
expect(result.stdout).toContain('structuredClone');
|
|
144
|
+
expect(result.stdout).toContain('ResizeObserver');
|
|
145
|
+
|
|
146
|
+
// Should show file locations
|
|
147
|
+
expect(result.stdout).toContain('App.tsx');
|
|
148
|
+
expect(result.stdout).toContain('App.css');
|
|
149
|
+
}, TEST_TIMEOUT);
|
|
150
|
+
|
|
151
|
+
it('should pass when targeting modern browsers', async () => {
|
|
152
|
+
const projectPath = await copyFixture('react-project', 'react-modern');
|
|
153
|
+
|
|
154
|
+
// Create configuration targeting modern browsers
|
|
155
|
+
await createTestConfig(projectPath, {
|
|
156
|
+
version: '1.0.0',
|
|
157
|
+
targets: [
|
|
158
|
+
{ browser: 'chrome', minVersion: 'baseline' },
|
|
159
|
+
{ browser: 'safari', minVersion: 'baseline' },
|
|
160
|
+
{ browser: 'firefox', minVersion: 'baseline' }
|
|
161
|
+
],
|
|
162
|
+
apiKeys: {
|
|
163
|
+
jules: null,
|
|
164
|
+
gemini: null
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
169
|
+
|
|
170
|
+
// Should pass with baseline targets
|
|
171
|
+
expect(result.exitCode).toBe(0);
|
|
172
|
+
expect(result.stdout).toContain('No compatibility issues found');
|
|
173
|
+
}, TEST_TIMEOUT);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('Vue Project Testing', () => {
|
|
177
|
+
it('should detect compatibility violations in Vue project', async () => {
|
|
178
|
+
const projectPath = await copyFixture('vue-project', 'vue-test');
|
|
179
|
+
|
|
180
|
+
await createTestConfig(projectPath, {
|
|
181
|
+
version: '1.0.0',
|
|
182
|
+
targets: [
|
|
183
|
+
{ browser: 'safari', minVersion: '14' },
|
|
184
|
+
{ browser: 'firefox', minVersion: '85' }
|
|
185
|
+
]
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const result = await runBaseGuard(['check', '--strict'], projectPath);
|
|
189
|
+
|
|
190
|
+
expect(result.exitCode).toBe(1);
|
|
191
|
+
expect(result.stdout).toContain('compatibility violations found');
|
|
192
|
+
|
|
193
|
+
// Should detect Vue-specific extractions
|
|
194
|
+
expect(result.stdout).toContain('container-type');
|
|
195
|
+
expect(result.stdout).toContain('App.vue');
|
|
196
|
+
|
|
197
|
+
// Should ignore Vue-specific syntax
|
|
198
|
+
expect(result.stdout).not.toContain('@click');
|
|
199
|
+
expect(result.stdout).not.toContain('v-if');
|
|
200
|
+
}, TEST_TIMEOUT);
|
|
201
|
+
|
|
202
|
+
it('should extract web platform features from Vue SFC', async () => {
|
|
203
|
+
const projectPath = await copyFixture('vue-project', 'vue-extraction');
|
|
204
|
+
|
|
205
|
+
await createTestConfig(projectPath, {
|
|
206
|
+
version: '1.0.0',
|
|
207
|
+
targets: [{ browser: 'safari', minVersion: '15' }]
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
211
|
+
|
|
212
|
+
// Should extract from all SFC sections
|
|
213
|
+
expect(result.stdout).toContain('ResizeObserver'); // From script
|
|
214
|
+
expect(result.stdout).toContain('container-type'); // From style
|
|
215
|
+
expect(result.stdout).toContain('dialog'); // From template
|
|
216
|
+
}, TEST_TIMEOUT);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe('Svelte Project Testing', () => {
|
|
220
|
+
it('should detect compatibility violations in Svelte project', async () => {
|
|
221
|
+
const projectPath = await copyFixture('svelte-project', 'svelte-test');
|
|
222
|
+
|
|
223
|
+
await createTestConfig(projectPath, {
|
|
224
|
+
version: '1.0.0',
|
|
225
|
+
targets: [
|
|
226
|
+
{ browser: 'safari', minVersion: '14' },
|
|
227
|
+
{ browser: 'chrome', minVersion: '88' }
|
|
228
|
+
]
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const result = await runBaseGuard(['check', '--strict'], projectPath);
|
|
232
|
+
|
|
233
|
+
expect(result.exitCode).toBe(1);
|
|
234
|
+
expect(result.stdout).toContain('compatibility violations found');
|
|
235
|
+
|
|
236
|
+
// Should detect Svelte-specific extractions
|
|
237
|
+
expect(result.stdout).toContain('App.svelte');
|
|
238
|
+
expect(result.stdout).toContain('OffscreenCanvas');
|
|
239
|
+
expect(result.stdout).toContain('backdrop-filter');
|
|
240
|
+
|
|
241
|
+
// Should ignore Svelte-specific syntax
|
|
242
|
+
expect(result.stdout).not.toContain('bind:this');
|
|
243
|
+
expect(result.stdout).not.toContain('on:click');
|
|
244
|
+
}, TEST_TIMEOUT);
|
|
245
|
+
|
|
246
|
+
it('should handle complex Svelte features', async () => {
|
|
247
|
+
const projectPath = await copyFixture('svelte-project', 'svelte-complex');
|
|
248
|
+
|
|
249
|
+
await createTestConfig(projectPath, {
|
|
250
|
+
version: '1.0.0',
|
|
251
|
+
targets: [{ browser: 'safari', minVersion: '15' }]
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
255
|
+
|
|
256
|
+
// Should extract modern web APIs
|
|
257
|
+
expect(result.stdout).toContain('WebGL2RenderingContext');
|
|
258
|
+
expect(result.stdout).toContain('serviceWorker');
|
|
259
|
+
expect(result.stdout).toContain('caches');
|
|
260
|
+
}, TEST_TIMEOUT);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe('Vanilla Project Testing', () => {
|
|
264
|
+
it('should detect all web platform features in vanilla project', async () => {
|
|
265
|
+
const projectPath = await copyFixture('vanilla-project', 'vanilla-test');
|
|
266
|
+
|
|
267
|
+
await createTestConfig(projectPath, {
|
|
268
|
+
version: '1.0.0',
|
|
269
|
+
targets: [
|
|
270
|
+
{ browser: 'safari', minVersion: '14' },
|
|
271
|
+
{ browser: 'firefox', minVersion: '80' }
|
|
272
|
+
]
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const result = await runBaseGuard(['check', '--strict'], projectPath);
|
|
276
|
+
|
|
277
|
+
expect(result.exitCode).toBe(1);
|
|
278
|
+
expect(result.stdout).toContain('compatibility violations found');
|
|
279
|
+
|
|
280
|
+
// Should detect features from all file types
|
|
281
|
+
expect(result.stdout).toContain('index.html');
|
|
282
|
+
expect(result.stdout).toContain('styles.css');
|
|
283
|
+
expect(result.stdout).toContain('script.js');
|
|
284
|
+
|
|
285
|
+
// Should detect comprehensive web platform features
|
|
286
|
+
expect(result.stdout).toContain('container-type'); // CSS
|
|
287
|
+
expect(result.stdout).toContain('dialog'); // HTML
|
|
288
|
+
expect(result.stdout).toContain('structuredClone'); // JavaScript
|
|
289
|
+
expect(result.stdout).toContain('color-mix'); // CSS function
|
|
290
|
+
expect(result.stdout).toContain('OffscreenCanvas'); // Canvas API
|
|
291
|
+
}, TEST_TIMEOUT);
|
|
292
|
+
|
|
293
|
+
it('should handle all modern CSS features', async () => {
|
|
294
|
+
const projectPath = await copyFixture('vanilla-project', 'vanilla-css');
|
|
295
|
+
|
|
296
|
+
await createTestConfig(projectPath, {
|
|
297
|
+
version: '1.0.0',
|
|
298
|
+
targets: [{ browser: 'safari', minVersion: '14' }]
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
302
|
+
|
|
303
|
+
// Should detect advanced CSS features
|
|
304
|
+
expect(result.stdout).toContain('backdrop-filter');
|
|
305
|
+
expect(result.stdout).toContain('aspect-ratio');
|
|
306
|
+
expect(result.stdout).toContain(':has');
|
|
307
|
+
expect(result.stdout).toContain('color-scheme');
|
|
308
|
+
expect(result.stdout).toContain('accent-color');
|
|
309
|
+
}, TEST_TIMEOUT);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
describe('Cross-Framework Testing', () => {
|
|
313
|
+
it('should handle mixed framework project', async () => {
|
|
314
|
+
// Create a project with multiple frameworks
|
|
315
|
+
const projectPath = path.join(TEMP_DIR, 'mixed-project');
|
|
316
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
317
|
+
|
|
318
|
+
// Copy files from different frameworks
|
|
319
|
+
await fs.copyFile(
|
|
320
|
+
path.join(FIXTURES_DIR, 'react-project/src/App.tsx'),
|
|
321
|
+
path.join(projectPath, 'react-component.tsx')
|
|
322
|
+
);
|
|
323
|
+
await fs.copyFile(
|
|
324
|
+
path.join(FIXTURES_DIR, 'vue-project/src/App.vue'),
|
|
325
|
+
path.join(projectPath, 'vue-component.vue')
|
|
326
|
+
);
|
|
327
|
+
await fs.copyFile(
|
|
328
|
+
path.join(FIXTURES_DIR, 'svelte-project/src/App.svelte'),
|
|
329
|
+
path.join(projectPath, 'svelte-component.svelte')
|
|
330
|
+
);
|
|
331
|
+
await fs.copyFile(
|
|
332
|
+
path.join(FIXTURES_DIR, 'vanilla-project/script.js'),
|
|
333
|
+
path.join(projectPath, 'vanilla-script.js')
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
await createTestConfig(projectPath, {
|
|
337
|
+
version: '1.0.0',
|
|
338
|
+
targets: [{ browser: 'safari', minVersion: '15' }]
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
342
|
+
|
|
343
|
+
// Should process all framework files
|
|
344
|
+
expect(result.stdout).toContain('react-component.tsx');
|
|
345
|
+
expect(result.stdout).toContain('vue-component.vue');
|
|
346
|
+
expect(result.stdout).toContain('svelte-component.svelte');
|
|
347
|
+
expect(result.stdout).toContain('vanilla-script.js');
|
|
348
|
+
|
|
349
|
+
// Should find violations in all files
|
|
350
|
+
expect(result.stdout).toContain('compatibility violations found');
|
|
351
|
+
}, TEST_TIMEOUT);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
describe('Configuration Testing', () => {
|
|
355
|
+
it('should respect different browser targets', async () => {
|
|
356
|
+
const projectPath = await copyFixture('react-project', 'config-test');
|
|
357
|
+
|
|
358
|
+
// Test with very old browsers
|
|
359
|
+
await createTestConfig(projectPath, {
|
|
360
|
+
version: '1.0.0',
|
|
361
|
+
targets: [
|
|
362
|
+
{ browser: 'safari', minVersion: '10' },
|
|
363
|
+
{ browser: 'chrome', minVersion: '60' }
|
|
364
|
+
]
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
const oldResult = await runBaseGuard(['check'], projectPath);
|
|
368
|
+
expect(oldResult.stdout).toContain('compatibility violations found');
|
|
369
|
+
|
|
370
|
+
// Test with very new browsers
|
|
371
|
+
await createTestConfig(projectPath, {
|
|
372
|
+
version: '1.0.0',
|
|
373
|
+
targets: [
|
|
374
|
+
{ browser: 'safari', minVersion: '17' },
|
|
375
|
+
{ browser: 'chrome', minVersion: '120' }
|
|
376
|
+
]
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
const newResult = await runBaseGuard(['check'], projectPath);
|
|
380
|
+
// Should have fewer or no violations with newer targets
|
|
381
|
+
expect(newResult.exitCode).toBeLessThanOrEqual(oldResult.exitCode);
|
|
382
|
+
}, TEST_TIMEOUT);
|
|
383
|
+
|
|
384
|
+
it('should handle baseline targets correctly', async () => {
|
|
385
|
+
const projectPath = await copyFixture('vanilla-project', 'baseline-test');
|
|
386
|
+
|
|
387
|
+
// Test baseline widely available
|
|
388
|
+
await createTestConfig(projectPath, {
|
|
389
|
+
version: '1.0.0',
|
|
390
|
+
targets: [
|
|
391
|
+
{ browser: 'chrome', minVersion: 'baseline' },
|
|
392
|
+
{ browser: 'safari', minVersion: 'baseline' }
|
|
393
|
+
]
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
397
|
+
|
|
398
|
+
// Should only flag features that are not baseline
|
|
399
|
+
if (result.exitCode === 1) {
|
|
400
|
+
expect(result.stdout).toContain('baseline');
|
|
401
|
+
}
|
|
402
|
+
}, TEST_TIMEOUT);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
describe('Error Handling and Edge Cases', () => {
|
|
406
|
+
it('should handle malformed files gracefully', async () => {
|
|
407
|
+
const projectPath = path.join(TEMP_DIR, 'malformed-project');
|
|
408
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
409
|
+
|
|
410
|
+
// Create malformed files
|
|
411
|
+
await fs.writeFile(path.join(projectPath, 'broken.js'), 'const invalid = {');
|
|
412
|
+
await fs.writeFile(path.join(projectPath, 'broken.css'), '.invalid { color: }');
|
|
413
|
+
await fs.writeFile(path.join(projectPath, 'broken.vue'), '<template><div></template>');
|
|
414
|
+
|
|
415
|
+
await createTestConfig(projectPath, {
|
|
416
|
+
version: '1.0.0',
|
|
417
|
+
targets: [{ browser: 'safari', minVersion: '15' }]
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
421
|
+
|
|
422
|
+
// Should not crash and should report parsing issues
|
|
423
|
+
expect(result.exitCode).not.toBe(2); // Not a crash
|
|
424
|
+
expect(result.stderr).toContain('parsing');
|
|
425
|
+
}, TEST_TIMEOUT);
|
|
426
|
+
|
|
427
|
+
it('should handle empty project', async () => {
|
|
428
|
+
const projectPath = path.join(TEMP_DIR, 'empty-project');
|
|
429
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
430
|
+
|
|
431
|
+
await createTestConfig(projectPath, {
|
|
432
|
+
version: '1.0.0',
|
|
433
|
+
targets: [{ browser: 'safari', minVersion: '15' }]
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
437
|
+
|
|
438
|
+
expect(result.exitCode).toBe(0);
|
|
439
|
+
expect(result.stdout).toContain('No files found to check');
|
|
440
|
+
}, TEST_TIMEOUT);
|
|
441
|
+
|
|
442
|
+
it('should handle missing configuration', async () => {
|
|
443
|
+
const projectPath = await copyFixture('react-project', 'no-config');
|
|
444
|
+
|
|
445
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
446
|
+
|
|
447
|
+
// Should prompt for initialization or use defaults
|
|
448
|
+
expect(result.stderr).toContain('configuration') || expect(result.stdout).toContain('init');
|
|
449
|
+
}, TEST_TIMEOUT);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
describe('Performance Testing', () => {
|
|
453
|
+
it('should handle large number of files efficiently', async () => {
|
|
454
|
+
const projectPath = path.join(TEMP_DIR, 'large-project');
|
|
455
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
456
|
+
|
|
457
|
+
// Create many files
|
|
458
|
+
const promises = [];
|
|
459
|
+
for (let i = 0; i < 50; i++) {
|
|
460
|
+
promises.push(
|
|
461
|
+
fs.writeFile(
|
|
462
|
+
path.join(projectPath, `file${i}.js`),
|
|
463
|
+
`
|
|
464
|
+
// Modern JavaScript features
|
|
465
|
+
const data = { test: ${i} };
|
|
466
|
+
const cloned = structuredClone(data);
|
|
467
|
+
const observer = new ResizeObserver(() => {});
|
|
468
|
+
console.log('File ${i}');
|
|
469
|
+
`
|
|
470
|
+
)
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
await Promise.all(promises);
|
|
474
|
+
|
|
475
|
+
await createTestConfig(projectPath, {
|
|
476
|
+
version: '1.0.0',
|
|
477
|
+
targets: [{ browser: 'safari', minVersion: '15' }]
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
const startTime = Date.now();
|
|
481
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
482
|
+
const duration = Date.now() - startTime;
|
|
483
|
+
|
|
484
|
+
// Should complete within reasonable time (10 seconds for 50 files)
|
|
485
|
+
expect(duration).toBeLessThan(10000);
|
|
486
|
+
expect(result.stdout).toContain('structuredClone');
|
|
487
|
+
expect(result.stdout).toContain('ResizeObserver');
|
|
488
|
+
}, TEST_TIMEOUT);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
describe('CLI Interface Testing', () => {
|
|
492
|
+
it('should show help information', async () => {
|
|
493
|
+
const result = await runBaseGuard(['--help']);
|
|
494
|
+
|
|
495
|
+
expect(result.exitCode).toBe(0);
|
|
496
|
+
expect(result.stdout).toContain('BaseGuard');
|
|
497
|
+
expect(result.stdout).toContain('check');
|
|
498
|
+
expect(result.stdout).toContain('init');
|
|
499
|
+
expect(result.stdout).toContain('fix');
|
|
500
|
+
}, TEST_TIMEOUT);
|
|
501
|
+
|
|
502
|
+
it('should show version information', async () => {
|
|
503
|
+
const result = await runBaseGuard(['--version']);
|
|
504
|
+
|
|
505
|
+
expect(result.exitCode).toBe(0);
|
|
506
|
+
expect(result.stdout).toMatch(/\d+\.\d+\.\d+/);
|
|
507
|
+
}, TEST_TIMEOUT);
|
|
508
|
+
|
|
509
|
+
it('should handle invalid commands gracefully', async () => {
|
|
510
|
+
const result = await runBaseGuard(['invalid-command']);
|
|
511
|
+
|
|
512
|
+
expect(result.exitCode).toBe(1);
|
|
513
|
+
expect(result.stderr).toContain('Unknown command') || expect(result.stdout).toContain('help');
|
|
514
|
+
}, TEST_TIMEOUT);
|
|
515
|
+
});
|
|
516
|
+
});
|