@dannysir/js-te 0.3.0 → 0.3.2

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.
@@ -0,0 +1,184 @@
1
+
2
+ import {findAbsolutePath, shouldTransform} from "./utils/pathHelper.js";
3
+ import {getModuleInfo} from "./utils/getModuleInfo.js";
4
+ import {createNamespaceWrapper, createOriginalDeclaration, createWrapperFunction} from "./utils/wrapperCreator.js";
5
+ import {BABEL, MOCK} from "../constants/babel.js";
6
+
7
+ export const babelTransformImport = (mockedPaths = null) => {
8
+ return ({types: t}) => {
9
+ return {
10
+ visitor: {
11
+ Program(path) {
12
+ const mockStoreDeclaration = t.VariableDeclaration('const', [
13
+ t.VariableDeclarator(
14
+ t.Identifier(MOCK.STORE_NAME),
15
+ t.MemberExpression(
16
+ t.Identifier('global'),
17
+ t.Identifier(MOCK.STORE_NAME)
18
+ )
19
+ )
20
+ ]);
21
+ path.node.body.unshift(mockStoreDeclaration);
22
+ },
23
+
24
+ ImportDeclaration(nodePath, state) {
25
+ const source = nodePath.node.source.value;
26
+
27
+ if (source === MOCK.STORE_PATH) {
28
+ return;
29
+ }
30
+
31
+ const currentFilePath = state.filename || process.cwd();
32
+ const absolutePath = findAbsolutePath(source, currentFilePath);
33
+
34
+ if (!shouldTransform(absolutePath, mockedPaths)) {
35
+ return;
36
+ }
37
+
38
+ const specifiers = nodePath.node.specifiers;
39
+ const originalVarName = nodePath.scope.generateUidIdentifier('original');
40
+
41
+ /*
42
+
43
+ const _original = await import('./random.js');
44
+ const random = (...args) => {
45
+ const module = mockStore.has('/path/to/random.js')
46
+ ? { ..._original, ...mockStore.get('/path/to/random.js') }
47
+ : _original;
48
+ return module.random(...args);
49
+ };
50
+ */
51
+
52
+ const originalDeclaration = createOriginalDeclaration(
53
+ t,
54
+ originalVarName,
55
+ source,
56
+ false
57
+ );
58
+
59
+ const wrapperDeclarations = specifiers.map(spec => {
60
+ if (t.isImportDefaultSpecifier(spec)) {
61
+ return createWrapperFunction(
62
+ t,
63
+ 'default',
64
+ spec.local.name,
65
+ absolutePath,
66
+ originalVarName
67
+ );
68
+ } else if (t.isImportNamespaceSpecifier(spec)) {
69
+ return createNamespaceWrapper(
70
+ t,
71
+ spec.local.name,
72
+ absolutePath,
73
+ originalVarName
74
+ );
75
+ } else {
76
+ return createWrapperFunction(
77
+ t,
78
+ spec.imported.name,
79
+ spec.local.name,
80
+ absolutePath,
81
+ originalVarName
82
+ );
83
+ }
84
+ });
85
+
86
+ const wrapperDeclaration = t.variableDeclaration(BABEL.CONST, wrapperDeclarations);
87
+
88
+ nodePath.replaceWithMultiple([originalDeclaration, wrapperDeclaration]);
89
+ },
90
+
91
+ VariableDeclaration(nodePath, state) {
92
+ const declarations = nodePath.node.declarations;
93
+
94
+ if (!declarations || declarations.length === 0) {
95
+ return;
96
+ }
97
+
98
+ if (nodePath.node._transformed) {
99
+ return;
100
+ }
101
+
102
+ const newDeclarations = [];
103
+ let hasTransformation = false;
104
+
105
+ for (const declarator of declarations) {
106
+ const requireInfo = getModuleInfo(t, declarator);
107
+
108
+ if (!requireInfo) {
109
+ newDeclarations.push(declarator);
110
+ continue;
111
+ }
112
+
113
+ const {source} = requireInfo;
114
+ const currentFilePath = state.filename || process.cwd();
115
+ const absolutePath = findAbsolutePath(source, currentFilePath);
116
+
117
+ if (!shouldTransform(absolutePath, mockedPaths)) {
118
+ newDeclarations.push(declarator);
119
+ continue;
120
+ }
121
+
122
+ hasTransformation = true;
123
+ const originalVar = nodePath.scope.generateUidIdentifier('original');
124
+
125
+ /*
126
+
127
+ const _original = require('./random');
128
+ const random = (...args) => {
129
+ const module = mockStore.has('/path/to/random.js')
130
+ ? { ..._original, ...mockStore.get('/path/to/random.js') }
131
+ : _original;
132
+ return module.random(...args);
133
+ };
134
+ */
135
+
136
+ newDeclarations.push(
137
+ t.variableDeclarator(
138
+ originalVar,
139
+ t.callExpression(
140
+ t.identifier('require'),
141
+ [t.stringLiteral(source)]
142
+ )
143
+ )
144
+ );
145
+
146
+ if (t.isObjectPattern(declarator.id)) {
147
+ const properties = declarator.id.properties;
148
+
149
+ properties.forEach(prop => {
150
+ const key = prop.key.name;
151
+ const localName = prop.value.name;
152
+
153
+ newDeclarations.push(
154
+ createWrapperFunction(
155
+ t,
156
+ key,
157
+ localName,
158
+ absolutePath,
159
+ originalVar
160
+ )
161
+ );
162
+ });
163
+ } else {
164
+ newDeclarations.push(
165
+ createWrapperFunction(
166
+ t,
167
+ 'default',
168
+ declarator.id.name,
169
+ absolutePath,
170
+ originalVar
171
+ )
172
+ );
173
+ }
174
+ }
175
+
176
+ if (hasTransformation) {
177
+ nodePath.node.declarations = newDeclarations;
178
+ nodePath.node._transformed = true;
179
+ }
180
+ }
181
+ }
182
+ };
183
+ }
184
+ };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * require 호출 정보 추출
3
+ * @param {Object} t - Babel types
4
+ * @param {Object} declarator - VariableDeclarator 노드
5
+ * @returns {Object|null} require 정보 또는 null
6
+ */
7
+ export const getModuleInfo = (t, declarator) => {
8
+ const init = declarator.init;
9
+
10
+ if (!init ||
11
+ !t.isCallExpression(init) ||
12
+ !t.isIdentifier(init.callee, {name: 'require'}) ||
13
+ !init.arguments[0] ||
14
+ !t.isStringLiteral(init.arguments[0])) {
15
+ return null;
16
+ }
17
+
18
+ return {
19
+ source: init.arguments[0].value
20
+ };
21
+ };
@@ -0,0 +1,56 @@
1
+ import path from 'path';
2
+
3
+ import {BABEL} from "../../constants/babel.js";
4
+
5
+ /**
6
+ * 상대/절대 경로를 절대 경로로 변환
7
+ * @param {string} source - import/require 경로
8
+ * @param {string} currentFilePath - 현재 파일의 경로
9
+ * @returns {string} 절대 경로
10
+ *
11
+ * @example
12
+ * // 상대 경로인 경우:
13
+ * resolveAbsolutePath('./random.js', '/Users/san/project/test.js')
14
+ * // 반환: '/Users/san/project/random.js'
15
+ *
16
+ * // 절대 경로인 경우:
17
+ * resolveAbsolutePath('/Users/san/lib/utils.js', '/Users/san/project/test.js')
18
+ * // 반환: '/Users/san/lib/utils.js'
19
+ */
20
+ export const findAbsolutePath = (source, currentFilePath) => {
21
+ const currentDir = path.dirname(currentFilePath || process.cwd());
22
+
23
+ if (source.startsWith(BABEL.PERIOD)) {
24
+ return path.resolve(currentDir, source);
25
+ }
26
+
27
+ return source;
28
+ };
29
+
30
+ /**
31
+ * 해당 경로가 변환 대상인지 확인
32
+ * @param {string} absolutePath - 절대 경로
33
+ * @param {Set<string>|null} mockedPaths - mock된 경로들
34
+ * @returns {boolean}
35
+ *
36
+ * @example
37
+ * // mockedPaths가 null인 경우:
38
+ * shouldTransform('/Users/san/project/random.js', null)
39
+ * // 반환: true (모든 파일 변환)
40
+ *
41
+ * // mockedPaths에 포함된 경우:
42
+ * const mocked = new Set(['/Users/san/project/random.js']);
43
+ * shouldTransform('/Users/san/project/random.js', mocked)
44
+ * // 반환: true (변환 대상)
45
+ *
46
+ * // mockedPaths에 없는 경우:
47
+ * shouldTransform('/Users/san/project/game.js', mocked)
48
+ * // 반환: false (변환하지 않음)
49
+ */
50
+ export const shouldTransform = (absolutePath, mockedPaths) => {
51
+ if (!mockedPaths) {
52
+ return true;
53
+ }
54
+
55
+ return mockedPaths.has(absolutePath);
56
+ };
@@ -0,0 +1,121 @@
1
+
2
+ import {BABEL, MOCK} from "../../constants/babel.js";
3
+
4
+ /**
5
+ * Mock wrapper 함수를 생성하는 헬퍼
6
+ * @param {Object} t - Babel types
7
+ * @param {string} importedName - import된 함수명
8
+ * @param {string} localName - 로컬 변수명
9
+ * @param {string} absolutePath - 모듈의 절대 경로
10
+ * @param {Object} originalVarName - 원본 모듈을 가리키는 변수
11
+ * @returns {Object} 바벨 변수 선언
12
+ *
13
+ * @example
14
+ * // 반환 결과 (코드로 표현하면):
15
+ * const random = (...args) => {
16
+ * const module = mockStore.has('/path/to/random.js')
17
+ * ? { ..._original, ...mockStore.get('/path/to/random.js') }
18
+ * : _original;
19
+ * return module.random(...args);
20
+ * };
21
+ */
22
+ export const createWrapperFunction = (t, importedName, localName, absolutePath, originalVarName) => {
23
+ return t.variableDeclarator(
24
+ t.identifier(localName),
25
+ t.arrowFunctionExpression(
26
+ [t.restElement(t.identifier('args'))],
27
+ t.blockStatement([
28
+ t.variableDeclaration(BABEL.CONST, [
29
+ t.variableDeclarator(
30
+ t.identifier(BABEL.MODULE),
31
+ createConditionalModule(t, absolutePath, originalVarName)
32
+ )
33
+ ]),
34
+ t.returnStatement(
35
+ t.callExpression(
36
+ t.memberExpression(t.identifier(BABEL.MODULE), t.identifier(importedName)),
37
+ [t.spreadElement(t.identifier('args'))]
38
+ )
39
+ )
40
+ ])
41
+ )
42
+ );
43
+ };
44
+
45
+ /**
46
+ * Namespace import용 wrapper 생성
47
+ * @param {Object} t - Babel types
48
+ * @param {string} localName - 로컬 변수명
49
+ * @param {string} absolutePath - 모듈의 절대 경로
50
+ * @param {Object} originalVarName - 원본 모듈 변수
51
+ * @returns {Object} 바벨 변수 선언
52
+ *
53
+ * @example
54
+ * // 반환 결과 (코드로 표현하면):
55
+ * const utils = mockStore.has('/path/to/utils.js')
56
+ * ? { ..._original, ...mockStore.get('/path/to/utils.js') }
57
+ * : _original;
58
+ */
59
+ export const createNamespaceWrapper = (t, localName, absolutePath, originalVarName) => {
60
+ return t.variableDeclarator(
61
+ t.identifier(localName),
62
+ createConditionalModule(t, absolutePath, originalVarName)
63
+ );
64
+ };
65
+
66
+ /**
67
+ * 원본 모듈 선언문 생성
68
+ * @param {Object} t - Babel types
69
+ * @param {Object} originalVarName - 원본 모듈 변수
70
+ * @param {string} source - import 경로
71
+ * @param {boolean} isRequire - require 방식인지 여부
72
+ * @returns {Object} 바벨 변수 선언
73
+ *
74
+ * @example
75
+ * // isRequire = false인 경우 (코드로 표현하면):
76
+ * const _original = await import('./random.js');
77
+ *
78
+ * // isRequire = true인 경우 (코드로 표현하면):
79
+ * const _original = require('./random.js');
80
+ */
81
+ export const createOriginalDeclaration = (t, originalVarName, source, isRequire = false) => {
82
+ const init = isRequire
83
+ ? t.callExpression(t.identifier('require'), [t.stringLiteral(source)])
84
+ : t.awaitExpression(t.importExpression(t.stringLiteral(source)));
85
+
86
+ return t.variableDeclaration(BABEL.CONST, [
87
+ t.variableDeclarator(originalVarName, init)
88
+ ]);
89
+ };
90
+
91
+ /**
92
+ * 조건부 모듈 표현식 생성 (mockStore 체크)
93
+ * @param {Object} t - Babel types
94
+ * @param {string} absolutePath - 모듈의 절대 경로
95
+ * @param {Object} originalVarName - 원본 모듈 변수
96
+ * @returns {Object} 바벨 조건문
97
+ *
98
+ * @example
99
+ * // 반환 결과 (코드로 표현하면):
100
+ * mockStore.has('/path/to/random.js')
101
+ * ? { ..._original, ...mockStore.get('/path/to/random.js') }
102
+ * : _original
103
+ */
104
+ const createConditionalModule = (t, absolutePath, originalVarName) => {
105
+ return t.conditionalExpression(
106
+ t.callExpression(
107
+ t.memberExpression(t.identifier(MOCK.STORE_NAME), t.identifier(BABEL.HAS)),
108
+ [t.stringLiteral(absolutePath)]
109
+ ),
110
+ t.objectExpression([
111
+ t.spreadElement(originalVarName),
112
+ t.spreadElement(
113
+ t.callExpression(
114
+ t.memberExpression(t.identifier(MOCK.STORE_NAME), t.identifier(BABEL.GET)),
115
+ [t.stringLiteral(absolutePath)]
116
+ )
117
+ )
118
+ ]),
119
+ originalVarName
120
+ );
121
+ };
@@ -0,0 +1,22 @@
1
+ import path from 'path';
2
+ import {getFilePath} from "../utils/messages.js";
3
+ import {transformFiles} from "../utils/transformFiles.js";
4
+ import {NUM} from "../constants/index.js";
5
+
6
+ export const runTests = async (jsTe, mockedPaths, testFiles) => {
7
+ let totalPassed = NUM.ZERO;
8
+ let totalFailed = NUM.ZERO;
9
+
10
+ for (const file of testFiles) {
11
+ console.log(getFilePath(file));
12
+ transformFiles(file, mockedPaths);
13
+
14
+ await import(path.resolve(file));
15
+
16
+ const {passed, failed} = await jsTe.run();
17
+ totalPassed += passed;
18
+ totalFailed += failed;
19
+ }
20
+
21
+ return {totalPassed, totalFailed}
22
+ };
@@ -0,0 +1,32 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import {MODULE_TYPE, NUM, PATH} from "../constants/index.js";
4
+
5
+ const getUserModuleType = () => {
6
+ try {
7
+ const pkgPath = path.join(process.cwd(), 'package.json');
8
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
9
+ return pkg.type === MODULE_TYPE.MODULE ? MODULE_TYPE.ESM : MODULE_TYPE.CJS;
10
+ } catch {
11
+ return MODULE_TYPE.CJS;
12
+ }
13
+ };
14
+
15
+ export const setupEnvironment = async () => {
16
+ const moduleType = getUserModuleType();
17
+
18
+ let jsTe;
19
+ if (moduleType === MODULE_TYPE.ESM) {
20
+ jsTe = await import(PATH.DANNYSIR_JS_TE);
21
+ } else {
22
+ const {createRequire} = await import(MODULE_TYPE.MODULE);
23
+ const require = createRequire(import.meta.url);
24
+ jsTe = require(PATH.DANNYSIR_JS_TE);
25
+ }
26
+
27
+ Object.keys(jsTe).forEach(key => {
28
+ global[key] = jsTe[key];
29
+ });
30
+
31
+ return jsTe
32
+ };
@@ -0,0 +1,15 @@
1
+ import {findAllSourceFiles, findTestFiles} from "../utils/findFiles.js";
2
+ import {getFileCountString} from "../utils/messages.js";
3
+ import {collectMockedPaths} from "../mock/collectMocks.js";
4
+ import {transformFiles} from "../utils/transformFiles.js";
5
+
6
+ export const setupFiles = () => {
7
+ const testFiles = findTestFiles(process.cwd());
8
+ const mockedPaths = collectMockedPaths(testFiles);
9
+ const sourceFiles = findAllSourceFiles(process.cwd());
10
+
11
+ for (const file of sourceFiles) {
12
+ transformFiles(file, mockedPaths);
13
+ }
14
+ return {mockedPaths, testFiles}
15
+ };
@@ -0,0 +1,12 @@
1
+ export const MOCK = {
2
+ STORE_NAME: 'mockStore',
3
+ STORE_PATH: '@dannysir/js-te/src/mock/store.js'
4
+ };
5
+
6
+ export const BABEL = {
7
+ MODULE: 'module',
8
+ CONST: 'const',
9
+ HAS: 'has',
10
+ GET: 'get',
11
+ PERIOD: '.',
12
+ };
@@ -0,0 +1,29 @@
1
+ export const PATH = {
2
+ NODE_MODULES: 'node_modules',
3
+ TEST_DIRECTORY: 'test',
4
+ TEST_FILE: '.test.js',
5
+ JAVASCRIPT_FILE: '.js',
6
+ BIN: 'bin',
7
+ DIST: 'dist',
8
+ DANNYSIR_JS_TE: '@dannysir/js-te',
9
+ };
10
+
11
+ export const RESULT_MSG = {
12
+ TESTS: 'Tests: ',
13
+ TOTAL: 'Total Result: ',
14
+ CHECK: '✓ ',
15
+ CROSS: '✗ ',
16
+ DIRECTORY_DELIMITER: ' > ',
17
+ EMPTY: '',
18
+ };
19
+
20
+ export const NUM = {
21
+ ZERO: 0,
22
+ ONE: 1,
23
+ };
24
+
25
+ export const MODULE_TYPE = {
26
+ MODULE: 'module',
27
+ ESM: 'esm',
28
+ CJS: 'cjs',
29
+ };
@@ -0,0 +1,9 @@
1
+ export const COLORS = {
2
+ reset: '\x1b[0m',
3
+ green: '\x1b[32m',
4
+ red: '\x1b[31m',
5
+ yellow: '\x1b[33m',
6
+ cyan: '\x1b[36m',
7
+ gray: '\x1b[90m',
8
+ bold: '\x1b[1m'
9
+ };
package/src/matchers.js CHANGED
@@ -1,5 +1,4 @@
1
-
2
- import {getErrorMsg, getThrowErrorMsg} from "../utils/formatString.js";
1
+ import {getErrorMsg, getThrowErrorMsg} from "./utils/formatString.js";
3
2
 
