claude-autopm 1.17.0 → 1.20.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.
Files changed (76) hide show
  1. package/README.md +159 -0
  2. package/autopm/.claude/agents/core/mcp-manager.md +1 -1
  3. package/autopm/.claude/commands/pm/context.md +11 -0
  4. package/autopm/.claude/commands/pm/epic-decompose.md +25 -2
  5. package/autopm/.claude/commands/pm/epic-oneshot.md +13 -0
  6. package/autopm/.claude/commands/pm/epic-start.md +19 -0
  7. package/autopm/.claude/commands/pm/epic-sync-modular.md +10 -10
  8. package/autopm/.claude/commands/pm/epic-sync.md +14 -14
  9. package/autopm/.claude/commands/pm/issue-start.md +50 -5
  10. package/autopm/.claude/commands/pm/issue-sync.md +15 -15
  11. package/autopm/.claude/commands/pm/what-next.md +11 -0
  12. package/autopm/.claude/mcp/MCP-REGISTRY.md +1 -1
  13. package/autopm/.claude/scripts/azure/active-work.js +2 -2
  14. package/autopm/.claude/scripts/azure/blocked.js +13 -13
  15. package/autopm/.claude/scripts/azure/daily.js +1 -1
  16. package/autopm/.claude/scripts/azure/dashboard.js +1 -1
  17. package/autopm/.claude/scripts/azure/feature-list.js +2 -2
  18. package/autopm/.claude/scripts/azure/feature-status.js +1 -1
  19. package/autopm/.claude/scripts/azure/next-task.js +1 -1
  20. package/autopm/.claude/scripts/azure/search.js +1 -1
  21. package/autopm/.claude/scripts/azure/setup.js +15 -15
  22. package/autopm/.claude/scripts/azure/sprint-report.js +2 -2
  23. package/autopm/.claude/scripts/azure/sync.js +1 -1
  24. package/autopm/.claude/scripts/azure/us-list.js +1 -1
  25. package/autopm/.claude/scripts/azure/us-status.js +1 -1
  26. package/autopm/.claude/scripts/azure/validate.js +13 -13
  27. package/autopm/.claude/scripts/lib/frontmatter-utils.sh +42 -7
  28. package/autopm/.claude/scripts/lib/logging-utils.sh +20 -16
  29. package/autopm/.claude/scripts/lib/validation-utils.sh +1 -1
  30. package/autopm/.claude/scripts/pm/context.js +338 -0
  31. package/autopm/.claude/scripts/pm/issue-sync/format-comment.sh +3 -3
  32. package/autopm/.claude/scripts/pm/lib/README.md +85 -0
  33. package/autopm/.claude/scripts/pm/lib/logger.js +78 -0
  34. package/autopm/.claude/scripts/pm/next.js +25 -1
  35. package/autopm/.claude/scripts/pm/what-next.js +660 -0
  36. package/bin/autopm.js +25 -0
  37. package/bin/commands/team.js +86 -0
  38. package/package.json +1 -1
  39. package/lib/agentExecutor.js.deprecated +0 -101
  40. package/lib/azure/cache.js +0 -80
  41. package/lib/azure/client.js +0 -77
  42. package/lib/azure/formatter.js +0 -177
  43. package/lib/commandHelpers.js +0 -177
  44. package/lib/context/manager.js +0 -290
  45. package/lib/documentation/manager.js +0 -528
  46. package/lib/github/workflow-manager.js +0 -546
  47. package/lib/helpers/azure-batch-api.js +0 -133
  48. package/lib/helpers/azure-cache-manager.js +0 -287
  49. package/lib/helpers/azure-parallel-processor.js +0 -158
  50. package/lib/helpers/azure-work-item-create.js +0 -278
  51. package/lib/helpers/gh-issue-create.js +0 -250
  52. package/lib/helpers/interactive-prompt.js +0 -336
  53. package/lib/helpers/output-manager.js +0 -335
  54. package/lib/helpers/progress-indicator.js +0 -258
  55. package/lib/performance/benchmarker.js +0 -429
  56. package/lib/pm/epic-decomposer.js +0 -273
  57. package/lib/pm/epic-syncer.js +0 -221
  58. package/lib/prdMetadata.js +0 -270
  59. package/lib/providers/azure/index.js +0 -234
  60. package/lib/providers/factory.js +0 -87
  61. package/lib/providers/github/index.js +0 -204
  62. package/lib/providers/interface.js +0 -73
  63. package/lib/python/scaffold-manager.js +0 -576
  64. package/lib/react/scaffold-manager.js +0 -745
  65. package/lib/regression/analyzer.js +0 -578
  66. package/lib/release/manager.js +0 -324
  67. package/lib/tailwind/manager.js +0 -486
  68. package/lib/traefik/manager.js +0 -484
  69. package/lib/utils/colors.js +0 -126
  70. package/lib/utils/config.js +0 -317
  71. package/lib/utils/filesystem.js +0 -316
  72. package/lib/utils/logger.js +0 -135
  73. package/lib/utils/prompts.js +0 -294
  74. package/lib/utils/shell.js +0 -237
  75. package/lib/validators/email-validator.js +0 -337
  76. package/lib/workflow/manager.js +0 -449
