test-gen-js 0.1.1

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 (72) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/LICENSE +22 -0
  3. package/README.md +538 -0
  4. package/bin/cli.js +4 -0
  5. package/dist/analyzer/componentAnalyzer.d.ts +12 -0
  6. package/dist/analyzer/componentAnalyzer.d.ts.map +1 -0
  7. package/dist/analyzer/componentAnalyzer.js +223 -0
  8. package/dist/analyzer/componentAnalyzer.js.map +1 -0
  9. package/dist/analyzer/fileAnalyzer.d.ts +17 -0
  10. package/dist/analyzer/fileAnalyzer.d.ts.map +1 -0
  11. package/dist/analyzer/fileAnalyzer.js +201 -0
  12. package/dist/analyzer/fileAnalyzer.js.map +1 -0
  13. package/dist/analyzer/functionAnalyzer.d.ts +12 -0
  14. package/dist/analyzer/functionAnalyzer.d.ts.map +1 -0
  15. package/dist/analyzer/functionAnalyzer.js +184 -0
  16. package/dist/analyzer/functionAnalyzer.js.map +1 -0
  17. package/dist/analyzer/index.d.ts +7 -0
  18. package/dist/analyzer/index.d.ts.map +1 -0
  19. package/dist/analyzer/index.js +14 -0
  20. package/dist/analyzer/index.js.map +1 -0
  21. package/dist/cli.d.ts +3 -0
  22. package/dist/cli.d.ts.map +1 -0
  23. package/dist/cli.js +113 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/generator/index.d.ts +6 -0
  26. package/dist/generator/index.d.ts.map +1 -0
  27. package/dist/generator/index.js +12 -0
  28. package/dist/generator/index.js.map +1 -0
  29. package/dist/generator/mockGenerator.d.ts +14 -0
  30. package/dist/generator/mockGenerator.d.ts.map +1 -0
  31. package/dist/generator/mockGenerator.js +123 -0
  32. package/dist/generator/mockGenerator.js.map +1 -0
  33. package/dist/generator/testGenerator.d.ts +14 -0
  34. package/dist/generator/testGenerator.d.ts.map +1 -0
  35. package/dist/generator/testGenerator.js +301 -0
  36. package/dist/generator/testGenerator.js.map +1 -0
  37. package/dist/index.d.ts +9 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +32 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/parser/astParser.d.ts +15 -0
  42. package/dist/parser/astParser.d.ts.map +1 -0
  43. package/dist/parser/astParser.js +100 -0
  44. package/dist/parser/astParser.js.map +1 -0
  45. package/dist/parser/index.d.ts +6 -0
  46. package/dist/parser/index.d.ts.map +1 -0
  47. package/dist/parser/index.js +12 -0
  48. package/dist/parser/index.js.map +1 -0
  49. package/dist/parser/typeExtractor.d.ts +14 -0
  50. package/dist/parser/typeExtractor.d.ts.map +1 -0
  51. package/dist/parser/typeExtractor.js +165 -0
  52. package/dist/parser/typeExtractor.js.map +1 -0
  53. package/dist/templates/component.ejs +67 -0
  54. package/dist/templates/function.ejs +59 -0
  55. package/dist/templates/snapshot.ejs +48 -0
  56. package/dist/types.d.ts +95 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +6 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/utils/fileUtils.d.ts +43 -0
  61. package/dist/utils/fileUtils.d.ts.map +1 -0
  62. package/dist/utils/fileUtils.js +109 -0
  63. package/dist/utils/fileUtils.js.map +1 -0
  64. package/dist/utils/index.d.ts +6 -0
  65. package/dist/utils/index.d.ts.map +1 -0
  66. package/dist/utils/index.js +22 -0
  67. package/dist/utils/index.js.map +1 -0
  68. package/dist/utils/naming.d.ts +37 -0
  69. package/dist/utils/naming.d.ts.map +1 -0
  70. package/dist/utils/naming.js +73 -0
  71. package/dist/utils/naming.js.map +1 -0
  72. package/package.json +84 -0
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Analyzer module - Analyzes parsed AST to extract component/function information
3
+ */
4
+ export { analyzeFile, analyzeDirectory } from './fileAnalyzer';
5
+ export { analyzeComponent } from './componentAnalyzer';
6
+ export { analyzeFunction } from './functionAnalyzer';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * Analyzer module - Analyzes parsed AST to extract component/function information
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.analyzeFunction = exports.analyzeComponent = exports.analyzeDirectory = exports.analyzeFile = void 0;
7
+ var fileAnalyzer_1 = require("./fileAnalyzer");
8
+ Object.defineProperty(exports, "analyzeFile", { enumerable: true, get: function () { return fileAnalyzer_1.analyzeFile; } });
9
+ Object.defineProperty(exports, "analyzeDirectory", { enumerable: true, get: function () { return fileAnalyzer_1.analyzeDirectory; } });
10
+ var componentAnalyzer_1 = require("./componentAnalyzer");
11
+ Object.defineProperty(exports, "analyzeComponent", { enumerable: true, get: function () { return componentAnalyzer_1.analyzeComponent; } });
12
+ var functionAnalyzer_1 = require("./functionAnalyzer");
13
+ Object.defineProperty(exports, "analyzeFunction", { enumerable: true, get: function () { return functionAnalyzer_1.analyzeFunction; } });
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,+CAA+D;AAAtD,2GAAA,WAAW,OAAA;AAAE,gHAAA,gBAAgB,OAAA;AACtC,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA;AACzB,uDAAqD;AAA5C,mHAAA,eAAe,OAAA"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const ora_1 = __importDefault(require("ora"));
10
+ const analyzer_1 = require("./analyzer");
11
+ const generator_1 = require("./generator");
12
+ const program = new commander_1.Command();
13
+ program
14
+ .name('test-gen-js')
15
+ .description('Auto-generate test boilerplate code for JavaScript/TypeScript projects')
16
+ .version('0.1.0');
17
+ // Generate command
18
+ program
19
+ .command('generate <file>')
20
+ .alias('g')
21
+ .description('Generate test file for a component or function')
22
+ .option('-o, --output <path>', 'Output path for test file')
23
+ .option('-t, --template <type>', 'Template type: component | function | hook', 'auto')
24
+ .option('--snapshot', 'Include snapshot tests', false)
25
+ .option('--mock', 'Auto-generate mocks for dependencies', true)
26
+ .option('--overwrite', 'Overwrite existing test file', false)
27
+ .action(async (file, options) => {
28
+ const spinner = (0, ora_1.default)('Analyzing file...').start();
29
+ try {
30
+ // Analyze the source file
31
+ const analysis = await (0, analyzer_1.analyzeFile)(file);
32
+ spinner.text = 'Generating tests...';
33
+ // Generate test code
34
+ const result = await (0, generator_1.generateTest)(analysis, {
35
+ output: options.output,
36
+ snapshot: options.snapshot,
37
+ mock: options.mock,
38
+ overwrite: options.overwrite,
39
+ });
40
+ spinner.succeed(chalk_1.default.green('Test file generated!'));
41
+ console.log('');
42
+ console.log(chalk_1.default.cyan('📄 Source:'), file);
43
+ console.log(chalk_1.default.cyan('📝 Output:'), result.outputPath);
44
+ console.log(chalk_1.default.cyan('📊 Action:'), result.action);
45
+ console.log('');
46
+ if (analysis.components.length > 0) {
47
+ console.log(chalk_1.default.yellow('Components found:'));
48
+ analysis.components.forEach((c) => {
49
+ console.log(` - ${c.name} (${c.props.length} props, ${c.hooks.length} hooks)`);
50
+ });
51
+ }
52
+ if (analysis.functions.length > 0) {
53
+ console.log(chalk_1.default.yellow('Functions found:'));
54
+ analysis.functions.forEach((f) => {
55
+ console.log(` - ${f.name}(${f.params.map((p) => p.name).join(', ')})`);
56
+ });
57
+ }
58
+ }
59
+ catch (error) {
60
+ spinner.fail(chalk_1.default.red('Failed to generate tests'));
61
+ if (error instanceof Error) {
62
+ console.error(chalk_1.default.red(error.message));
63
+ }
64
+ process.exit(1);
65
+ }
66
+ });
67
+ // Scan command
68
+ program
69
+ .command('scan <directory>')
70
+ .alias('s')
71
+ .description('Scan directory and generate tests for all files')
72
+ .option('--dry-run', 'Preview without creating files', false)
73
+ .option('--pattern <glob>', 'File pattern to match', '**/*.{ts,tsx,js,jsx}')
74
+ .option('--exclude <patterns...>', 'Patterns to exclude', ['node_modules', 'dist', '*.test.*', '*.spec.*'])
75
+ .action(async (directory, options) => {
76
+ const spinner = (0, ora_1.default)('Scanning directory...').start();
77
+ try {
78
+ // TODO: Implement directory scanning
79
+ spinner.info(chalk_1.default.yellow('Directory scanning is coming in v0.2.0'));
80
+ console.log('');
81
+ console.log(chalk_1.default.cyan('Directory:'), directory);
82
+ console.log(chalk_1.default.cyan('Pattern:'), options.pattern);
83
+ console.log(chalk_1.default.cyan('Exclude:'), options.exclude.join(', '));
84
+ console.log(chalk_1.default.cyan('Dry run:'), options.dryRun);
85
+ }
86
+ catch (error) {
87
+ spinner.fail(chalk_1.default.red('Failed to scan directory'));
88
+ if (error instanceof Error) {
89
+ console.error(chalk_1.default.red(error.message));
90
+ }
91
+ process.exit(1);
92
+ }
93
+ });
94
+ // Init command
95
+ program
96
+ .command('init')
97
+ .description('Initialize test-gen-js configuration')
98
+ .action(async () => {
99
+ const spinner = (0, ora_1.default)('Creating configuration...').start();
100
+ try {
101
+ // TODO: Implement config initialization
102
+ spinner.info(chalk_1.default.yellow('Configuration file is coming in v0.2.0'));
103
+ }
104
+ catch (error) {
105
+ spinner.fail(chalk_1.default.red('Failed to create configuration'));
106
+ if (error instanceof Error) {
107
+ console.error(chalk_1.default.red(error.message));
108
+ }
109
+ process.exit(1);
110
+ }
111
+ });
112
+ program.parse();
113
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Generator module - Generates test code from analyzed information
3
+ */
4
+ export { generateTest, generateTests } from './testGenerator';
5
+ export { generateMocks } from './mockGenerator';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * Generator module - Generates test code from analyzed information
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateMocks = exports.generateTests = exports.generateTest = void 0;
7
+ var testGenerator_1 = require("./testGenerator");
8
+ Object.defineProperty(exports, "generateTest", { enumerable: true, get: function () { return testGenerator_1.generateTest; } });
9
+ Object.defineProperty(exports, "generateTests", { enumerable: true, get: function () { return testGenerator_1.generateTests; } });
10
+ var mockGenerator_1 = require("./mockGenerator");
11
+ Object.defineProperty(exports, "generateMocks", { enumerable: true, get: function () { return mockGenerator_1.generateMocks; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,iDAA8D;AAArD,6GAAA,YAAY,OAAA;AAAE,8GAAA,aAAa,OAAA;AACpC,iDAAgD;AAAvC,8GAAA,aAAa,OAAA"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Mock Generator
3
+ * Generates mock code for dependencies
4
+ */
5
+ import type { ImportInfo } from '../types';
6
+ /**
7
+ * Generate mock statements for imports
8
+ */
9
+ export declare function generateMocks(imports: ImportInfo[]): string[];
10
+ /**
11
+ * Generate mock for a hook
12
+ */
13
+ export declare function generateHookMock(hookName: string): string;
14
+ //# sourceMappingURL=mockGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockGenerator.d.ts","sourceRoot":"","sources":["../../src/generator/mockGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,CAW7D;AAmGD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYzD"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ /**
3
+ * Mock Generator
4
+ * Generates mock code for dependencies
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.generateMocks = generateMocks;
8
+ exports.generateHookMock = generateHookMock;
9
+ /**
10
+ * Generate mock statements for imports
11
+ */
12
+ function generateMocks(imports) {
13
+ const mocks = [];
14
+ for (const imp of imports) {
15
+ const mock = generateMockForImport(imp);
16
+ if (mock) {
17
+ mocks.push(mock);
18
+ }
19
+ }
20
+ return mocks;
21
+ }
22
+ /**
23
+ * Generate mock for a single import
24
+ */
25
+ function generateMockForImport(imp) {
26
+ // Skip React and testing library imports
27
+ if (shouldSkipMock(imp.source)) {
28
+ return null;
29
+ }
30
+ // Navigation mocks
31
+ if (imp.source === '@react-navigation/native') {
32
+ return `jest.mock('@react-navigation/native', () => ({
33
+ useNavigation: () => ({
34
+ navigate: jest.fn(),
35
+ goBack: jest.fn(),
36
+ reset: jest.fn(),
37
+ }),
38
+ useRoute: () => ({
39
+ params: {},
40
+ }),
41
+ useFocusEffect: jest.fn(),
42
+ }));`;
43
+ }
44
+ if (imp.source === '@react-navigation/stack') {
45
+ return `jest.mock('@react-navigation/stack', () => ({
46
+ createStackNavigator: jest.fn(() => ({
47
+ Navigator: ({ children }: any) => children,
48
+ Screen: ({ children }: any) => children,
49
+ })),
50
+ }));`;
51
+ }
52
+ // Redux mocks
53
+ if (imp.source === 'react-redux') {
54
+ return `jest.mock('react-redux', () => ({
55
+ useSelector: jest.fn(),
56
+ useDispatch: () => jest.fn(),
57
+ Provider: ({ children }: any) => children,
58
+ }));`;
59
+ }
60
+ // Async storage mock
61
+ if (imp.source === '@react-native-async-storage/async-storage') {
62
+ return `jest.mock('@react-native-async-storage/async-storage', () => ({
63
+ setItem: jest.fn(() => Promise.resolve()),
64
+ getItem: jest.fn(() => Promise.resolve(null)),
65
+ removeItem: jest.fn(() => Promise.resolve()),
66
+ clear: jest.fn(() => Promise.resolve()),
67
+ }));`;
68
+ }
69
+ // Animated mock for React Native
70
+ if (imp.source === 'react-native' && imp.specifiers.includes('Animated')) {
71
+ return `jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');`;
72
+ }
73
+ // Generic mock for other imports
74
+ if (imp.source.startsWith('.') || imp.source.startsWith('@/') || imp.source.startsWith('~/')) {
75
+ // Local imports - generate basic mock
76
+ const mockExports = imp.specifiers
77
+ .map((spec) => {
78
+ if (spec.startsWith('* as')) {
79
+ return null;
80
+ }
81
+ return ` ${spec}: jest.fn()`;
82
+ })
83
+ .filter(Boolean)
84
+ .join(',\n');
85
+ if (mockExports) {
86
+ return `jest.mock('${imp.source}', () => ({
87
+ ${mockExports},
88
+ }));`;
89
+ }
90
+ }
91
+ return null;
92
+ }
93
+ /**
94
+ * Check if import should be skipped for mocking
95
+ */
96
+ function shouldSkipMock(source) {
97
+ const skipList = [
98
+ 'react',
99
+ 'react-native',
100
+ '@testing-library/react',
101
+ '@testing-library/react-native',
102
+ '@testing-library/jest-native',
103
+ 'jest',
104
+ '@jest',
105
+ ];
106
+ return skipList.some((skip) => source === skip || source.startsWith(`${skip}/`));
107
+ }
108
+ /**
109
+ * Generate mock for a hook
110
+ */
111
+ function generateHookMock(hookName) {
112
+ // Common hooks
113
+ const hookMocks = {
114
+ useState: `jest.spyOn(React, 'useState').mockImplementation((init) => [init, jest.fn()]);`,
115
+ useEffect: `jest.spyOn(React, 'useEffect').mockImplementation((f) => f());`,
116
+ useContext: `jest.spyOn(React, 'useContext').mockReturnValue({});`,
117
+ useRef: `jest.spyOn(React, 'useRef').mockReturnValue({ current: null });`,
118
+ useMemo: `jest.spyOn(React, 'useMemo').mockImplementation((f) => f());`,
119
+ useCallback: `jest.spyOn(React, 'useCallback').mockImplementation((f) => f);`,
120
+ };
121
+ return hookMocks[hookName] || `// TODO: Mock ${hookName}`;
122
+ }
123
+ //# sourceMappingURL=mockGenerator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockGenerator.js","sourceRoot":"","sources":["../../src/generator/mockGenerator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Test Generator
3
+ * Generates test code from analyzed file information
4
+ */
5
+ import type { FileAnalysis, GeneratorOptions, GeneratedTest } from '../types';
6
+ /**
7
+ * Generate test for a single file analysis
8
+ */
9
+ export declare function generateTest(analysis: FileAnalysis, options?: GeneratorOptions): Promise<GeneratedTest>;
10
+ /**
11
+ * Generate tests for multiple file analyses
12
+ */
13
+ export declare function generateTests(analyses: FileAnalysis[], options?: GeneratorOptions): Promise<GeneratedTest[]>;
14
+ //# sourceMappingURL=testGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testGenerator.d.ts","sourceRoot":"","sources":["../../src/generator/testGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAM9E;;GAEG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,YAAY,EACtB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,aAAa,CAAC,CA+CxB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,YAAY,EAAE,EACxB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,aAAa,EAAE,CAAC,CAS1B"}
@@ -0,0 +1,301 @@
1
+ "use strict";
2
+ /**
3
+ * Test Generator
4
+ * Generates test code from analyzed file information
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.generateTest = generateTest;
11
+ exports.generateTests = generateTests;
12
+ const ejs_1 = __importDefault(require("ejs"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const fs_extra_1 = __importDefault(require("fs-extra"));
15
+ const typeExtractor_1 = require("../parser/typeExtractor");
16
+ // Templates directory
17
+ const TEMPLATES_DIR = path_1.default.join(__dirname, '../templates');
18
+ /**
19
+ * Generate test for a single file analysis
20
+ */
21
+ async function generateTest(analysis, options = {}) {
22
+ const { output, snapshot = false, mock = true, testSuffix = '.test', overwrite = false, } = options;
23
+ // Determine output path
24
+ const ext = path_1.default.extname(analysis.filePath);
25
+ const baseName = path_1.default.basename(analysis.filePath, ext);
26
+ const dirName = path_1.default.dirname(analysis.filePath);
27
+ const outputPath = output || path_1.default.join(dirName, `${baseName}${testSuffix}${ext}`);
28
+ // Check if file exists
29
+ const exists = await fs_extra_1.default.pathExists(outputPath);
30
+ if (exists && !overwrite) {
31
+ return {
32
+ code: '',
33
+ outputPath,
34
+ sourcePath: analysis.filePath,
35
+ action: 'skipped',
36
+ };
37
+ }
38
+ // Generate test code
39
+ let code;
40
+ if (analysis.components.length > 0) {
41
+ code = await generateComponentTest(analysis, { snapshot, mock });
42
+ }
43
+ else if (analysis.functions.length > 0) {
44
+ code = await generateFunctionTest(analysis, { mock });
45
+ }
46
+ else {
47
+ throw new Error('No components or functions found to generate tests for');
48
+ }
49
+ // Write to file
50
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(outputPath));
51
+ await fs_extra_1.default.writeFile(outputPath, code, 'utf-8');
52
+ return {
53
+ code,
54
+ outputPath,
55
+ sourcePath: analysis.filePath,
56
+ action: exists ? 'updated' : 'created',
57
+ };
58
+ }
59
+ /**
60
+ * Generate tests for multiple file analyses
61
+ */
62
+ async function generateTests(analyses, options = {}) {
63
+ const results = [];
64
+ for (const analysis of analyses) {
65
+ const result = await generateTest(analysis, options);
66
+ results.push(result);
67
+ }
68
+ return results;
69
+ }
70
+ /**
71
+ * Generate test code for components
72
+ */
73
+ async function generateComponentTest(analysis, options) {
74
+ const templatePath = path_1.default.join(TEMPLATES_DIR, 'component.ejs');
75
+ // Check if custom template exists, otherwise use default
76
+ let template;
77
+ if (await fs_extra_1.default.pathExists(templatePath)) {
78
+ template = await fs_extra_1.default.readFile(templatePath, 'utf-8');
79
+ }
80
+ else {
81
+ template = getDefaultComponentTemplate();
82
+ }
83
+ // Prepare template data
84
+ const data = {
85
+ analysis,
86
+ options,
87
+ helpers: {
88
+ generateMockValue: typeExtractor_1.generateMockValue,
89
+ generatePropValue,
90
+ getRelativeImport,
91
+ getTestingLibrary,
92
+ },
93
+ };
94
+ return ejs_1.default.render(template, data);
95
+ }
96
+ /**
97
+ * Generate test code for functions
98
+ */
99
+ async function generateFunctionTest(analysis, options) {
100
+ const templatePath = path_1.default.join(TEMPLATES_DIR, 'function.ejs');
101
+ // Check if custom template exists, otherwise use default
102
+ let template;
103
+ if (await fs_extra_1.default.pathExists(templatePath)) {
104
+ template = await fs_extra_1.default.readFile(templatePath, 'utf-8');
105
+ }
106
+ else {
107
+ template = getDefaultFunctionTemplate();
108
+ }
109
+ // Prepare template data
110
+ const data = {
111
+ analysis,
112
+ options,
113
+ helpers: {
114
+ generateMockValue: typeExtractor_1.generateMockValue,
115
+ getRelativeImport,
116
+ },
117
+ };
118
+ return ejs_1.default.render(template, data);
119
+ }
120
+ /**
121
+ * Generate a prop value for testing
122
+ */
123
+ function generatePropValue(prop) {
124
+ // Event handlers
125
+ if (prop.name.startsWith('on') && prop.name.length > 2) {
126
+ return 'jest.fn()';
127
+ }
128
+ // Common prop patterns
129
+ if (prop.name === 'children')
130
+ return "'Test Children'";
131
+ if (prop.name === 'className' || prop.name === 'style')
132
+ return "{}";
133
+ if (prop.name === 'testID' || prop.name === 'data-testid')
134
+ return "'test-id'";
135
+ if (prop.name.toLowerCase().includes('id'))
136
+ return "'test-id'";
137
+ if (prop.name.toLowerCase().includes('name'))
138
+ return "'Test Name'";
139
+ if (prop.name.toLowerCase().includes('title'))
140
+ return "'Test Title'";
141
+ if (prop.name.toLowerCase().includes('label'))
142
+ return "'Test Label'";
143
+ if (prop.name.toLowerCase().includes('text'))
144
+ return "'Test Text'";
145
+ if (prop.name.toLowerCase().includes('disabled'))
146
+ return 'false';
147
+ if (prop.name.toLowerCase().includes('loading'))
148
+ return 'false';
149
+ if (prop.name.toLowerCase().includes('visible'))
150
+ return 'true';
151
+ if (prop.name.toLowerCase().includes('active'))
152
+ return 'true';
153
+ return (0, typeExtractor_1.generateMockValue)(prop.type);
154
+ }
155
+ /**
156
+ * Get relative import path
157
+ */
158
+ function getRelativeImport(testPath, sourcePath) {
159
+ const relative = path_1.default.relative(path_1.default.dirname(testPath), sourcePath);
160
+ const ext = path_1.default.extname(relative);
161
+ const withoutExt = relative.slice(0, -ext.length);
162
+ // Ensure it starts with ./
163
+ if (!withoutExt.startsWith('.')) {
164
+ return `./${withoutExt}`;
165
+ }
166
+ return withoutExt;
167
+ }
168
+ /**
169
+ * Get the appropriate testing library import based on framework
170
+ */
171
+ function getTestingLibrary(framework) {
172
+ switch (framework) {
173
+ case 'react-native':
174
+ return {
175
+ package: '@testing-library/react-native',
176
+ imports: ['render', 'fireEvent', 'screen', 'waitFor'],
177
+ };
178
+ case 'react':
179
+ return {
180
+ package: '@testing-library/react',
181
+ imports: ['render', 'fireEvent', 'screen', 'waitFor'],
182
+ };
183
+ default:
184
+ return {
185
+ package: '@testing-library/react',
186
+ imports: ['render', 'fireEvent', 'screen', 'waitFor'],
187
+ };
188
+ }
189
+ }
190
+ /**
191
+ * Default component test template
192
+ */
193
+ function getDefaultComponentTemplate() {
194
+ return `<%
195
+ const testLib = helpers.getTestingLibrary(analysis.framework);
196
+ const sourceImport = helpers.getRelativeImport(analysis.filePath.replace(/\\.(tsx?|jsx?)$/, '.test.$1'), analysis.filePath);
197
+ %>
198
+ import React from 'react';
199
+ import { <%= testLib.imports.join(', ') %> } from '<%= testLib.package %>';
200
+ <% analysis.components.forEach(component => { %>
201
+ import { <%= component.name %> } from '<%= sourceImport %>';
202
+ <% }); %>
203
+
204
+ <% analysis.components.forEach(component => { %>
205
+ describe('<%= component.name %>', () => {
206
+ const defaultProps = {
207
+ <% component.props.forEach((prop, index) => { %>
208
+ <%= prop.name %>: <%= helpers.generatePropValue(prop) %><%= index < component.props.length - 1 ? ',' : '' %>
209
+ <% }); %>
210
+ };
211
+
212
+ beforeEach(() => {
213
+ jest.clearAllMocks();
214
+ });
215
+
216
+ it('renders without crashing', () => {
217
+ render(<<%= component.name %> {...defaultProps} />);
218
+ });
219
+
220
+ <% if (options.snapshot) { %>
221
+ it('matches snapshot', () => {
222
+ const { toJSON } = render(<<%= component.name %> {...defaultProps} />);
223
+ expect(toJSON()).toMatchSnapshot();
224
+ });
225
+
226
+ <% } %>
227
+ <% component.events.forEach(event => { %>
228
+ it('calls <%= event %> when triggered', () => {
229
+ const handler = jest.fn();
230
+ render(<<%= component.name %> {...defaultProps} <%= event %>={handler} />);
231
+
232
+ // TODO: Trigger the <%= event %> event
233
+ // fireEvent.press(screen.getByTestId('...'));
234
+
235
+ // expect(handler).toHaveBeenCalled();
236
+ });
237
+
238
+ <% }); %>
239
+ <% component.hooks.forEach(hook => { %>
240
+ // TODO: Test <%= hook %> behavior
241
+ it('uses <%= hook %> correctly', () => {
242
+ render(<<%= component.name %> {...defaultProps} />);
243
+ // Add assertions for <%= hook %>
244
+ });
245
+
246
+ <% }); %>
247
+ });
248
+
249
+ <% }); %>
250
+ `;
251
+ }
252
+ /**
253
+ * Default function test template
254
+ */
255
+ function getDefaultFunctionTemplate() {
256
+ return `<%
257
+ const sourceImport = helpers.getRelativeImport(analysis.filePath.replace(/\\.(tsx?|jsx?)$/, '.test.$1'), analysis.filePath);
258
+ %>
259
+ <% analysis.functions.forEach(func => { %>
260
+ import { <%= func.name %> } from '<%= sourceImport %>';
261
+ <% }); %>
262
+
263
+ <% analysis.functions.forEach(func => { %>
264
+ describe('<%= func.name %>', () => {
265
+ beforeEach(() => {
266
+ jest.clearAllMocks();
267
+ });
268
+
269
+ <% if (func.isAsync) { %>
270
+ it('should resolve successfully', async () => {
271
+ const result = await <%= func.name %>(<%= func.params.map(p => helpers.generateMockValue(p.type)).join(', ') %>);
272
+
273
+ // TODO: Add assertions
274
+ expect(result).toBeDefined();
275
+ });
276
+
277
+ it('should handle errors', async () => {
278
+ // TODO: Mock error scenario
279
+ // await expect(<%= func.name %>()).rejects.toThrow();
280
+ });
281
+ <% } else { %>
282
+ it('should return expected result', () => {
283
+ const result = <%= func.name %>(<%= func.params.map(p => helpers.generateMockValue(p.type)).join(', ') %>);
284
+
285
+ // TODO: Add assertions
286
+ expect(result).toBeDefined();
287
+ });
288
+ <% } %>
289
+
290
+ <% func.params.forEach(param => { %>
291
+ it('should handle <%= param.name %> parameter', () => {
292
+ // TODO: Test with different <%= param.name %> values
293
+ });
294
+
295
+ <% }); %>
296
+ });
297
+
298
+ <% }); %>
299
+ `;
300
+ }
301
+ //# sourceMappingURL=testGenerator.js.map