4
3
  const runArgFnc = (actual) => {
5
4
  if (typeof actual === 'function') {
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import {transformSync} from "@babel/core";
3
- import {BABEL} from "../../constants.js";
4
- import {createMockCollectorPlugin} from "../../babelCollectMocks.js";
3
+ import {createMockCollectorPlugin} from "../babelPlugins/babelCollectMocks.js";
4
+ import {BABEL} from "../constants/babel.js";
5
5
 
6
6
  export const collectMockedPaths = (testFiles) => {
7
7
  const mockedPaths = new Set();
@@ -19,7 +19,6 @@ export const collectMockedPaths = (testFiles) => {
19
19
  }
20
20
  });
21
21
  } catch (error) {
22
- // 파싱 에러는 무시 (어차피 테스트 실행 시 에러 발생)
23
22
  console.warn(`Warning: Failed to scan ${testFile} for mocks`);
24
23
  }
25
24
  }
package/src/mock/store.js CHANGED
@@ -1,17 +1,17 @@
1
1
  export const mockStore = new Map();
2
2
 
3
- export function clearAllMocks() {
3
+ export const clearAllMocks = () => {
4
4
  mockStore.clear();
5
5
  }
6
6
 
7
- export function mock(modulePath, mockExports) {
7
+ export const mock = (modulePath, mockExports) => {
8
8
  mockStore.set(modulePath, mockExports);
9
9
  }
10
10
 
11
- export function unmock(modulePath) {
11
+ export const unmock = (modulePath) => {
12
12
  mockStore.delete(modulePath);
13
13
  }
14
14
 
15
- export function isMocked(modulePath) {
15
+ export const isMocked = (modulePath) => {
16
16
  return mockStore.has(modulePath);
17
17
  }
@@ -1,4 +1,7 @@
1
- import {DIRECTORY_DELIMITER} from "../constants.js";
1
+ import {formatFailureMessage, formatSuccessMessage, getMatcherForReplace, placeHolder} from "./utils/formatString.js";
2
+ import {clearAllMocks} from "./mock/store.js";
3
+ import {NUM, RESULT_MSG} from "./constants/index.js";
4
+ import {getTestResultMsg} from "./utils/messages.js";
2
5
 
3
6
  class TestManager {
4
7
  #tests = [];
@@ -24,7 +27,7 @@ class TestManager {
24
27
  }
25
28
  await fn();
26
29
  },
27
- path: this.#testDepth.join(DIRECTORY_DELIMITER),
30
+ path: this.#testDepth.join(RESULT_MSG.DIRECTORY_DELIMITER),
28
31
  }
29
32
  this.#tests.push(testObj);
30
33
  }
@@ -52,21 +55,37 @@ class TestManager {
52
55
  this.#beforeEachArr = [];
53
56
  }
54
57
 
58
+ async run() {
59
+ let passed = NUM.ZERO;
60
+ let failed = NUM.ZERO;
61
+
62
+ for (const test of testManager.getTests()) {
63
+ try {
64
+ await test.fn();
65
+ console.log(formatSuccessMessage(test));
66
+ passed++;
67
+ clearAllMocks();
68
+ } catch (error) {
69
+ console.log(formatFailureMessage(test, error));
70
+ failed++;
71
+ }
72
+ }
73
+
74
+ console.log(getTestResultMsg(RESULT_MSG.TESTS, passed, failed));
75
+
76
+ testManager.clearTests();
77
+
78
+ return {passed, failed};
79
+ }
80
+
55
81
  #formatDescription(args, description) {
56
82
  let argIndex = 0;
57
- return description.replace(/%([so])/g, (match, type) => {
83
+ return description.replace(getMatcherForReplace(), (match, type) => {
58
84
  if (argIndex >= args.length) return match;
59
85
 
60
- const arg = args[argIndex++];
86
+ const formatter = placeHolder[type];
61
87
 
62
- switch (type) {
63
- case 's':
64
- return arg;
65
- case 'o':
66
- return JSON.stringify(arg);
67
- default:
68
- return match;
69
- }
88
+ return formatter ? formatter(args[argIndex++]) : match;
70
89
  });
71
90
  }
72
91
  }
@@ -1,8 +1,8 @@
1
- import {COLORS} from "../constants.js";
1
+ import {COLORS} from "../constants/view.js";
2
2
 
3
3
  export const colorize = (text, color) => `${color}${text}${COLORS.reset}`;
4
4
 
5
5
  export const green = (text) => colorize(text, COLORS.green + COLORS.bold);
6
6
  export const red = (text) => colorize(text, COLORS.red + COLORS.bold);
7
7
  export const bold = (text) => colorize(text, COLORS.bold);
8
- export const yellow = (text) => colorize(text, COLORS.yellow + COLORS.bold);
8
+ export const yellow = (text) => colorize(text, COLORS.yellow + COLORS.bold);
@@ -1,15 +1,21 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import {PATH} from "../../constants.js";
4
3
 
4
+
5
+ import {PATH} from "../constants/index.js";
6
+
7
+ /**
8
+ * 테스트 파일을 찾는 로직입니다.
9
+ * @param {string} dir
10
+ * @returns {string[]}
11
+ */
5
12
  export const findTestFiles = (dir) => {
6
13
  const files = [];
7
14
 
8
- const walk = (directory, inTestDir = false) => {
15
+ const walk = (directory) => {
9
16
  const items = fs.readdirSync(directory);
10
17
  const dirName = path.basename(directory);
11
-
12
- const isTestDir = dirName === PATH.TEST_DIRECTORY || inTestDir;
18
+ const isTestDir = dirName === PATH.TEST_DIRECTORY;
13
19
 
14
20
  for (const item of items) {
15
21
  if (item === PATH.NODE_MODULES) continue;
@@ -31,6 +37,11 @@ export const findTestFiles = (dir) => {
31
37
  return files;
32
38
  }
33
39
 
40
+ /**
41
+ * 테스트 파일을 포함한 전체 파일을 찾는 함수입니다.
42
+ * @param {string} dir
43
+ * @returns {string[]}
44
+ */
34
45
  export const findAllSourceFiles = (dir) => {
35
46
  const files = [];
36
47
 
@@ -53,4 +64,4 @@ export const findAllSourceFiles = (dir) => {
53
64
 
54
65
  walk(dir);
55
66
  return files;
56
- }
67
+ };