@@ -1,745 +0,0 @@
1
- /**
2
- * React Scaffold Manager
3
- * Centralized React application scaffolding functionality
4
- */
5
-
6
- const fs = require('fs').promises;
7
- const path = require('path');
8
-
9
- /**
10
- * Configuration
11
- */
12
- const CONFIG = {
13
- defaults: {
14
- bundler: 'vite',
15
- port: 3000,
16
- testFramework: 'vitest'
17
- }
18
- };
19
-
20
- /**
21
- * Templates
22
- */
23
- const TEMPLATES = {
24
- vitePackage: {
25
- name: 'react-app',
26
- private: true,
27
- version: '0.0.0',
28
- type: 'module',
29
- scripts: {
30
- dev: 'vite',
31
- build: 'vite build',
32
- lint: 'eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0',
33
- preview: 'vite preview',
34
- test: 'vitest'
35
- },
36
- dependencies: {
37
- react: '^18.2.0',
38
- 'react-dom': '^18.2.0'
39
- },
40
- devDependencies: {
41
- '@types/react': '^18.2.43',
42
- '@types/react-dom': '^18.2.17',
43
- '@vitejs/plugin-react': '^4.2.1',
44
- eslint: '^8.55.0',
45
- 'eslint-plugin-react': '^7.33.2',
46
- 'eslint-plugin-react-hooks': '^4.6.0',
47
- 'eslint-plugin-react-refresh': '^0.4.5',
48
- vite: '^5.0.8'
49
- }
50
- }
51
- };
52
-
53
- class ReactScaffoldManager {
54
- constructor(projectRoot = process.cwd()) {
55
- this.projectRoot = projectRoot;
56
- }
57
-
58
- /**
59
- * Creates React app
60
- */
61
- async createApp(name = 'app', options = {}) {
62
- const bundler = options.bundler || CONFIG.defaults.bundler;
63
- const typescript = options.typescript || false;
64
-
65
- const appDir = path.join(this.projectRoot, name);
66
- await fs.mkdir(appDir, { recursive: true });
67
- await fs.mkdir(path.join(appDir, 'src'), { recursive: true });
68
- await fs.mkdir(path.join(appDir, 'public'), { recursive: true });
69
-
70
- // Create package.json
71
- const packageJson = { ...TEMPLATES.vitePackage, name };
72
-
73
- if (typescript) {
74
- packageJson.devDependencies.typescript = '^5.2.2';
75
- packageJson.devDependencies['@typescript-eslint/eslint-plugin'] = '^6.14.0';
76
- packageJson.devDependencies['@typescript-eslint/parser'] = '^6.14.0';
77
- }
78
-
79
- await fs.writeFile(
80
- path.join(appDir, 'package.json'),
81
- JSON.stringify(packageJson, null, 2)
82
- );
83
-
84
- // Create vite.config.js
85
- const viteConfig = `import { defineConfig } from 'vite'
86
- import react from '@vitejs/plugin-react'
87
-
88
- // https://vitejs.dev/config/
89
- export default defineConfig({
90
- plugins: [react()],
91
- server: {
92
- port: ${CONFIG.defaults.port}
93
- }
94
- })
95
- `;
96
-
97
- await fs.writeFile(path.join(appDir, 'vite.config.js'), viteConfig);
98
-
99
- // Create index.html
100
- const indexHtml = `<!doctype html>
101
- <html lang="en">
102
- <head>
103
- <meta charset="UTF-8" />
104
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
105
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
106
- <title>${name}</title>
107
- </head>
108
- <body>
109
- <div id="root"></div>
110
- <script type="module" src="/src/main.jsx"></script>
111
- </body>
112
- </html>
113
- `;
114
-
115
- await fs.writeFile(path.join(appDir, 'index.html'), indexHtml);
116
-
117
- // Create main.jsx
118
- const mainJsx = `import React from 'react'
119
- import ReactDOM from 'react-dom/client'
120
- import App from './App.jsx'
121
- import './index.css'
122
-
123
- ReactDOM.createRoot(document.getElementById('root')).render(
124
- <React.StrictMode>
125
- <App />
126
- </React.StrictMode>,
127
- )
128
- `;
129
-
130
- await fs.writeFile(path.join(appDir, 'src', 'main.jsx'), mainJsx);
131
-
132
- // Create App.jsx
133
- const appJsx = `import { useState } from 'react'
134
- import './App.css'
135
-
136
- function App() {
137
- const [count, setCount] = useState(0)
138
-
139
- return (
140
- <>
141
- <h1>React + Vite</h1>
142
- <div className="card">
143
- <button onClick={() => setCount((count) => count + 1)}>
144
- count is {count}
145
- </button>
146
- </div>
147
- </>
148
- )
149
- }
150
-
151
- export default App
152
- `;
153
-
154
- await fs.writeFile(path.join(appDir, 'src', 'App.jsx'), appJsx);
155
-
156
- // Create basic CSS files
157
- await fs.writeFile(path.join(appDir, 'src', 'index.css'), '/* Global styles */\n');
158
- await fs.writeFile(path.join(appDir, 'src', 'App.css'), '/* App styles */\n');
159
-
160
- if (typescript) {
161
- await this.setupTypeScript(appDir);
162
- }
163
-
164
- return {
165
- name,
166
- bundler,
167
- typescript,
168
- path: appDir
169
- };
170
- }
171
-
172
- /**
173
- * Sets up TypeScript
174
- */
175
- async setupTypeScript(appDir) {
176
- const tsConfig = {
177
- compilerOptions: {
178
- target: 'ES2020',
179
- useDefineForClassFields: true,
180
- lib: ['ES2020', 'DOM', 'DOM.Iterable'],
181
- module: 'ESNext',
182
- skipLibCheck: true,
183
- moduleResolution: 'bundler',
184
- allowImportingTsExtensions: true,
185
- resolveJsonModule: true,
186
- isolatedModules: true,
187
- noEmit: true,
188
- jsx: 'react-jsx',
189
- strict: true,
190
- noUnusedLocals: true,
191
- noUnusedParameters: true,
192
- noFallthroughCasesInSwitch: true
193
- },
194
- include: ['src'],
195
- references: [{ path: './tsconfig.node.json' }]
196
- };
197
-
198
- await fs.writeFile(
199
- path.join(appDir, 'tsconfig.json'),
200
- JSON.stringify(tsConfig, null, 2)
201
- );
202
-
203
- return tsConfig;
204
- }
205
-
206
- /**
207
- * Creates app structure
208
- */
209
- async createStructure() {
210
- const dirs = [
211
- 'src',
212
- 'src/components',
213
- 'src/pages',
214
- 'src/hooks',
215
- 'src/utils',
216
- 'src/services',
217
- 'src/assets',
218
- 'src/assets/images',
219
- 'src/assets/styles',
220
- 'public'
221
- ];
222
-
223
- for (const dir of dirs) {
224
- await fs.mkdir(path.join(this.projectRoot, dir), { recursive: true });
225
- }
226
-
227
- // Create .gitignore
228
- const gitignore = `# Dependencies
229
- node_modules
230
- .pnp
231
- .pnp.js
232
-
233
- # Testing
234
- coverage
235
-
236
- # Production
237
- build
238
- dist
239
-
240
- # Misc
241
- .DS_Store
242
- .env.local
243
- .env.development.local
244
- .env.test.local
245
- .env.production.local
246
-
247
- npm-debug.log*
248
- yarn-debug.log*
249
- yarn-error.log*
250
- pnpm-debug.log*
251
- lerna-debug.log*
252
-
253
- # Editor directories and files
254
- .vscode/*
255
- !.vscode/extensions.json
256
- .idea
257
- *.suo
258
- *.ntvs*
259
- *.njsproj
260
- *.sln
261
- *.sw?
262
- `;
263
-
264
- await fs.writeFile(path.join(this.projectRoot, '.gitignore'), gitignore);
265
-
266
- return {
267
- directories: dirs,
268
- gitignore: true
269
- };
270
- }
271
-
272
- /**
273
- * Creates component
274
- */
275
- async createComponent(name = 'Component', options = {}) {
276
- const type = options.type || 'functional';
277
- const styled = options.styled || false;
278
- const typescript = options.typescript || false;
279
- const ext = typescript ? 'tsx' : 'jsx';
280
-
281
- const componentsDir = path.join(this.projectRoot, 'src', 'components');
282
- await fs.mkdir(componentsDir, { recursive: true });
283
-
284
- let componentCode;
285
-
286
- if (type === 'functional') {
287
- componentCode = `import React from 'react';
288
- ${styled ? `import './${name}.css';` : ''}
289
-
290
- const ${name} = (props) => {
291
- return (
292
- <div className="${name.toLowerCase()}">
293
- <h2>${name}</h2>
294
- {props.children}
295
- </div>
296
- );
297
- };
298
-
299
- export default ${name};
300
- `;
301
- } else {
302
- componentCode = `import React, { Component } from 'react';
303
- ${styled ? `import './${name}.css';` : ''}
304
-
305
- class ${name} extends Component {
306
- render() {
307
- return (
308
- <div className="${name.toLowerCase()}">
309
- <h2>${name}</h2>
310
- {this.props.children}
311
- </div>
312
- );
313
- }
314
- }
315
-
316
- export default ${name};
317
- `;
318
- }
319
-
320
- await fs.writeFile(
321
- path.join(componentsDir, `${name}.${ext}`),
322
- componentCode
323
- );
324
-
325
- if (styled) {
326
- const styleContent = `.${name.toLowerCase()} {
327
- /* ${name} styles */
328
- padding: 1rem;
329
- margin: 1rem 0;
330
- }
331
- `;
332
- await fs.writeFile(
333
- path.join(componentsDir, `${name}.css`),
334
- styleContent
335
- );
336
- }
337
-
338
- // Create test file
339
- const testContent = `import { render, screen } from '@testing-library/react';
340
- import ${name} from './${name}';
341
-
342
- describe('${name}', () => {
343
- it('renders ${name} component', () => {
344
- render(<${name} />);
345
- const element = screen.getByText('${name}');
346
- expect(element).toBeInTheDocument();
347
- });
348
- });
349
- `;
350
-
351
- await fs.writeFile(
352
- path.join(componentsDir, `${name}.test.${ext}`),
353
- testContent
354
- );
355
-
356
- return {
357
- name,
358
- type,
359
- path: `src/components/${name}.${ext}`,
360
- styled,
361
- test: `src/components/${name}.test.${ext}`
362
- };
363
- }
364
-
365
- /**
366
- * Sets up state management
367
- */
368
- async setupStore(type = 'redux') {
369
- const storeDir = path.join(this.projectRoot, 'src', 'store');
370
- await fs.mkdir(storeDir, { recursive: true });
371
-
372
- if (type === 'redux') {
373
- return await this.setupReduxStore(storeDir);
374
- } else if (type === 'zustand') {
375
- return await this.setupZustandStore(storeDir);
376
- } else {
377
- throw new Error(`Unknown store type: ${type}`);
378
- }
379
- }
380
-
381
- /**
382
- * Sets up Redux store
383
- */
384
- async setupReduxStore(storeDir) {
385
- const storeConfig = `import { configureStore } from '@reduxjs/toolkit';
386
- import rootReducer from './reducers';
387
-
388
- export const store = configureStore({
389
- reducer: rootReducer,
390
- });
391
-
392
- export type RootState = ReturnType<typeof store.getState>;
393
- export type AppDispatch = typeof store.dispatch;
394
- `;
395
-
396
- await fs.writeFile(path.join(storeDir, 'index.js'), storeConfig);
397
-
398
- // Create reducers directory
399
- await fs.mkdir(path.join(storeDir, 'reducers'), { recursive: true });
400
-
401
- const rootReducer = `import { combineReducers } from '@reduxjs/toolkit';
402
-
403
- const rootReducer = combineReducers({
404
- // Add your reducers here
405
- });
406
-
407
- export default rootReducer;
408
- `;
409
-
410
- await fs.writeFile(path.join(storeDir, 'reducers', 'index.js'), rootReducer);
411
-
412
- // Create example slice
413
- const exampleSlice = `import { createSlice } from '@reduxjs/toolkit';
414
-
415
- const initialState = {
416
- value: 0,
417
- };
418
-
419
- export const counterSlice = createSlice({
420
- name: 'counter',
421
- initialState,
422
- reducers: {
423
- increment: (state) => {
424
- state.value += 1;
425
- },
426
- decrement: (state) => {
427
- state.value -= 1;
428
- },
429
- incrementByAmount: (state, action) => {
430
- state.value += action.payload;
431
- },
432
- },
433
- });
434
-
435
- export const { increment, decrement, incrementByAmount } = counterSlice.actions;
436
- export default counterSlice.reducer;
437
- `;
438
-
439
- await fs.writeFile(path.join(storeDir, 'counterSlice.js'), exampleSlice);
440
-
441
- return {
442
- type: 'redux',
443
- store: 'src/store/index.js',
444
- reducers: 'src/store/reducers/',
445
- example: 'src/store/counterSlice.js'
446
- };
447
- }
448
-
449
- /**
450
- * Sets up Zustand store
451
- */
452
- async setupZustandStore(storeDir) {
453
- const zustandStore = `import { create } from 'zustand';
454
- import { devtools, persist } from 'zustand/middleware';
455
-
456
- interface StoreState {
457
- count: number;
458
- increment: () => void;
459
- decrement: () => void;
460
- reset: () => void;
461
- }
462
-
463
- const useStore = create<StoreState>()(
464
- devtools(
465
- persist(
466
- (set) => ({
467
- count: 0,
468
- increment: () => set((state) => ({ count: state.count + 1 })),
469
- decrement: () => set((state) => ({ count: state.count - 1 })),
470
- reset: () => set({ count: 0 }),
471
- }),
472
- {
473
- name: 'app-storage',
474
- }
475
- )
476
- )
477
- );
478
-
479
- export default useStore;
480
- `;
481
-
482
- await fs.writeFile(path.join(storeDir, 'index.js'), zustandStore);
483
-
484
- return {
485
- type: 'zustand',
486
- store: 'src/store/index.js'
487
- };
488
- }
489
-
490
- /**
491
- * Sets up routing
492
- */
493
- async setupRouting() {
494
- const srcDir = path.join(this.projectRoot, 'src');
495
- await fs.mkdir(srcDir, { recursive: true });
496
-
497
- // Create router configuration
498
- const routerConfig = `import { createBrowserRouter, RouterProvider } from 'react-router-dom';
499
- import Layout from './components/Layout';
500
- import HomePage from './pages/HomePage';
501
- import AboutPage from './pages/AboutPage';
502
- import NotFoundPage from './pages/NotFoundPage';
503
-
504
- const router = createBrowserRouter([
505
- {
506
- path: '/',
507
- element: <Layout />,
508
- children: [
509
- {
510
- index: true,
511
- element: <HomePage />,
512
- },
513
- {
514
- path: 'about',
515
- element: <AboutPage />,
516
- },
517
- {
518
- path: '*',
519
- element: <NotFoundPage />,
520
- },
521
- ],
522
- },
523
- ]);
524
-
525
- function Router() {
526
- return <RouterProvider router={router} />;
527
- }
528
-
529
- export default Router;
530
- `;
531
-
532
- await fs.writeFile(path.join(srcDir, 'router.jsx'), routerConfig);
533
-
534
- // Create pages
535
- await this.createPages();
536
-
537
- // Create Layout component
538
- await this.createLayoutComponent();
539
-
540
- return {
541
- router: 'src/router.jsx',
542
- pages: ['HomePage', 'AboutPage', 'NotFoundPage'],
543
- layout: 'src/components/Layout.jsx'
544
- };
545
- }
546
-
547
- /**
548
- * Creates page components
549
- */
550
- async createPages() {
551
- const pagesDir = path.join(this.projectRoot, 'src', 'pages');
552
- await fs.mkdir(pagesDir, { recursive: true });
553
-
554
- const pages = {
555
- HomePage: `import React from 'react';
556
-
557
- const HomePage = () => {
558
- return (
559
- <div>
560
- <h1>Home Page</h1>
561
- <p>Welcome to the React app!</p>
562
- </div>
563
- );
564
- };
565
-
566
- export default HomePage;
567
- `,
568
- AboutPage: `import React from 'react';
569
-
570
- const AboutPage = () => {
571
- return (
572
- <div>
573
- <h1>About Page</h1>
574
- <p>This is the about page.</p>
575
- </div>
576
- );
577
- };
578
-
579
- export default AboutPage;
580
- `,
581
- NotFoundPage: `import React from 'react';
582
-
583
- const NotFoundPage = () => {
584
- return (
585
- <div>
586
- <h1>404 - Page Not Found</h1>
587
- <p>The page you are looking for does not exist.</p>
588
- </div>
589
- );
590
- };
591
-
592
- export default NotFoundPage;
593
- `
594
- };
595
-
596
- for (const [name, content] of Object.entries(pages)) {
597
- await fs.writeFile(path.join(pagesDir, `${name}.jsx`), content);
598
- }
599
- }
600
-
601
- /**
602
- * Creates Layout component
603
- */
604
- async createLayoutComponent() {
605
- const componentsDir = path.join(this.projectRoot, 'src', 'components');
606
- await fs.mkdir(componentsDir, { recursive: true });
607
-
608
- const layout = `import React from 'react';
609
- import { Outlet, Link } from 'react-router-dom';
610
-
611
- const Layout = () => {
612
- return (
613
- <div>
614
- <nav>
615
- <ul>
616
- <li><Link to="/">Home</Link></li>
617
- <li><Link to="/about">About</Link></li>
618
- </ul>
619
- </nav>
620
- <main>
621
- <Outlet />
622
- </main>
623
- </div>
624
- );
625
- };
626
-
627
- export default Layout;
628
- `;
629
-
630
- await fs.writeFile(path.join(componentsDir, 'Layout.jsx'), layout);
631
- }
632
-
633
- /**
634
- * Sets up testing
635
- */
636
- async setupTesting(framework = CONFIG.defaults.testFramework) {
637
- if (framework === 'vitest') {
638
- return await this.setupVitest();
639
- } else if (framework === 'jest') {
640
- return await this.setupJest();
641
- } else {
642
- throw new Error(`Unknown test framework: ${framework}`);
643
- }
644
- }
645
-
646
- /**
647
- * Sets up Vitest
648
- */
649
- async setupVitest() {
650
- const vitestConfig = `/// <reference types="vitest" />
651
- import { defineConfig } from 'vite';
652
- import react from '@vitejs/plugin-react';
653
-
654
- export default defineConfig({
655
- plugins: [react()],
656
- test: {
657
- globals: true,
658
- environment: 'jsdom',
659
- setupFiles: './src/test/setup.js',
660
- coverage: {
661
- provider: 'v8',
662
- reporter: ['text', 'json', 'html'],
663
- },
664
- },
665
- });
666
- `;
667
-
668
- await fs.writeFile(
669
- path.join(this.projectRoot, 'vitest.config.js'),
670
- vitestConfig
671
- );
672
-
673
- // Create test setup
674
- const testDir = path.join(this.projectRoot, 'src', 'test');
675
- await fs.mkdir(testDir, { recursive: true });
676
-
677
- const setupFile = `import '@testing-library/jest-dom';
678
- import { cleanup } from '@testing-library/react';
679
- import { afterEach } from 'vitest';
680
-
681
- // Cleanup after each test
682
- afterEach(() => {
683
- cleanup();
684
- });
685
- `;
686
-
687
- await fs.writeFile(path.join(testDir, 'setup.js'), setupFile);
688
-
689
- // Create example test
690
- const exampleTest = `import { describe, it, expect } from 'vitest';
691
- import { render, screen } from '@testing-library/react';
692
- import App from '../App';
693
-
694
- describe('App', () => {
695
- it('renders headline', () => {
696
- render(<App />);
697
- const headline = screen.getByText(/React/i);
698
- expect(headline).toBeInTheDocument();
699
- });
700
- });
701
- `;
702
-
703
- await fs.writeFile(path.join(testDir, 'App.test.jsx'), exampleTest);
704
-
705
- return {
706
- framework: 'vitest',
707
- config: 'vitest.config.js',
708
- setup: 'src/test/setup.js',
709
- example: 'src/test/App.test.jsx'
710
- };
711
- }
712
-
713
- /**
714
- * Sets up Jest
715
- */
716
- async setupJest() {
717
- const jestConfig = {
718
- testEnvironment: 'jsdom',
719
- setupFilesAfterEnv: ['<rootDir>/src/test/setup.js'],
720
- moduleNameMapper: {
721
- '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
722
- },
723
- transform: {
724
- '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', {
725
- presets: [
726
- ['@babel/preset-env', { targets: { node: 'current' } }],
727
- '@babel/preset-react',
728
- ],
729
- }],
730
- },
731
- };
732
-
733
- await fs.writeFile(
734
- path.join(this.projectRoot, 'jest.config.json'),
735
- JSON.stringify(jestConfig, null, 2)
736
- );
737
-
738
- return {
739
- framework: 'jest',
740
- config: 'jest.config.json'
741
- };
742
- }
743
- }
744
-
745
- module.exports = ReactScaffoldManager;