@dannysir/js-te 0.3.2 → 0.4.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/README.md +243 -30
- package/bin/cli.js +3 -3
- package/dist/index.cjs +93 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +93 -17
- package/dist/index.mjs.map +1 -1
- package/index.js +3 -0
- package/package.json +1 -1
- package/src/cli/runTests.js +2 -2
- package/src/cli/setupEnvironment.js +1 -1
- package/src/cli/setupFiles.js +3 -4
- package/src/{mock → cli/utils}/collectMocks.js +2 -2
- package/src/{utils → cli/utils}/findFiles.js +1 -1
- package/src/{utils → cli/utils}/messages.js +1 -1
- package/src/{utils → cli/utils}/transformFiles.js +3 -3
- package/src/matchers.js +7 -7
- package/src/mock/store.js +5 -1
- package/src/mock/utils/changeModuleExports.js +35 -0
- package/src/mock/utils/mockFunctions.js +38 -0
- package/src/testManager.js +12 -4
- package/src/utils/formatString.js +2 -11
package/README.md
CHANGED
|
@@ -3,26 +3,19 @@
|
|
|
3
3
|
Jest에서 영감을 받아 만든 가벼운 JavaScript 테스트 프레임워크입니다.
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
## [📎 최근 업데이트 0.
|
|
7
|
-
|
|
8
|
-
###
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- 불필요하게 거대한 로직 분리
|
|
20
|
-
- `cli.js` 내부 로직 분리 & `cli.js` 내부에서는 전체 흐름만 관리하도록 수정
|
|
21
|
-
- 바벨 플러그인 코드내 중복되는 코드 제거
|
|
22
|
-
- 디렉토리 구조 변경
|
|
23
|
-
- 기존 디렉토리 내부에 있던 유틸 디렉토리를 통합된 유틸로 관리
|
|
24
|
-
- bin 내부에 존재하는 로직을 `cli.js`를 제외하고 전부 src 디렉토리로 옮김
|
|
25
|
-
- 분리된 디렉토리를 src 내부에서 관리하도록 수정 (ex: `babelTransformImport.js`)
|
|
6
|
+
## [📎 최근 업데이트 0.4.0v](https://github.com/dannysir/js-te-package/blob/main/CHANGELOG.md)
|
|
7
|
+
|
|
8
|
+
### Mock Functions 기능 추가
|
|
9
|
+
- `fn()` 함수로 모킹 가능한 함수 생성
|
|
10
|
+
- Mock function 메서드 지원
|
|
11
|
+
- `mockImplementation()` - 함수 구현 로직 변경
|
|
12
|
+
- `mockReturnValue()` - 고정된 반환값 설정
|
|
13
|
+
- `mockReturnValueOnce()` - 일회성 반환값 설정 (여러 번 호출 가능)
|
|
14
|
+
- `mockClear()` - mock 상태 초기화
|
|
15
|
+
### Module Mocking 개선
|
|
16
|
+
- `mock()` 함수가 모듈의 모든 함수를 자동으로 mock function으로 변환
|
|
17
|
+
- 변환된 함수들도 `mockImplementation()`, `mockReturnValue()` 등 사용 가능
|
|
18
|
+
|
|
26
19
|
---
|
|
27
20
|
## 설치
|
|
28
21
|
|
|
@@ -36,7 +29,7 @@ npm install --save-dev @dannysir/js-te
|
|
|
36
29
|
|
|
37
30
|
`*.test.js` 파일을 만들면 자동으로 찾아서 실행합니다.
|
|
38
31
|
|
|
39
|
-
별도의 import문 없이 `describe`와 `test`, `expect` 로직이 사용 가능합니다.
|
|
32
|
+
별도의 import문 없이 `describe`와 `test`, `expect` 로직이 사용 가능합니다.
|
|
40
33
|
|
|
41
34
|
```javascript
|
|
42
35
|
// math.test.js
|
|
@@ -177,18 +170,188 @@ const {random1, random2} = _module;
|
|
|
177
170
|
3. 테스트 실행
|
|
178
171
|
4. 원본 파일 복구
|
|
179
172
|
|
|
180
|
-
###
|
|
173
|
+
### Mock Functions
|
|
174
|
+
|
|
175
|
+
**0.4.0 버전부터 Jest와 유사한 Mock Functions 기능을 제공합니다.**
|
|
176
|
+
|
|
177
|
+
`fn()` 함수로 생성한 mock function은 반환값 제어 등의 기능을 제공합니다.
|
|
178
|
+
|
|
179
|
+
### `fn(implementation : optional)`
|
|
180
|
+
|
|
181
|
+
모킹 가능한 함수를 생성합니다.
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
import { fn } from '@dannysir/js-te';
|
|
185
|
+
|
|
186
|
+
test('mock function 기본 사용', () => {
|
|
187
|
+
const mockFn = fn();
|
|
188
|
+
|
|
189
|
+
mockFn('test');
|
|
190
|
+
mockFn(1, 2, 3);
|
|
191
|
+
|
|
192
|
+
// mock 함수는 기본적으로 undefined 반환
|
|
193
|
+
expect(mockFn()).toBe(undefined);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test('초기 구현과 함께 생성', () => {
|
|
197
|
+
const mockFn = fn((x, y) => x + y);
|
|
198
|
+
|
|
199
|
+
expect(mockFn(1, 2)).toBe(3);
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### `mockImplementation(fn)`
|
|
204
|
+
|
|
205
|
+
Mock 함수의 구현을 변경합니다.
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
test('구현 변경하기', () => {
|
|
209
|
+
const mockFn = fn();
|
|
210
|
+
|
|
211
|
+
mockFn.mockImplementation((x) => x * 2);
|
|
212
|
+
|
|
213
|
+
expect(mockFn(5)).toBe(10);
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### `mockReturnValue(value)`
|
|
218
|
+
|
|
219
|
+
Mock 함수가 항상 특정 값을 반환하도록 설정합니다.
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
test('고정 반환값 설정', () => {
|
|
223
|
+
const mockFn = fn();
|
|
224
|
+
|
|
225
|
+
mockFn.mockReturnValue(42);
|
|
226
|
+
|
|
227
|
+
expect(mockFn()).toBe(42);
|
|
228
|
+
expect(mockFn()).toBe(42);
|
|
229
|
+
expect(mockFn()).toBe(42);
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### `mockReturnValueOnce(...values)`
|
|
234
|
+
|
|
235
|
+
Mock 함수가 지정된 값들을 순서대로 한 번씩 반환하도록 설정합니다.
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
test('일회성 반환값 설정', () => {
|
|
239
|
+
const mockFn = fn();
|
|
240
|
+
|
|
241
|
+
mockFn.mockReturnValueOnce(1, 2, 3);
|
|
242
|
+
|
|
243
|
+
expect(mockFn()).toBe(1);
|
|
244
|
+
expect(mockFn()).toBe(2);
|
|
245
|
+
expect(mockFn()).toBe(3);
|
|
246
|
+
expect(mockFn()).toBe(undefined); // 큐가 비면 기본값 반환
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('mockReturnValueOnce와 mockReturnValue 조합', () => {
|
|
250
|
+
const mockFn = fn();
|
|
251
|
+
|
|
252
|
+
mockFn
|
|
253
|
+
.mockReturnValueOnce(1, 2)
|
|
254
|
+
.mockReturnValue(99);
|
|
255
|
+
|
|
256
|
+
expect(mockFn()).toBe(1);
|
|
257
|
+
expect(mockFn()).toBe(2);
|
|
258
|
+
expect(mockFn()).toBe(99); // 이후 계속 99 반환
|
|
259
|
+
expect(mockFn()).toBe(99);
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### `mockClear()`
|
|
264
|
+
|
|
265
|
+
Mock 함수의 상태를 초기화합니다.
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
test('mock 상태 초기화', () => {
|
|
269
|
+
const mockFn = fn();
|
|
270
|
+
|
|
271
|
+
mockFn.mockReturnValue(42);
|
|
272
|
+
expect(mockFn()).toBe(42);
|
|
273
|
+
|
|
274
|
+
mockFn.mockClear();
|
|
275
|
+
expect(mockFn()).toBe(undefined); // 기본값으로 돌아감
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Module Mocking
|
|
280
|
+
|
|
281
|
+
#### `mock(모듈 절대 경로), mock객체)`
|
|
181
282
|
|
|
182
283
|
모듈을 모킹합니다. import 하기 **전에** 호출해야 합니다.
|
|
183
284
|
|
|
184
|
-
|
|
285
|
+
> **0.4.0 버전부터 `mock()` 함수가 모듈의 모든 함수를 자동으로 mock function으로 변환합니다.**
|
|
286
|
+
>
|
|
287
|
+
> **0.4.0 버전부터 `mock()` 함수가 모킹 객체를 리턴합니다.**
|
|
185
288
|
|
|
186
|
-
|
|
289
|
+
### **🚨 주의사항 (매우 중요)**
|
|
290
|
+
|
|
291
|
+
1. **반드시 경로는 절대 경로로 입력해주세요.**
|
|
187
292
|
- babel이 import문에서 절대 경로로 변환하여 확인을 하기 때문에 반드시 절대 경로로 등록해주세요.
|
|
188
293
|
2. ~~import문을 반드시 mocking 이후에 선언해주세요.~~
|
|
189
294
|
- ~~mocking 전에 import를 하게 되면 mocking되기 전의 모듈을 가져오게 됩니다.~~
|
|
190
295
|
|
|
191
296
|
> **0.3.0 버전부터 import문을 mock선언 이후에 하지 않아도 됩니다.**
|
|
297
|
+
3. **모킹한 모듈을 제어하고 싶다면 반드시 리턴 받은 객체를 활용하세요.**
|
|
298
|
+
|
|
299
|
+
**반환값 사용 예시**
|
|
300
|
+
```javascript
|
|
301
|
+
// math.js
|
|
302
|
+
export const add = (a, b) => a + b;
|
|
303
|
+
export const multiply = (a, b) => a * b;
|
|
304
|
+
|
|
305
|
+
// math.test.js
|
|
306
|
+
import { add, multiply} from './math.js';
|
|
307
|
+
test('mock 객체 반환값 활용', () => {
|
|
308
|
+
// mock() 함수가 모킹된 객체를 반환
|
|
309
|
+
// example - { add : 모킹함수, multiply : 모킹함수}
|
|
310
|
+
const mockedMath = mock('/absolute/path/to/math.js', {
|
|
311
|
+
add: (a, b) => a + b,
|
|
312
|
+
multiply: (a, b) => a * b
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// ⚠️ 중요: mock function 메서드는 반드시 반환받은 객체에 사용하세요
|
|
316
|
+
// 올바른 사용 ✅
|
|
317
|
+
mockedMath.add.mockReturnValue(100);
|
|
318
|
+
mockedMath.multiply.mockReturnValueOnce(50, 75);
|
|
319
|
+
// 잘못된 사용 ❌
|
|
320
|
+
// add.mockReturnValue(100); // 동작하지 않습니다!
|
|
321
|
+
|
|
322
|
+
expect(add(1, 2)).toBe(100);
|
|
323
|
+
expect(multiply(2, 3)).toBe(50);
|
|
324
|
+
expect(multiply(2, 3)).toBe(75);
|
|
325
|
+
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### **왜 반환된 객체를 사용해야 하나요?**
|
|
330
|
+
|
|
331
|
+
**간략 설명**
|
|
332
|
+
|
|
333
|
+
wrapper 패턴을 통해 모듈을 변경하기 때문에 mock function에 접근이 불가
|
|
334
|
+
|
|
335
|
+
**상세 설명**
|
|
336
|
+
|
|
337
|
+
`mock()` 함수는 모듈의 함수들을 mock function으로 변환하여 mockStore에 저장합니다.
|
|
338
|
+
|
|
339
|
+
하지만 `import`로 가져온 함수는 wrapper 함수이기 때문에 mock function의 메서드(`mockReturnValue`, `mockImplementation` 등)를 직접 가지고 있지 않습니다.
|
|
340
|
+
|
|
341
|
+
따라서 mock function의 메서드를 사용하려면 **반드시 `mock()` 함수가 반환한 객체**를 통해 접근해야 합니다.
|
|
342
|
+
```javascript
|
|
343
|
+
// 동작 원리
|
|
344
|
+
const mockedMath = mock('/path/to/math.js', {
|
|
345
|
+
add: (a, b) => a + b
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// mockedMath.add는 실제 mock function (메서드 있음) ✅
|
|
349
|
+
mockedMath.add.mockReturnValue(100);
|
|
350
|
+
|
|
351
|
+
// import로 가져온 add는 wrapper 함수 (메서드 없음) ❌
|
|
352
|
+
const { add } = await import('./math.js');
|
|
353
|
+
// add.mockReturnValue(100); // TypeError: add.mockReturnValue is not a function
|
|
354
|
+
```
|
|
192
355
|
|
|
193
356
|
**💡 부분 모킹(Partial Mocking)**
|
|
194
357
|
|
|
@@ -214,6 +377,8 @@ test('부분 모킹 예제', async () => {
|
|
|
214
377
|
});
|
|
215
378
|
```
|
|
216
379
|
|
|
380
|
+
> 모킹을 한 모듈에 mock function을 쓰고 싶으면
|
|
381
|
+
|
|
217
382
|
**📦 모듈 시스템 지원**
|
|
218
383
|
|
|
219
384
|
ESM(import)과 CommonJS(require) 모두 지원합니다.
|
|
@@ -249,12 +414,32 @@ test('랜덤 함수 모킹', async () => {
|
|
|
249
414
|
// 2. 모킹된 값 사용
|
|
250
415
|
expect(play()).toBe(5);
|
|
251
416
|
});
|
|
417
|
+
|
|
418
|
+
// 0.4.0 버전부터 mock functions 사용 가능
|
|
419
|
+
test('mock functions로 동적 제어', async () => {
|
|
420
|
+
const mocked = mock('/Users/san/Js-Te/test-helper/random.js', {
|
|
421
|
+
random: () => 0.5
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
expect(play()).toBe(5);
|
|
425
|
+
|
|
426
|
+
// 반환값 동적 변경
|
|
427
|
+
mocked.random.mockReturnValue(0.3);
|
|
428
|
+
expect(play()).toBe(3);
|
|
429
|
+
|
|
430
|
+
// 일회성 반환값 설정
|
|
431
|
+
mocked.random.mockReturnValueOnce(0.1);
|
|
432
|
+
expect(play()).toBe(1);
|
|
433
|
+
expect(play()).toBe(3); // 이전 설정값으로 복귀
|
|
434
|
+
});
|
|
252
435
|
```
|
|
253
436
|
|
|
254
437
|
### `clearAllMocks()`
|
|
255
438
|
|
|
256
439
|
등록된 모든 mock을 제거합니다.
|
|
257
440
|
|
|
441
|
+
**참고**: `clearAllMocks()`는 mockStore에서 mock을 제거하지만, 각 mock function의 내부 상태(returnQueue, implementation 등)는 초기화하지 않습니다. Mock function의 상태를 초기화하려면 각 함수의 `mockClear()` 메서드를 사용하세요.
|
|
442
|
+
|
|
258
443
|
### `unmock(모듈경로)`
|
|
259
444
|
|
|
260
445
|
특정 mock만 제거합니다.
|
|
@@ -374,20 +559,38 @@ describe('문자열 테스트', () => {
|
|
|
374
559
|
});
|
|
375
560
|
```
|
|
376
561
|
|
|
377
|
-
###
|
|
562
|
+
### Mock Functions 기본 사용
|
|
563
|
+
```javascript
|
|
564
|
+
import { fn } from '@dannysir/js-te';
|
|
565
|
+
|
|
566
|
+
test('콜백 함수 모킹', () => {
|
|
567
|
+
const mockCallback = fn((x) => x * 2);
|
|
568
|
+
|
|
569
|
+
expect(mockCallback(21)).toBe(42);
|
|
570
|
+
|
|
571
|
+
// 구현 변경
|
|
572
|
+
mockCallback.mockImplementation((x) => x + 10);
|
|
573
|
+
expect(mockCallback(5)).toBe(15);
|
|
574
|
+
});
|
|
575
|
+
```
|
|
378
576
|
|
|
379
|
-
|
|
577
|
+
### 전체 모킹
|
|
578
|
+
#### 모듈 모킹 (전체)
|
|
380
579
|
```javascript
|
|
381
580
|
// mocking.test.js
|
|
382
581
|
import {random} from '../src/test-helper/game.js'; // 0.2.4 버전부터 import문 상단 배치 가능
|
|
383
582
|
|
|
384
583
|
test('[mocking] - mocking random function', async () => {
|
|
385
|
-
mock('/Users/san/Js-Te/test-helper/random.js', {
|
|
584
|
+
const mocked = mock('/Users/san/Js-Te/test-helper/random.js', {
|
|
386
585
|
random: () => 3,
|
|
387
586
|
});
|
|
388
587
|
// 0.3.0 버전 이전까지는 반드시 mock 이후 동적 import문 작성
|
|
389
588
|
// const {play} = await import('../src/test-helper/game.js');
|
|
390
589
|
expect(play()).toBe(30);
|
|
590
|
+
|
|
591
|
+
// 0.4.0 버전부터: 동적으로 반환값 변경 가능
|
|
592
|
+
mocked.random.mockReturnValue(5);
|
|
593
|
+
expect(play()).toBe(50);
|
|
391
594
|
});
|
|
392
595
|
|
|
393
596
|
// game.js
|
|
@@ -401,7 +604,7 @@ export const play = () => {
|
|
|
401
604
|
export const random = () => Math.random();
|
|
402
605
|
```
|
|
403
606
|
|
|
404
|
-
####
|
|
607
|
+
#### 모듈 모킹 (부분)
|
|
405
608
|
```javascript
|
|
406
609
|
// calculator.js
|
|
407
610
|
export const add = (a, b) => a + b;
|
|
@@ -411,7 +614,7 @@ export const multiply = (a, b) => a * b;
|
|
|
411
614
|
// calculator.test.js
|
|
412
615
|
test('[partial mocking] - mock only multiply', async () => {
|
|
413
616
|
// multiply만 모킹, add와 subtract는 원본 사용
|
|
414
|
-
mock('/Users/san/Js-Te/calculator.js', {
|
|
617
|
+
const mocked = mock('/Users/san/Js-Te/calculator.js', {
|
|
415
618
|
multiply: (a, b) => 999
|
|
416
619
|
});
|
|
417
620
|
|
|
@@ -419,7 +622,17 @@ test('[partial mocking] - mock only multiply', async () => {
|
|
|
419
622
|
|
|
420
623
|
expect(add(2, 3)).toBe(5);
|
|
421
624
|
expect(subtract(5, 2)).toBe(3);
|
|
422
|
-
expect(multiply(2, 3)).toBe(999);
|
|
625
|
+
expect(multiply(2, 3)).toBe(999);
|
|
626
|
+
|
|
627
|
+
// 0.4.0 버전부터: mock function 메서드 사용 가능
|
|
628
|
+
mocked.multiply.mockReturnValue(100);
|
|
629
|
+
expect(multiply(2, 3)).toBe(100);
|
|
630
|
+
|
|
631
|
+
// 일회성 반환값
|
|
632
|
+
mocked.multiply.mockReturnValueOnce(50, 75);
|
|
633
|
+
expect(multiply(2, 3)).toBe(50);
|
|
634
|
+
expect(multiply(2, 3)).toBe(75);
|
|
635
|
+
expect(multiply(2, 3)).toBe(100); // 이전 설정값으로 복귀
|
|
423
636
|
});
|
|
424
637
|
```
|
|
425
638
|
|
package/bin/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import {NUM, RESULT_MSG} from "../src/constants/index.js";
|
|
4
|
-
import {restoreFiles} from "../src/utils/transformFiles.js";
|
|
5
|
-
import {getErrorMsgInLogic, getFileCountString, getTestResultMsg} from "../src/utils/messages.js";
|
|
4
|
+
import {restoreFiles} from "../src/cli/utils/transformFiles.js";
|
|
5
|
+
import {getErrorMsgInLogic, getFileCountString, getTestResultMsg} from "../src/cli/utils/messages.js";
|
|
6
6
|
import {setupEnvironment} from "../src/cli/setupEnvironment.js";
|
|
7
7
|
import {setupFiles} from "../src/cli/setupFiles.js";
|
|
8
8
|
import {runTests} from "../src/cli/runTests.js";
|
|
@@ -26,4 +26,4 @@ const main = async () => {
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
const exitCode = await main();
|
|
29
|
-
process.exit(exitCode);
|
|
29
|
+
process.exit(exitCode);
|
package/dist/index.cjs
CHANGED
|
@@ -36,21 +36,85 @@ const formatFailureMessage = (test, error) => {
|
|
|
36
36
|
return messages.join('\n');
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
const
|
|
39
|
+
const formatErrorMsg = (expect, actual) => {
|
|
40
40
|
return `Expected ${JSON.stringify(expect)} but got ${JSON.stringify(actual)}`;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
const
|
|
43
|
+
const formatThrowErrorMsg = (expect) => {
|
|
44
44
|
return `Expected function to throw an error containing "${expect}", but it did not throw`;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
/**
|
|
48
|
+
* 목업 함수의 메서드 타입 정의
|
|
49
|
+
* @typedef {Object} MockMethods
|
|
50
|
+
* @property {function(function): MockMethods} mockImplementation - 구현 설정
|
|
51
|
+
* @property {function(...*): MockMethods} mockReturnValueOnce - 일회성 반환값 설정
|
|
52
|
+
* @property {function(*): MockMethods} mockReturnValue - 반환값 설정
|
|
53
|
+
* @property {function(): void} mockClear - 목업 상태 초기화
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {function} mockFn
|
|
58
|
+
* @param {Object} state
|
|
59
|
+
* @returns {{mockImplementation(*): this, mockReturnValueOnce(...[*]): this, mockReturnValue(*): this, mockClear(): this}|*}
|
|
60
|
+
*/
|
|
61
|
+
const mockFunctions = (mockFn, state) => {
|
|
62
|
+
return {
|
|
63
|
+
mockImplementation(newImpl) {
|
|
64
|
+
state.curImplement = newImpl;
|
|
65
|
+
return mockFn;
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
mockReturnValueOnce(...value) {
|
|
69
|
+
state.returnQueue.push(...value);
|
|
70
|
+
return mockFn;
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
mockReturnValue(value) {
|
|
74
|
+
state.curImplement = () => value;
|
|
75
|
+
return mockFn;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
mockClear() {
|
|
79
|
+
state.returnQueue = [];
|
|
80
|
+
state.curImplement = () => null;
|
|
81
|
+
return mockFn;
|
|
82
|
+
},
|
|
83
|
+
}
|
|
50
84
|
};
|
|
51
85
|
|
|
52
|
-
|
|
53
|
-
|
|
86
|
+
/**
|
|
87
|
+
* 목업 함수로 변환하는 로직
|
|
88
|
+
* @param {function} [implementation] - 목업 함수 로직 (선택, 기본값: () => null)
|
|
89
|
+
* @returns {(function(...*): *) & MockMethods} 호출 가능하면서 목업 메서드를 가진 함수
|
|
90
|
+
*/
|
|
91
|
+
const makeMockFnc = (implementation = (() => null)) => {
|
|
92
|
+
const state = {
|
|
93
|
+
returnQueue: [],
|
|
94
|
+
curImplement: implementation,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const mockFn = (...args) => {
|
|
98
|
+
if (state.returnQueue.length > 0) {
|
|
99
|
+
return state.returnQueue.shift();
|
|
100
|
+
}
|
|
101
|
+
return state.curImplement(...args);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const methods = mockFunctions(mockFn, state);
|
|
105
|
+
Object.assign(mockFn, methods);
|
|
106
|
+
|
|
107
|
+
return mockFn;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const changeModuleExports = (moduleExports) => {
|
|
111
|
+
const result = {};
|
|
112
|
+
|
|
113
|
+
for (const moduleName in moduleExports) {
|
|
114
|
+
result[moduleName] = makeMockFnc(moduleExports[moduleName]);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return result;
|
|
54
118
|
};
|
|
55
119
|
|
|
56
120
|
const mockStore = new Map();
|
|
@@ -60,7 +124,9 @@ const clearAllMocks = () => {
|
|
|
60
124
|
};
|
|
61
125
|
|
|
62
126
|
const mock = (modulePath, mockExports) => {
|
|
63
|
-
|
|
127
|
+
const mockedExports = changeModuleExports(mockExports);
|
|
128
|
+
mockStore.set(modulePath, mockedExports);
|
|
129
|
+
return mockStore.get(modulePath);
|
|
64
130
|
};
|
|
65
131
|
|
|
66
132
|
const unmock = (modulePath) => {
|
|
@@ -88,6 +154,10 @@ class TestManager {
|
|
|
88
154
|
#tests = [];
|
|
89
155
|
#testDepth = [];
|
|
90
156
|
#beforeEachArr = [];
|
|
157
|
+
#placeHolder = {
|
|
158
|
+
's': (value) => value,
|
|
159
|
+
'o': (value) => JSON.stringify(value),
|
|
160
|
+
};
|
|
91
161
|
|
|
92
162
|
describe(str, fn) {
|
|
93
163
|
this.#testDepth.push(str);
|
|
@@ -159,12 +229,16 @@ class TestManager {
|
|
|
159
229
|
return {passed, failed};
|
|
160
230
|
}
|
|
161
231
|
|
|
232
|
+
#getMatcherForReplace = () => {
|
|
233
|
+
return new RegExp(`%([${Object.keys(this.#placeHolder).join('')}])`, 'g')
|
|
234
|
+
};
|
|
235
|
+
|
|
162
236
|
#formatDescription(args, description) {
|
|
163
237
|
let argIndex = 0;
|
|
164
|
-
return description.replace(getMatcherForReplace(), (match, type) => {
|
|
238
|
+
return description.replace(this.#getMatcherForReplace(), (match, type) => {
|
|
165
239
|
if (argIndex >= args.length) return match;
|
|
166
240
|
|
|
167
|
-
const formatter = placeHolder[type];
|
|
241
|
+
const formatter = this.#placeHolder[type];
|
|
168
242
|
|
|
169
243
|
return formatter ? formatter(args[argIndex++]) : match;
|
|
170
244
|
});
|
|
@@ -183,14 +257,14 @@ const runArgFnc = (actual) => {
|
|
|
183
257
|
const toBe = (actual, expected) => {
|
|
184
258
|
const value = runArgFnc(actual);
|
|
185
259
|
if (value !== expected) {
|
|
186
|
-
throw new Error(
|
|
260
|
+
throw new Error(formatErrorMsg(expected, value));
|
|
187
261
|
}
|
|
188
262
|
};
|
|
189
263
|
|
|
190
264
|
const toEqual = (actual, expected) => {
|
|
191
265
|
const value = runArgFnc(actual);
|
|
192
266
|
if (JSON.stringify(value) !== JSON.stringify(expected)) {
|
|
193
|
-
throw new Error(
|
|
267
|
+
throw new Error(formatErrorMsg(expected, value));
|
|
194
268
|
}
|
|
195
269
|
};
|
|
196
270
|
|
|
@@ -199,24 +273,24 @@ const toThrow = (actual, expected) => {
|
|
|
199
273
|
runArgFnc(actual);
|
|
200
274
|
} catch (e) {
|
|
201
275
|
if (!e.message.includes(expected)) {
|
|
202
|
-
throw new Error(
|
|
276
|
+
throw new Error(formatErrorMsg(expected, e.message));
|
|
203
277
|
}
|
|
204
278
|
return;
|
|
205
279
|
}
|
|
206
|
-
throw new Error(
|
|
280
|
+
throw new Error(formatThrowErrorMsg(expected));
|
|
207
281
|
};
|
|
208
282
|
|
|
209
283
|
const toBeTruthy = (actual) => {
|
|
210
284
|
const value = runArgFnc(actual);
|
|
211
285
|
if (!value) {
|
|
212
|
-
throw new Error(
|
|
286
|
+
throw new Error(formatErrorMsg(true, value));
|
|
213
287
|
}
|
|
214
288
|
};
|
|
215
289
|
|
|
216
290
|
const toBeFalsy = (actual) => {
|
|
217
291
|
const value = runArgFnc(actual);
|
|
218
292
|
if (value) {
|
|
219
|
-
throw new Error(
|
|
293
|
+
throw new Error(formatErrorMsg(false, value));
|
|
220
294
|
}
|
|
221
295
|
};
|
|
222
296
|
|
|
@@ -310,10 +384,13 @@ const beforeEach = (fn) => testManager.beforeEach(fn);
|
|
|
310
384
|
*/
|
|
311
385
|
const run = () => testManager.run();
|
|
312
386
|
|
|
387
|
+
const fn = makeMockFnc;
|
|
388
|
+
|
|
313
389
|
exports.beforeEach = beforeEach;
|
|
314
390
|
exports.clearAllMocks = clearAllMocks;
|
|
315
391
|
exports.describe = describe;
|
|
316
392
|
exports.expect = expect;
|
|
393
|
+
exports.fn = fn;
|
|
317
394
|
exports.isMocked = isMocked;
|
|
318
395
|
exports.mock = mock;
|
|
319
396
|
exports.mockStore = mockStore;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/constants/view.js","../src/utils/consoleColor.js","../src/constants/index.js","../src/utils/formatString.js","../src/mock/store.js","../src/utils/messages.js","../src/testManager.js","../src/matchers.js","../src/expect.js","../index.js"],"sourcesContent":["export const COLORS = {\n reset: '\\x1b[0m',\n green: '\\x1b[32m',\n red: '\\x1b[31m',\n yellow: '\\x1b[33m',\n cyan: '\\x1b[36m',\n gray: '\\x1b[90m',\n bold: '\\x1b[1m'\n};\n","import {COLORS} from \"../constants/view.js\";\n\nexport const colorize = (text, color) => `${color}${text}${COLORS.reset}`;\n\nexport const green = (text) => colorize(text, COLORS.green + COLORS.bold);\nexport const red = (text) => colorize(text, COLORS.red + COLORS.bold);\nexport const bold = (text) => colorize(text, COLORS.bold);\nexport const yellow = (text) => colorize(text, COLORS.yellow + COLORS.bold);\n","export const PATH = {\n NODE_MODULES: 'node_modules',\n TEST_DIRECTORY: 'test',\n TEST_FILE: '.test.js',\n JAVASCRIPT_FILE: '.js',\n BIN: 'bin',\n DIST: 'dist',\n DANNYSIR_JS_TE: '@dannysir/js-te',\n};\n\nexport const RESULT_MSG = {\n TESTS: 'Tests: ',\n TOTAL: 'Total Result: ',\n CHECK: '✓ ',\n CROSS: '✗ ',\n DIRECTORY_DELIMITER: ' > ',\n EMPTY: '',\n};\n\nexport const NUM = {\n ZERO: 0,\n ONE: 1,\n};\n\nexport const MODULE_TYPE = {\n MODULE: 'module',\n ESM: 'esm',\n CJS: 'cjs',\n};\n","import {green, red} from \"./consoleColor.js\";\nimport {RESULT_MSG} from \"../constants/index.js\";\n\nexport const formatSuccessMessage = (test) => {\n const pathString = test.path === '' ? RESULT_MSG.EMPTY : test.path + RESULT_MSG.DIRECTORY_DELIMITER;\n return green(RESULT_MSG.CHECK) + pathString + test.description;\n};\n\nexport const formatFailureMessage = (test, error) => {\n const messages = [];\n messages.push(red(RESULT_MSG.CROSS) + test.path + test.description);\n messages.push(red(` Error Message : ${error.message}`));\n return messages.join('\\n');\n};\n\nexport const getErrorMsg = (expect, actual) => {\n return `Expected ${JSON.stringify(expect)} but got ${JSON.stringify(actual)}`;\n};\n\nexport const getThrowErrorMsg = (expect) => {\n return `Expected function to throw an error containing \"${expect}\", but it did not throw`;\n};\n\nexport const placeHolder = {\n 's': (value) => value,\n 'o': (value) => JSON.stringify(value),\n};\n\nexport const getMatcherForReplace = () => {\n return new RegExp(`%([${Object.keys(placeHolder).join('')}])`, 'g')\n};\n","export const mockStore = new Map();\n\nexport const clearAllMocks = () => {\n mockStore.clear();\n}\n\nexport const mock = (modulePath, mockExports) => {\n mockStore.set(modulePath, mockExports);\n}\n\nexport const unmock = (modulePath) => {\n mockStore.delete(modulePath);\n}\n\nexport const isMocked = (modulePath) => {\n return mockStore.has(modulePath);\n}\n","import {bold, green, red, yellow} from \"./consoleColor.js\";\n\nexport const getTestResultMsg = (title, success, fail) => {\n let msg = '\\n';\n\n msg += title;\n msg += green(success + ' passed') + ', ';\n if (fail) {\n msg += red(fail + ' failed') + ', ';\n }\n msg += bold(success + fail + ' total');\n\n return msg;\n};\n\nexport const getFileCountString = (n) => {\n return `\\nFound ${green(n)} test file(s)`;\n};\n\nexport const getFilePath = (path) => {\n return `\\n${yellow(path)}\\n`;\n};\n\nexport const getErrorMsgInLogic = (error) => {\n return red(`\\n✗ Test execution failed\\n Error: ${error}\\n`)\n};\n","import {formatFailureMessage, formatSuccessMessage, getMatcherForReplace, placeHolder} from \"./utils/formatString.js\";\nimport {clearAllMocks} from \"./mock/store.js\";\nimport {NUM, RESULT_MSG} from \"./constants/index.js\";\nimport {getTestResultMsg} from \"./utils/messages.js\";\n\nclass TestManager {\n #tests = [];\n #testDepth = [];\n #beforeEachArr = [];\n\n describe(str, fn) {\n this.#testDepth.push(str);\n const prevLength = this.#beforeEachArr.length;\n fn();\n this.#beforeEachArr.length = prevLength;\n this.#testDepth.pop();\n }\n\n test(description, fn) {\n const beforeEachHooks = [...this.#beforeEachArr];\n\n const testObj = {\n description,\n fn: async () => {\n for (const hook of beforeEachHooks) {\n await hook();\n }\n await fn();\n },\n path: this.#testDepth.join(RESULT_MSG.DIRECTORY_DELIMITER),\n }\n this.#tests.push(testObj);\n }\n\n testEach(cases) {\n return (description, fn) => {\n cases.forEach(testCase => {\n const args = Array.isArray(testCase) ? testCase : [testCase];\n this.test(this.#formatDescription(args, description), () => fn(...args));\n });\n };\n }\n\n beforeEach(fn) {\n this.#beforeEachArr.push(fn);\n }\n\n getTests() {\n return [...this.#tests];\n }\n\n clearTests() {\n this.#tests = [];\n this.#testDepth = [];\n this.#beforeEachArr = [];\n }\n\n async run() {\n let passed = NUM.ZERO;\n let failed = NUM.ZERO;\n\n for (const test of testManager.getTests()) {\n try {\n await test.fn();\n console.log(formatSuccessMessage(test));\n passed++;\n clearAllMocks();\n } catch (error) {\n console.log(formatFailureMessage(test, error));\n failed++;\n }\n }\n\n console.log(getTestResultMsg(RESULT_MSG.TESTS, passed, failed));\n\n testManager.clearTests();\n\n return {passed, failed};\n }\n\n #formatDescription(args, description) {\n let argIndex = 0;\n return description.replace(getMatcherForReplace(), (match, type) => {\n if (argIndex >= args.length) return match;\n\n const formatter = placeHolder[type];\n\n return formatter ? formatter(args[argIndex++]) : match;\n });\n }\n}\n\nexport const testManager = new TestManager();","import {getErrorMsg, getThrowErrorMsg} from \"./utils/formatString.js\";\n\nconst runArgFnc = (actual) => {\n if (typeof actual === 'function') {\n return actual();\n }\n return actual;\n};\n\nexport const toBe = (actual, expected) => {\n const value = runArgFnc(actual);\n if (value !== expected) {\n throw new Error(getErrorMsg(expected, value));\n }\n};\n\nexport const toEqual = (actual, expected) => {\n const value = runArgFnc(actual);\n if (JSON.stringify(value) !== JSON.stringify(expected)) {\n throw new Error(getErrorMsg(expected, value));\n }\n};\n\nexport const toThrow = (actual, expected) => {\n try {\n runArgFnc(actual);\n } catch (e) {\n if (!e.message.includes(expected)) {\n throw new Error(getErrorMsg(expected, e.message));\n }\n return;\n }\n throw new Error(getThrowErrorMsg(expected));\n};\n\nexport const toBeTruthy = (actual) => {\n const value = runArgFnc(actual);\n if (!value) {\n throw new Error(getErrorMsg(true, value));\n }\n};\n\nexport const toBeFalsy = (actual) => {\n const value = runArgFnc(actual);\n if (value) {\n throw new Error(getErrorMsg(false, value));\n }\n};\n","import {toBe, toBeFalsy, toBeTruthy, toEqual, toThrow} from \"./matchers.js\";\n\nexport const expect = (actual) => {\n return {\n toBe(expected) {\n toBe(actual, expected);\n },\n toEqual(expected) {\n toEqual(actual, expected);\n },\n toThrow(expected) {\n toThrow(actual, expected);\n },\n toBeTruthy() {\n toBeTruthy(actual);\n },\n toBeFalsy() {\n toBeFalsy(actual);\n }\n }\n};\n","import {testManager} from \"./src/testManager.js\";\nimport {clearAllMocks, isMocked, mock, unmock, mockStore} from './src/mock/store.js';\nimport {expect} from \"./src/expect.js\";\n\n/**\n * 테스트 케이스를 정의합니다.\n * @param {string} description - 테스트 설명\n * @param {Function} fn - 테스트 함수\n *\n * @example\n * test('더하기 테스트', () => {\n * expect(1 + 2).toBe(3);\n * });\n */\nexport const test = (description, fn) => testManager.test(description, fn);\n\n/**\n * 배열 형태의 테스트 케이스를 반복 실행합니다.\n * @param {Array<Array>} cases - 테스트 케이스 배열\n * @returns {Function} 테스트 실행 함수\n *\n * @example\n * test.each([\n * [1, 2, 3],\n * [2, 3, 5],\n * ])('add(%s, %s) = %s', (a, b, expected) => {\n * expect(a + b).toBe(expected);\n * });\n */\ntest.each = (cases) => testManager.testEach(cases);\n\n/**\n * 테스트 그룹을 정의합니다. 중첩 가능합니다.\n * @param {string} suiteName - 그룹 이름\n * @param {Function} fn - 그룹 내부 테스트들을 정의하는 함수\n *\n * @example\n * describe('계산기', () => {\n * test('더하기', () => {\n * expect(1 + 1).toBe(2);\n * });\n * });\n */\nexport const describe = (suiteName, fn) => testManager.describe(suiteName, fn);\n\n/**\n * 각 테스트 실행 전에 실행될 함수를 등록합니다.\n * @param {Function} fn - 전처리 함수\n *\n * @example\n * describe('카운터 테스트', () => {\n * let counter;\n *\n * beforeEach(() => {\n * counter = 0;\n * });\n *\n * test('초기값은 0', () => {\n * expect(counter).toBe(0);\n * });\n * });\n */\nexport const beforeEach = (fn) => testManager.beforeEach(fn);\n\n/**\n * 등록된 모든 테스트를 실행합니다.\n * @returns {Promise<{passed: number, failed: number}>} 테스트 결과\n *\n * @example\n * const { passed, failed } = await run();\n * console.log(`${passed} passed, ${failed} failed`);\n */\nexport const run = () => testManager.run();\n\n/**\n * 값을 검증하는 matcher 함수들을 반환합니다.\n * @function\n * @param {*} actual - 검증할 값\n * @returns {Object} matcher 함수들\n *\n * @example\n * expect(1 + 1).toBe(2);\n * expect([1, 2, 3]).toEqual([1, 2, 3]);\n * expect(() => { throw new Error('error') }).toThrow('error');\n * expect(true).toBeTruthy();\n * expect(false).toBeFalsy();\n */\nexport {expect};\n\nexport {mock, clearAllMocks, unmock, isMocked, mockStore};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/constants/view.js","../src/utils/consoleColor.js","../src/constants/index.js","../src/utils/formatString.js","../src/mock/utils/mockFunctions.js","../src/mock/utils/changeModuleExports.js","../src/mock/store.js","../src/cli/utils/messages.js","../src/testManager.js","../src/matchers.js","../src/expect.js","../index.js"],"sourcesContent":["export const COLORS = {\n reset: '\\x1b[0m',\n green: '\\x1b[32m',\n red: '\\x1b[31m',\n yellow: '\\x1b[33m',\n cyan: '\\x1b[36m',\n gray: '\\x1b[90m',\n bold: '\\x1b[1m'\n};\n","import {COLORS} from \"../constants/view.js\";\n\nexport const colorize = (text, color) => `${color}${text}${COLORS.reset}`;\n\nexport const green = (text) => colorize(text, COLORS.green + COLORS.bold);\nexport const red = (text) => colorize(text, COLORS.red + COLORS.bold);\nexport const bold = (text) => colorize(text, COLORS.bold);\nexport const yellow = (text) => colorize(text, COLORS.yellow + COLORS.bold);\n","export const PATH = {\n NODE_MODULES: 'node_modules',\n TEST_DIRECTORY: 'test',\n TEST_FILE: '.test.js',\n JAVASCRIPT_FILE: '.js',\n BIN: 'bin',\n DIST: 'dist',\n DANNYSIR_JS_TE: '@dannysir/js-te',\n};\n\nexport const RESULT_MSG = {\n TESTS: 'Tests: ',\n TOTAL: 'Total Result: ',\n CHECK: '✓ ',\n CROSS: '✗ ',\n DIRECTORY_DELIMITER: ' > ',\n EMPTY: '',\n};\n\nexport const NUM = {\n ZERO: 0,\n ONE: 1,\n};\n\nexport const MODULE_TYPE = {\n MODULE: 'module',\n ESM: 'esm',\n CJS: 'cjs',\n};\n","import {green, red} from \"./consoleColor.js\";\nimport {RESULT_MSG} from \"../constants/index.js\";\n\nexport const formatSuccessMessage = (test) => {\n const pathString = test.path === '' ? RESULT_MSG.EMPTY : test.path + RESULT_MSG.DIRECTORY_DELIMITER;\n return green(RESULT_MSG.CHECK) + pathString + test.description;\n};\n\nexport const formatFailureMessage = (test, error) => {\n const messages = [];\n messages.push(red(RESULT_MSG.CROSS) + test.path + test.description);\n messages.push(red(` Error Message : ${error.message}`));\n return messages.join('\\n');\n};\n\nexport const formatErrorMsg = (expect, actual) => {\n return `Expected ${JSON.stringify(expect)} but got ${JSON.stringify(actual)}`;\n};\n\nexport const formatThrowErrorMsg = (expect) => {\n return `Expected function to throw an error containing \"${expect}\", but it did not throw`;\n};\n","/**\n * 목업 함수의 메서드 타입 정의\n * @typedef {Object} MockMethods\n * @property {function(function): MockMethods} mockImplementation - 구현 설정\n * @property {function(...*): MockMethods} mockReturnValueOnce - 일회성 반환값 설정\n * @property {function(*): MockMethods} mockReturnValue - 반환값 설정\n * @property {function(): void} mockClear - 목업 상태 초기화\n */\n\n/**\n * @param {function} mockFn\n * @param {Object} state\n * @returns {{mockImplementation(*): this, mockReturnValueOnce(...[*]): this, mockReturnValue(*): this, mockClear(): this}|*}\n */\nexport const mockFunctions = (mockFn, state) => {\n return {\n mockImplementation(newImpl) {\n state.curImplement = newImpl;\n return mockFn;\n },\n\n mockReturnValueOnce(...value) {\n state.returnQueue.push(...value);\n return mockFn;\n },\n\n mockReturnValue(value) {\n state.curImplement = () => value;\n return mockFn;\n },\n\n mockClear() {\n state.returnQueue = [];\n state.curImplement = () => null;\n return mockFn;\n },\n }\n};\n","import {mockFunctions} from \"./mockFunctions.js\";\n\n/**\n * 목업 함수로 변환하는 로직\n * @param {function} [implementation] - 목업 함수 로직 (선택, 기본값: () => null)\n * @returns {(function(...*): *) & MockMethods} 호출 가능하면서 목업 메서드를 가진 함수\n */\nexport const makeMockFnc = (implementation = (() => null)) => {\n const state = {\n returnQueue: [],\n curImplement: implementation,\n };\n\n const mockFn = (...args) => {\n if (state.returnQueue.length > 0) {\n return state.returnQueue.shift();\n }\n return state.curImplement(...args);\n };\n\n const methods = mockFunctions(mockFn, state);\n Object.assign(mockFn, methods);\n\n return mockFn;\n};\n\nexport const changeModuleExports = (moduleExports) => {\n const result = {};\n\n for (const moduleName in moduleExports) {\n result[moduleName] = makeMockFnc(moduleExports[moduleName]);\n }\n\n return result;\n};\n","import {changeModuleExports} from \"./utils/changeModuleExports.js\";\n\nexport const mockStore = new Map();\n\nexport const clearAllMocks = () => {\n mockStore.clear();\n}\n\nexport const mock = (modulePath, mockExports) => {\n const mockedExports = changeModuleExports(mockExports);\n mockStore.set(modulePath, mockedExports);\n return mockStore.get(modulePath);\n}\n\nexport const unmock = (modulePath) => {\n mockStore.delete(modulePath);\n}\n\nexport const isMocked = (modulePath) => {\n return mockStore.has(modulePath);\n}\n","import {bold, green, red, yellow} from \"../../utils/consoleColor.js\";\n\nexport const getTestResultMsg = (title, success, fail) => {\n let msg = '\\n';\n\n msg += title;\n msg += green(success + ' passed') + ', ';\n if (fail) {\n msg += red(fail + ' failed') + ', ';\n }\n msg += bold(success + fail + ' total');\n\n return msg;\n};\n\nexport const getFileCountString = (n) => {\n return `\\nFound ${green(n)} test file(s)`;\n};\n\nexport const getFilePath = (path) => {\n return `\\n${yellow(path)}\\n`;\n};\n\nexport const getErrorMsgInLogic = (error) => {\n return red(`\\n✗ Test execution failed\\n Error: ${error}\\n`)\n};\n","import {formatFailureMessage, formatSuccessMessage} from \"./utils/formatString.js\";\nimport {clearAllMocks} from \"./mock/store.js\";\nimport {NUM, RESULT_MSG} from \"./constants/index.js\";\nimport {getTestResultMsg} from \"./cli/utils/messages.js\";\n\nclass TestManager {\n #tests = [];\n #testDepth = [];\n #beforeEachArr = [];\n #placeHolder = {\n 's': (value) => value,\n 'o': (value) => JSON.stringify(value),\n };\n\n describe(str, fn) {\n this.#testDepth.push(str);\n const prevLength = this.#beforeEachArr.length;\n fn();\n this.#beforeEachArr.length = prevLength;\n this.#testDepth.pop();\n }\n\n test(description, fn) {\n const beforeEachHooks = [...this.#beforeEachArr];\n\n const testObj = {\n description,\n fn: async () => {\n for (const hook of beforeEachHooks) {\n await hook();\n }\n await fn();\n },\n path: this.#testDepth.join(RESULT_MSG.DIRECTORY_DELIMITER),\n }\n this.#tests.push(testObj);\n }\n\n testEach(cases) {\n return (description, fn) => {\n cases.forEach(testCase => {\n const args = Array.isArray(testCase) ? testCase : [testCase];\n this.test(this.#formatDescription(args, description), () => fn(...args));\n });\n };\n }\n\n beforeEach(fn) {\n this.#beforeEachArr.push(fn);\n }\n\n getTests() {\n return [...this.#tests];\n }\n\n clearTests() {\n this.#tests = [];\n this.#testDepth = [];\n this.#beforeEachArr = [];\n }\n\n async run() {\n let passed = NUM.ZERO;\n let failed = NUM.ZERO;\n\n for (const test of testManager.getTests()) {\n try {\n await test.fn();\n console.log(formatSuccessMessage(test));\n passed++;\n clearAllMocks();\n } catch (error) {\n console.log(formatFailureMessage(test, error));\n failed++;\n }\n }\n\n console.log(getTestResultMsg(RESULT_MSG.TESTS, passed, failed));\n\n testManager.clearTests();\n\n return {passed, failed};\n }\n\n #getMatcherForReplace = () => {\n return new RegExp(`%([${Object.keys(this.#placeHolder).join('')}])`, 'g')\n };\n\n #formatDescription(args, description) {\n let argIndex = 0;\n return description.replace(this.#getMatcherForReplace(), (match, type) => {\n if (argIndex >= args.length) return match;\n\n const formatter = this.#placeHolder[type];\n\n return formatter ? formatter(args[argIndex++]) : match;\n });\n }\n}\n\nexport const testManager = new TestManager();","import {formatErrorMsg, formatThrowErrorMsg} from \"./utils/formatString.js\";\n\nconst runArgFnc = (actual) => {\n if (typeof actual === 'function') {\n return actual();\n }\n return actual;\n};\n\nexport const toBe = (actual, expected) => {\n const value = runArgFnc(actual);\n if (value !== expected) {\n throw new Error(formatErrorMsg(expected, value));\n }\n};\n\nexport const toEqual = (actual, expected) => {\n const value = runArgFnc(actual);\n if (JSON.stringify(value) !== JSON.stringify(expected)) {\n throw new Error(formatErrorMsg(expected, value));\n }\n};\n\nexport const toThrow = (actual, expected) => {\n try {\n runArgFnc(actual);\n } catch (e) {\n if (!e.message.includes(expected)) {\n throw new Error(formatErrorMsg(expected, e.message));\n }\n return;\n }\n throw new Error(formatThrowErrorMsg(expected));\n};\n\nexport const toBeTruthy = (actual) => {\n const value = runArgFnc(actual);\n if (!value) {\n throw new Error(formatErrorMsg(true, value));\n }\n};\n\nexport const toBeFalsy = (actual) => {\n const value = runArgFnc(actual);\n if (value) {\n throw new Error(formatErrorMsg(false, value));\n }\n};\n","import {toBe, toBeFalsy, toBeTruthy, toEqual, toThrow} from \"./matchers.js\";\n\nexport const expect = (actual) => {\n return {\n toBe(expected) {\n toBe(actual, expected);\n },\n toEqual(expected) {\n toEqual(actual, expected);\n },\n toThrow(expected) {\n toThrow(actual, expected);\n },\n toBeTruthy() {\n toBeTruthy(actual);\n },\n toBeFalsy() {\n toBeFalsy(actual);\n }\n }\n};\n","import {testManager} from \"./src/testManager.js\";\nimport {clearAllMocks, isMocked, mock, unmock, mockStore} from './src/mock/store.js';\nimport {expect} from \"./src/expect.js\";\nimport {makeMockFnc} from \"./src/mock/utils/changeModuleExports.js\";\n\n/**\n * 테스트 케이스를 정의합니다.\n * @param {string} description - 테스트 설명\n * @param {Function} fn - 테스트 함수\n *\n * @example\n * test('더하기 테스트', () => {\n * expect(1 + 2).toBe(3);\n * });\n */\nexport const test = (description, fn) => testManager.test(description, fn);\n\n/**\n * 배열 형태의 테스트 케이스를 반복 실행합니다.\n * @param {Array<Array>} cases - 테스트 케이스 배열\n * @returns {Function} 테스트 실행 함수\n *\n * @example\n * test.each([\n * [1, 2, 3],\n * [2, 3, 5],\n * ])('add(%s, %s) = %s', (a, b, expected) => {\n * expect(a + b).toBe(expected);\n * });\n */\ntest.each = (cases) => testManager.testEach(cases);\n\n/**\n * 테스트 그룹을 정의합니다. 중첩 가능합니다.\n * @param {string} suiteName - 그룹 이름\n * @param {Function} fn - 그룹 내부 테스트들을 정의하는 함수\n *\n * @example\n * describe('계산기', () => {\n * test('더하기', () => {\n * expect(1 + 1).toBe(2);\n * });\n * });\n */\nexport const describe = (suiteName, fn) => testManager.describe(suiteName, fn);\n\n/**\n * 각 테스트 실행 전에 실행될 함수를 등록합니다.\n * @param {Function} fn - 전처리 함수\n *\n * @example\n * describe('카운터 테스트', () => {\n * let counter;\n *\n * beforeEach(() => {\n * counter = 0;\n * });\n *\n * test('초기값은 0', () => {\n * expect(counter).toBe(0);\n * });\n * });\n */\nexport const beforeEach = (fn) => testManager.beforeEach(fn);\n\n/**\n * 등록된 모든 테스트를 실행합니다.\n * @returns {Promise<{passed: number, failed: number}>} 테스트 결과\n *\n * @example\n * const { passed, failed } = await run();\n * console.log(`${passed} passed, ${failed} failed`);\n */\nexport const run = () => testManager.run();\n\n/**\n * 값을 검증하는 matcher 함수들을 반환합니다.\n * @function\n * @param {*} actual - 검증할 값\n * @returns {Object} matcher 함수들\n *\n * @example\n * expect(1 + 1).toBe(2);\n * expect([1, 2, 3]).toEqual([1, 2, 3]);\n * expect(() => { throw new Error('error') }).toThrow('error');\n * expect(true).toBeTruthy();\n * expect(false).toBeFalsy();\n */\nexport {expect};\n\nexport {mock, clearAllMocks, unmock, isMocked, mockStore};\n\nexport const fn = makeMockFnc;\n"],"names":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -34,21 +34,85 @@ const formatFailureMessage = (test, error) => {
|
|
|
34
34
|
return messages.join('\n');
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
const
|
|
37
|
+
const formatErrorMsg = (expect, actual) => {
|
|
38
38
|
return `Expected ${JSON.stringify(expect)} but got ${JSON.stringify(actual)}`;
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
const
|
|
41
|
+
const formatThrowErrorMsg = (expect) => {
|
|
42
42
|
return `Expected function to throw an error containing "${expect}", but it did not throw`;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
/**
|
|
46
|
+
* 목업 함수의 메서드 타입 정의
|
|
47
|
+
* @typedef {Object} MockMethods
|
|
48
|
+
* @property {function(function): MockMethods} mockImplementation - 구현 설정
|
|
49
|
+
* @property {function(...*): MockMethods} mockReturnValueOnce - 일회성 반환값 설정
|
|
50
|
+
* @property {function(*): MockMethods} mockReturnValue - 반환값 설정
|
|
51
|
+
* @property {function(): void} mockClear - 목업 상태 초기화
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {function} mockFn
|
|
56
|
+
* @param {Object} state
|
|
57
|
+
* @returns {{mockImplementation(*): this, mockReturnValueOnce(...[*]): this, mockReturnValue(*): this, mockClear(): this}|*}
|
|
58
|
+
*/
|
|
59
|
+
const mockFunctions = (mockFn, state) => {
|
|
60
|
+
return {
|
|
61
|
+
mockImplementation(newImpl) {
|
|
62
|
+
state.curImplement = newImpl;
|
|
63
|
+
return mockFn;
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
mockReturnValueOnce(...value) {
|
|
67
|
+
state.returnQueue.push(...value);
|
|
68
|
+
return mockFn;
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
mockReturnValue(value) {
|
|
72
|
+
state.curImplement = () => value;
|
|
73
|
+
return mockFn;
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
mockClear() {
|
|
77
|
+
state.returnQueue = [];
|
|
78
|
+
state.curImplement = () => null;
|
|
79
|
+
return mockFn;
|
|
80
|
+
},
|
|
81
|
+
}
|
|
48
82
|
};
|
|
49
83
|
|
|
50
|
-
|
|
51
|
-
|
|
84
|
+
/**
|
|
85
|
+
* 목업 함수로 변환하는 로직
|
|
86
|
+
* @param {function} [implementation] - 목업 함수 로직 (선택, 기본값: () => null)
|
|
87
|
+
* @returns {(function(...*): *) & MockMethods} 호출 가능하면서 목업 메서드를 가진 함수
|
|
88
|
+
*/
|
|
89
|
+
const makeMockFnc = (implementation = (() => null)) => {
|
|
90
|
+
const state = {
|
|
91
|
+
returnQueue: [],
|
|
92
|
+
curImplement: implementation,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const mockFn = (...args) => {
|
|
96
|
+
if (state.returnQueue.length > 0) {
|
|
97
|
+
return state.returnQueue.shift();
|
|
98
|
+
}
|
|
99
|
+
return state.curImplement(...args);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const methods = mockFunctions(mockFn, state);
|
|
103
|
+
Object.assign(mockFn, methods);
|
|
104
|
+
|
|
105
|
+
return mockFn;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const changeModuleExports = (moduleExports) => {
|
|
109
|
+
const result = {};
|
|
110
|
+
|
|
111
|
+
for (const moduleName in moduleExports) {
|
|
112
|
+
result[moduleName] = makeMockFnc(moduleExports[moduleName]);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return result;
|
|
52
116
|
};
|
|
53
117
|
|
|
54
118
|
const mockStore = new Map();
|
|
@@ -58,7 +122,9 @@ const clearAllMocks = () => {
|
|
|
58
122
|
};
|
|
59
123
|
|
|
60
124
|
const mock = (modulePath, mockExports) => {
|
|
61
|
-
|
|
125
|
+
const mockedExports = changeModuleExports(mockExports);
|
|
126
|
+
mockStore.set(modulePath, mockedExports);
|
|
127
|
+
return mockStore.get(modulePath);
|
|
62
128
|
};
|
|
63
129
|
|
|
64
130
|
const unmock = (modulePath) => {
|
|
@@ -86,6 +152,10 @@ class TestManager {
|
|
|
86
152
|
#tests = [];
|
|
87
153
|
#testDepth = [];
|
|
88
154
|
#beforeEachArr = [];
|
|
155
|
+
#placeHolder = {
|
|
156
|
+
's': (value) => value,
|
|
157
|
+
'o': (value) => JSON.stringify(value),
|
|
158
|
+
};
|
|
89
159
|
|
|
90
160
|
describe(str, fn) {
|
|
91
161
|
this.#testDepth.push(str);
|
|
@@ -157,12 +227,16 @@ class TestManager {
|
|
|
157
227
|
return {passed, failed};
|
|
158
228
|
}
|
|
159
229
|
|
|
230
|
+
#getMatcherForReplace = () => {
|
|
231
|
+
return new RegExp(`%([${Object.keys(this.#placeHolder).join('')}])`, 'g')
|
|
232
|
+
};
|
|
233
|
+
|
|
160
234
|
#formatDescription(args, description) {
|
|
161
235
|
let argIndex = 0;
|
|
162
|
-
return description.replace(getMatcherForReplace(), (match, type) => {
|
|
236
|
+
return description.replace(this.#getMatcherForReplace(), (match, type) => {
|
|
163
237
|
if (argIndex >= args.length) return match;
|
|
164
238
|
|
|
165
|
-
const formatter = placeHolder[type];
|
|
239
|
+
const formatter = this.#placeHolder[type];
|
|
166
240
|
|
|
167
241
|
return formatter ? formatter(args[argIndex++]) : match;
|
|
168
242
|
});
|
|
@@ -181,14 +255,14 @@ const runArgFnc = (actual) => {
|
|
|
181
255
|
const toBe = (actual, expected) => {
|
|
182
256
|
const value = runArgFnc(actual);
|
|
183
257
|
if (value !== expected) {
|
|
184
|
-
throw new Error(
|
|
258
|
+
throw new Error(formatErrorMsg(expected, value));
|
|
185
259
|
}
|
|
186
260
|
};
|
|
187
261
|
|
|
188
262
|
const toEqual = (actual, expected) => {
|
|
189
263
|
const value = runArgFnc(actual);
|
|
190
264
|
if (JSON.stringify(value) !== JSON.stringify(expected)) {
|
|
191
|
-
throw new Error(
|
|
265
|
+
throw new Error(formatErrorMsg(expected, value));
|
|
192
266
|
}
|
|
193
267
|
};
|
|
194
268
|
|
|
@@ -197,24 +271,24 @@ const toThrow = (actual, expected) => {
|
|
|
197
271
|
runArgFnc(actual);
|
|
198
272
|
} catch (e) {
|
|
199
273
|
if (!e.message.includes(expected)) {
|
|
200
|
-
throw new Error(
|
|
274
|
+
throw new Error(formatErrorMsg(expected, e.message));
|
|
201
275
|
}
|
|
202
276
|
return;
|
|
203
277
|
}
|
|
204
|
-
throw new Error(
|
|
278
|
+
throw new Error(formatThrowErrorMsg(expected));
|
|
205
279
|
};
|
|
206
280
|
|
|
207
281
|
const toBeTruthy = (actual) => {
|
|
208
282
|
const value = runArgFnc(actual);
|
|
209
283
|
if (!value) {
|
|
210
|
-
throw new Error(
|
|
284
|
+
throw new Error(formatErrorMsg(true, value));
|
|
211
285
|
}
|
|
212
286
|
};
|
|
213
287
|
|
|
214
288
|
const toBeFalsy = (actual) => {
|
|
215
289
|
const value = runArgFnc(actual);
|
|
216
290
|
if (value) {
|
|
217
|
-
throw new Error(
|
|
291
|
+
throw new Error(formatErrorMsg(false, value));
|
|
218
292
|
}
|
|
219
293
|
};
|
|
220
294
|
|
|
@@ -308,5 +382,7 @@ const beforeEach = (fn) => testManager.beforeEach(fn);
|
|
|
308
382
|
*/
|
|
309
383
|
const run = () => testManager.run();
|
|
310
384
|
|
|
311
|
-
|
|
385
|
+
const fn = makeMockFnc;
|
|
386
|
+
|
|
387
|
+
export { beforeEach, clearAllMocks, describe, expect, fn, isMocked, mock, mockStore, run, test, unmock };
|
|
312
388
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/constants/view.js","../src/utils/consoleColor.js","../src/constants/index.js","../src/utils/formatString.js","../src/mock/store.js","../src/utils/messages.js","../src/testManager.js","../src/matchers.js","../src/expect.js","../index.js"],"sourcesContent":["export const COLORS = {\n reset: '\\x1b[0m',\n green: '\\x1b[32m',\n red: '\\x1b[31m',\n yellow: '\\x1b[33m',\n cyan: '\\x1b[36m',\n gray: '\\x1b[90m',\n bold: '\\x1b[1m'\n};\n","import {COLORS} from \"../constants/view.js\";\n\nexport const colorize = (text, color) => `${color}${text}${COLORS.reset}`;\n\nexport const green = (text) => colorize(text, COLORS.green + COLORS.bold);\nexport const red = (text) => colorize(text, COLORS.red + COLORS.bold);\nexport const bold = (text) => colorize(text, COLORS.bold);\nexport const yellow = (text) => colorize(text, COLORS.yellow + COLORS.bold);\n","export const PATH = {\n NODE_MODULES: 'node_modules',\n TEST_DIRECTORY: 'test',\n TEST_FILE: '.test.js',\n JAVASCRIPT_FILE: '.js',\n BIN: 'bin',\n DIST: 'dist',\n DANNYSIR_JS_TE: '@dannysir/js-te',\n};\n\nexport const RESULT_MSG = {\n TESTS: 'Tests: ',\n TOTAL: 'Total Result: ',\n CHECK: '✓ ',\n CROSS: '✗ ',\n DIRECTORY_DELIMITER: ' > ',\n EMPTY: '',\n};\n\nexport const NUM = {\n ZERO: 0,\n ONE: 1,\n};\n\nexport const MODULE_TYPE = {\n MODULE: 'module',\n ESM: 'esm',\n CJS: 'cjs',\n};\n","import {green, red} from \"./consoleColor.js\";\nimport {RESULT_MSG} from \"../constants/index.js\";\n\nexport const formatSuccessMessage = (test) => {\n const pathString = test.path === '' ? RESULT_MSG.EMPTY : test.path + RESULT_MSG.DIRECTORY_DELIMITER;\n return green(RESULT_MSG.CHECK) + pathString + test.description;\n};\n\nexport const formatFailureMessage = (test, error) => {\n const messages = [];\n messages.push(red(RESULT_MSG.CROSS) + test.path + test.description);\n messages.push(red(` Error Message : ${error.message}`));\n return messages.join('\\n');\n};\n\nexport const getErrorMsg = (expect, actual) => {\n return `Expected ${JSON.stringify(expect)} but got ${JSON.stringify(actual)}`;\n};\n\nexport const getThrowErrorMsg = (expect) => {\n return `Expected function to throw an error containing \"${expect}\", but it did not throw`;\n};\n\nexport const placeHolder = {\n 's': (value) => value,\n 'o': (value) => JSON.stringify(value),\n};\n\nexport const getMatcherForReplace = () => {\n return new RegExp(`%([${Object.keys(placeHolder).join('')}])`, 'g')\n};\n","export const mockStore = new Map();\n\nexport const clearAllMocks = () => {\n mockStore.clear();\n}\n\nexport const mock = (modulePath, mockExports) => {\n mockStore.set(modulePath, mockExports);\n}\n\nexport const unmock = (modulePath) => {\n mockStore.delete(modulePath);\n}\n\nexport const isMocked = (modulePath) => {\n return mockStore.has(modulePath);\n}\n","import {bold, green, red, yellow} from \"./consoleColor.js\";\n\nexport const getTestResultMsg = (title, success, fail) => {\n let msg = '\\n';\n\n msg += title;\n msg += green(success + ' passed') + ', ';\n if (fail) {\n msg += red(fail + ' failed') + ', ';\n }\n msg += bold(success + fail + ' total');\n\n return msg;\n};\n\nexport const getFileCountString = (n) => {\n return `\\nFound ${green(n)} test file(s)`;\n};\n\nexport const getFilePath = (path) => {\n return `\\n${yellow(path)}\\n`;\n};\n\nexport const getErrorMsgInLogic = (error) => {\n return red(`\\n✗ Test execution failed\\n Error: ${error}\\n`)\n};\n","import {formatFailureMessage, formatSuccessMessage, getMatcherForReplace, placeHolder} from \"./utils/formatString.js\";\nimport {clearAllMocks} from \"./mock/store.js\";\nimport {NUM, RESULT_MSG} from \"./constants/index.js\";\nimport {getTestResultMsg} from \"./utils/messages.js\";\n\nclass TestManager {\n #tests = [];\n #testDepth = [];\n #beforeEachArr = [];\n\n describe(str, fn) {\n this.#testDepth.push(str);\n const prevLength = this.#beforeEachArr.length;\n fn();\n this.#beforeEachArr.length = prevLength;\n this.#testDepth.pop();\n }\n\n test(description, fn) {\n const beforeEachHooks = [...this.#beforeEachArr];\n\n const testObj = {\n description,\n fn: async () => {\n for (const hook of beforeEachHooks) {\n await hook();\n }\n await fn();\n },\n path: this.#testDepth.join(RESULT_MSG.DIRECTORY_DELIMITER),\n }\n this.#tests.push(testObj);\n }\n\n testEach(cases) {\n return (description, fn) => {\n cases.forEach(testCase => {\n const args = Array.isArray(testCase) ? testCase : [testCase];\n this.test(this.#formatDescription(args, description), () => fn(...args));\n });\n };\n }\n\n beforeEach(fn) {\n this.#beforeEachArr.push(fn);\n }\n\n getTests() {\n return [...this.#tests];\n }\n\n clearTests() {\n this.#tests = [];\n this.#testDepth = [];\n this.#beforeEachArr = [];\n }\n\n async run() {\n let passed = NUM.ZERO;\n let failed = NUM.ZERO;\n\n for (const test of testManager.getTests()) {\n try {\n await test.fn();\n console.log(formatSuccessMessage(test));\n passed++;\n clearAllMocks();\n } catch (error) {\n console.log(formatFailureMessage(test, error));\n failed++;\n }\n }\n\n console.log(getTestResultMsg(RESULT_MSG.TESTS, passed, failed));\n\n testManager.clearTests();\n\n return {passed, failed};\n }\n\n #formatDescription(args, description) {\n let argIndex = 0;\n return description.replace(getMatcherForReplace(), (match, type) => {\n if (argIndex >= args.length) return match;\n\n const formatter = placeHolder[type];\n\n return formatter ? formatter(args[argIndex++]) : match;\n });\n }\n}\n\nexport const testManager = new TestManager();","import {getErrorMsg, getThrowErrorMsg} from \"./utils/formatString.js\";\n\nconst runArgFnc = (actual) => {\n if (typeof actual === 'function') {\n return actual();\n }\n return actual;\n};\n\nexport const toBe = (actual, expected) => {\n const value = runArgFnc(actual);\n if (value !== expected) {\n throw new Error(getErrorMsg(expected, value));\n }\n};\n\nexport const toEqual = (actual, expected) => {\n const value = runArgFnc(actual);\n if (JSON.stringify(value) !== JSON.stringify(expected)) {\n throw new Error(getErrorMsg(expected, value));\n }\n};\n\nexport const toThrow = (actual, expected) => {\n try {\n runArgFnc(actual);\n } catch (e) {\n if (!e.message.includes(expected)) {\n throw new Error(getErrorMsg(expected, e.message));\n }\n return;\n }\n throw new Error(getThrowErrorMsg(expected));\n};\n\nexport const toBeTruthy = (actual) => {\n const value = runArgFnc(actual);\n if (!value) {\n throw new Error(getErrorMsg(true, value));\n }\n};\n\nexport const toBeFalsy = (actual) => {\n const value = runArgFnc(actual);\n if (value) {\n throw new Error(getErrorMsg(false, value));\n }\n};\n","import {toBe, toBeFalsy, toBeTruthy, toEqual, toThrow} from \"./matchers.js\";\n\nexport const expect = (actual) => {\n return {\n toBe(expected) {\n toBe(actual, expected);\n },\n toEqual(expected) {\n toEqual(actual, expected);\n },\n toThrow(expected) {\n toThrow(actual, expected);\n },\n toBeTruthy() {\n toBeTruthy(actual);\n },\n toBeFalsy() {\n toBeFalsy(actual);\n }\n }\n};\n","import {testManager} from \"./src/testManager.js\";\nimport {clearAllMocks, isMocked, mock, unmock, mockStore} from './src/mock/store.js';\nimport {expect} from \"./src/expect.js\";\n\n/**\n * 테스트 케이스를 정의합니다.\n * @param {string} description - 테스트 설명\n * @param {Function} fn - 테스트 함수\n *\n * @example\n * test('더하기 테스트', () => {\n * expect(1 + 2).toBe(3);\n * });\n */\nexport const test = (description, fn) => testManager.test(description, fn);\n\n/**\n * 배열 형태의 테스트 케이스를 반복 실행합니다.\n * @param {Array<Array>} cases - 테스트 케이스 배열\n * @returns {Function} 테스트 실행 함수\n *\n * @example\n * test.each([\n * [1, 2, 3],\n * [2, 3, 5],\n * ])('add(%s, %s) = %s', (a, b, expected) => {\n * expect(a + b).toBe(expected);\n * });\n */\ntest.each = (cases) => testManager.testEach(cases);\n\n/**\n * 테스트 그룹을 정의합니다. 중첩 가능합니다.\n * @param {string} suiteName - 그룹 이름\n * @param {Function} fn - 그룹 내부 테스트들을 정의하는 함수\n *\n * @example\n * describe('계산기', () => {\n * test('더하기', () => {\n * expect(1 + 1).toBe(2);\n * });\n * });\n */\nexport const describe = (suiteName, fn) => testManager.describe(suiteName, fn);\n\n/**\n * 각 테스트 실행 전에 실행될 함수를 등록합니다.\n * @param {Function} fn - 전처리 함수\n *\n * @example\n * describe('카운터 테스트', () => {\n * let counter;\n *\n * beforeEach(() => {\n * counter = 0;\n * });\n *\n * test('초기값은 0', () => {\n * expect(counter).toBe(0);\n * });\n * });\n */\nexport const beforeEach = (fn) => testManager.beforeEach(fn);\n\n/**\n * 등록된 모든 테스트를 실행합니다.\n * @returns {Promise<{passed: number, failed: number}>} 테스트 결과\n *\n * @example\n * const { passed, failed } = await run();\n * console.log(`${passed} passed, ${failed} failed`);\n */\nexport const run = () => testManager.run();\n\n/**\n * 값을 검증하는 matcher 함수들을 반환합니다.\n * @function\n * @param {*} actual - 검증할 값\n * @returns {Object} matcher 함수들\n *\n * @example\n * expect(1 + 1).toBe(2);\n * expect([1, 2, 3]).toEqual([1, 2, 3]);\n * expect(() => { throw new Error('error') }).toThrow('error');\n * expect(true).toBeTruthy();\n * expect(false).toBeFalsy();\n */\nexport {expect};\n\nexport {mock, clearAllMocks, unmock, isMocked, mockStore};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/constants/view.js","../src/utils/consoleColor.js","../src/constants/index.js","../src/utils/formatString.js","../src/mock/utils/mockFunctions.js","../src/mock/utils/changeModuleExports.js","../src/mock/store.js","../src/cli/utils/messages.js","../src/testManager.js","../src/matchers.js","../src/expect.js","../index.js"],"sourcesContent":["export const COLORS = {\n reset: '\\x1b[0m',\n green: '\\x1b[32m',\n red: '\\x1b[31m',\n yellow: '\\x1b[33m',\n cyan: '\\x1b[36m',\n gray: '\\x1b[90m',\n bold: '\\x1b[1m'\n};\n","import {COLORS} from \"../constants/view.js\";\n\nexport const colorize = (text, color) => `${color}${text}${COLORS.reset}`;\n\nexport const green = (text) => colorize(text, COLORS.green + COLORS.bold);\nexport const red = (text) => colorize(text, COLORS.red + COLORS.bold);\nexport const bold = (text) => colorize(text, COLORS.bold);\nexport const yellow = (text) => colorize(text, COLORS.yellow + COLORS.bold);\n","export const PATH = {\n NODE_MODULES: 'node_modules',\n TEST_DIRECTORY: 'test',\n TEST_FILE: '.test.js',\n JAVASCRIPT_FILE: '.js',\n BIN: 'bin',\n DIST: 'dist',\n DANNYSIR_JS_TE: '@dannysir/js-te',\n};\n\nexport const RESULT_MSG = {\n TESTS: 'Tests: ',\n TOTAL: 'Total Result: ',\n CHECK: '✓ ',\n CROSS: '✗ ',\n DIRECTORY_DELIMITER: ' > ',\n EMPTY: '',\n};\n\nexport const NUM = {\n ZERO: 0,\n ONE: 1,\n};\n\nexport const MODULE_TYPE = {\n MODULE: 'module',\n ESM: 'esm',\n CJS: 'cjs',\n};\n","import {green, red} from \"./consoleColor.js\";\nimport {RESULT_MSG} from \"../constants/index.js\";\n\nexport const formatSuccessMessage = (test) => {\n const pathString = test.path === '' ? RESULT_MSG.EMPTY : test.path + RESULT_MSG.DIRECTORY_DELIMITER;\n return green(RESULT_MSG.CHECK) + pathString + test.description;\n};\n\nexport const formatFailureMessage = (test, error) => {\n const messages = [];\n messages.push(red(RESULT_MSG.CROSS) + test.path + test.description);\n messages.push(red(` Error Message : ${error.message}`));\n return messages.join('\\n');\n};\n\nexport const formatErrorMsg = (expect, actual) => {\n return `Expected ${JSON.stringify(expect)} but got ${JSON.stringify(actual)}`;\n};\n\nexport const formatThrowErrorMsg = (expect) => {\n return `Expected function to throw an error containing \"${expect}\", but it did not throw`;\n};\n","/**\n * 목업 함수의 메서드 타입 정의\n * @typedef {Object} MockMethods\n * @property {function(function): MockMethods} mockImplementation - 구현 설정\n * @property {function(...*): MockMethods} mockReturnValueOnce - 일회성 반환값 설정\n * @property {function(*): MockMethods} mockReturnValue - 반환값 설정\n * @property {function(): void} mockClear - 목업 상태 초기화\n */\n\n/**\n * @param {function} mockFn\n * @param {Object} state\n * @returns {{mockImplementation(*): this, mockReturnValueOnce(...[*]): this, mockReturnValue(*): this, mockClear(): this}|*}\n */\nexport const mockFunctions = (mockFn, state) => {\n return {\n mockImplementation(newImpl) {\n state.curImplement = newImpl;\n return mockFn;\n },\n\n mockReturnValueOnce(...value) {\n state.returnQueue.push(...value);\n return mockFn;\n },\n\n mockReturnValue(value) {\n state.curImplement = () => value;\n return mockFn;\n },\n\n mockClear() {\n state.returnQueue = [];\n state.curImplement = () => null;\n return mockFn;\n },\n }\n};\n","import {mockFunctions} from \"./mockFunctions.js\";\n\n/**\n * 목업 함수로 변환하는 로직\n * @param {function} [implementation] - 목업 함수 로직 (선택, 기본값: () => null)\n * @returns {(function(...*): *) & MockMethods} 호출 가능하면서 목업 메서드를 가진 함수\n */\nexport const makeMockFnc = (implementation = (() => null)) => {\n const state = {\n returnQueue: [],\n curImplement: implementation,\n };\n\n const mockFn = (...args) => {\n if (state.returnQueue.length > 0) {\n return state.returnQueue.shift();\n }\n return state.curImplement(...args);\n };\n\n const methods = mockFunctions(mockFn, state);\n Object.assign(mockFn, methods);\n\n return mockFn;\n};\n\nexport const changeModuleExports = (moduleExports) => {\n const result = {};\n\n for (const moduleName in moduleExports) {\n result[moduleName] = makeMockFnc(moduleExports[moduleName]);\n }\n\n return result;\n};\n","import {changeModuleExports} from \"./utils/changeModuleExports.js\";\n\nexport const mockStore = new Map();\n\nexport const clearAllMocks = () => {\n mockStore.clear();\n}\n\nexport const mock = (modulePath, mockExports) => {\n const mockedExports = changeModuleExports(mockExports);\n mockStore.set(modulePath, mockedExports);\n return mockStore.get(modulePath);\n}\n\nexport const unmock = (modulePath) => {\n mockStore.delete(modulePath);\n}\n\nexport const isMocked = (modulePath) => {\n return mockStore.has(modulePath);\n}\n","import {bold, green, red, yellow} from \"../../utils/consoleColor.js\";\n\nexport const getTestResultMsg = (title, success, fail) => {\n let msg = '\\n';\n\n msg += title;\n msg += green(success + ' passed') + ', ';\n if (fail) {\n msg += red(fail + ' failed') + ', ';\n }\n msg += bold(success + fail + ' total');\n\n return msg;\n};\n\nexport const getFileCountString = (n) => {\n return `\\nFound ${green(n)} test file(s)`;\n};\n\nexport const getFilePath = (path) => {\n return `\\n${yellow(path)}\\n`;\n};\n\nexport const getErrorMsgInLogic = (error) => {\n return red(`\\n✗ Test execution failed\\n Error: ${error}\\n`)\n};\n","import {formatFailureMessage, formatSuccessMessage} from \"./utils/formatString.js\";\nimport {clearAllMocks} from \"./mock/store.js\";\nimport {NUM, RESULT_MSG} from \"./constants/index.js\";\nimport {getTestResultMsg} from \"./cli/utils/messages.js\";\n\nclass TestManager {\n #tests = [];\n #testDepth = [];\n #beforeEachArr = [];\n #placeHolder = {\n 's': (value) => value,\n 'o': (value) => JSON.stringify(value),\n };\n\n describe(str, fn) {\n this.#testDepth.push(str);\n const prevLength = this.#beforeEachArr.length;\n fn();\n this.#beforeEachArr.length = prevLength;\n this.#testDepth.pop();\n }\n\n test(description, fn) {\n const beforeEachHooks = [...this.#beforeEachArr];\n\n const testObj = {\n description,\n fn: async () => {\n for (const hook of beforeEachHooks) {\n await hook();\n }\n await fn();\n },\n path: this.#testDepth.join(RESULT_MSG.DIRECTORY_DELIMITER),\n }\n this.#tests.push(testObj);\n }\n\n testEach(cases) {\n return (description, fn) => {\n cases.forEach(testCase => {\n const args = Array.isArray(testCase) ? testCase : [testCase];\n this.test(this.#formatDescription(args, description), () => fn(...args));\n });\n };\n }\n\n beforeEach(fn) {\n this.#beforeEachArr.push(fn);\n }\n\n getTests() {\n return [...this.#tests];\n }\n\n clearTests() {\n this.#tests = [];\n this.#testDepth = [];\n this.#beforeEachArr = [];\n }\n\n async run() {\n let passed = NUM.ZERO;\n let failed = NUM.ZERO;\n\n for (const test of testManager.getTests()) {\n try {\n await test.fn();\n console.log(formatSuccessMessage(test));\n passed++;\n clearAllMocks();\n } catch (error) {\n console.log(formatFailureMessage(test, error));\n failed++;\n }\n }\n\n console.log(getTestResultMsg(RESULT_MSG.TESTS, passed, failed));\n\n testManager.clearTests();\n\n return {passed, failed};\n }\n\n #getMatcherForReplace = () => {\n return new RegExp(`%([${Object.keys(this.#placeHolder).join('')}])`, 'g')\n };\n\n #formatDescription(args, description) {\n let argIndex = 0;\n return description.replace(this.#getMatcherForReplace(), (match, type) => {\n if (argIndex >= args.length) return match;\n\n const formatter = this.#placeHolder[type];\n\n return formatter ? formatter(args[argIndex++]) : match;\n });\n }\n}\n\nexport const testManager = new TestManager();","import {formatErrorMsg, formatThrowErrorMsg} from \"./utils/formatString.js\";\n\nconst runArgFnc = (actual) => {\n if (typeof actual === 'function') {\n return actual();\n }\n return actual;\n};\n\nexport const toBe = (actual, expected) => {\n const value = runArgFnc(actual);\n if (value !== expected) {\n throw new Error(formatErrorMsg(expected, value));\n }\n};\n\nexport const toEqual = (actual, expected) => {\n const value = runArgFnc(actual);\n if (JSON.stringify(value) !== JSON.stringify(expected)) {\n throw new Error(formatErrorMsg(expected, value));\n }\n};\n\nexport const toThrow = (actual, expected) => {\n try {\n runArgFnc(actual);\n } catch (e) {\n if (!e.message.includes(expected)) {\n throw new Error(formatErrorMsg(expected, e.message));\n }\n return;\n }\n throw new Error(formatThrowErrorMsg(expected));\n};\n\nexport const toBeTruthy = (actual) => {\n const value = runArgFnc(actual);\n if (!value) {\n throw new Error(formatErrorMsg(true, value));\n }\n};\n\nexport const toBeFalsy = (actual) => {\n const value = runArgFnc(actual);\n if (value) {\n throw new Error(formatErrorMsg(false, value));\n }\n};\n","import {toBe, toBeFalsy, toBeTruthy, toEqual, toThrow} from \"./matchers.js\";\n\nexport const expect = (actual) => {\n return {\n toBe(expected) {\n toBe(actual, expected);\n },\n toEqual(expected) {\n toEqual(actual, expected);\n },\n toThrow(expected) {\n toThrow(actual, expected);\n },\n toBeTruthy() {\n toBeTruthy(actual);\n },\n toBeFalsy() {\n toBeFalsy(actual);\n }\n }\n};\n","import {testManager} from \"./src/testManager.js\";\nimport {clearAllMocks, isMocked, mock, unmock, mockStore} from './src/mock/store.js';\nimport {expect} from \"./src/expect.js\";\nimport {makeMockFnc} from \"./src/mock/utils/changeModuleExports.js\";\n\n/**\n * 테스트 케이스를 정의합니다.\n * @param {string} description - 테스트 설명\n * @param {Function} fn - 테스트 함수\n *\n * @example\n * test('더하기 테스트', () => {\n * expect(1 + 2).toBe(3);\n * });\n */\nexport const test = (description, fn) => testManager.test(description, fn);\n\n/**\n * 배열 형태의 테스트 케이스를 반복 실행합니다.\n * @param {Array<Array>} cases - 테스트 케이스 배열\n * @returns {Function} 테스트 실행 함수\n *\n * @example\n * test.each([\n * [1, 2, 3],\n * [2, 3, 5],\n * ])('add(%s, %s) = %s', (a, b, expected) => {\n * expect(a + b).toBe(expected);\n * });\n */\ntest.each = (cases) => testManager.testEach(cases);\n\n/**\n * 테스트 그룹을 정의합니다. 중첩 가능합니다.\n * @param {string} suiteName - 그룹 이름\n * @param {Function} fn - 그룹 내부 테스트들을 정의하는 함수\n *\n * @example\n * describe('계산기', () => {\n * test('더하기', () => {\n * expect(1 + 1).toBe(2);\n * });\n * });\n */\nexport const describe = (suiteName, fn) => testManager.describe(suiteName, fn);\n\n/**\n * 각 테스트 실행 전에 실행될 함수를 등록합니다.\n * @param {Function} fn - 전처리 함수\n *\n * @example\n * describe('카운터 테스트', () => {\n * let counter;\n *\n * beforeEach(() => {\n * counter = 0;\n * });\n *\n * test('초기값은 0', () => {\n * expect(counter).toBe(0);\n * });\n * });\n */\nexport const beforeEach = (fn) => testManager.beforeEach(fn);\n\n/**\n * 등록된 모든 테스트를 실행합니다.\n * @returns {Promise<{passed: number, failed: number}>} 테스트 결과\n *\n * @example\n * const { passed, failed } = await run();\n * console.log(`${passed} passed, ${failed} failed`);\n */\nexport const run = () => testManager.run();\n\n/**\n * 값을 검증하는 matcher 함수들을 반환합니다.\n * @function\n * @param {*} actual - 검증할 값\n * @returns {Object} matcher 함수들\n *\n * @example\n * expect(1 + 1).toBe(2);\n * expect([1, 2, 3]).toEqual([1, 2, 3]);\n * expect(() => { throw new Error('error') }).toThrow('error');\n * expect(true).toBeTruthy();\n * expect(false).toBeFalsy();\n */\nexport {expect};\n\nexport {mock, clearAllMocks, unmock, isMocked, mockStore};\n\nexport const fn = makeMockFnc;\n"],"names":[],"mappings":"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"}
|
package/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {testManager} from "./src/testManager.js";
|
|
2
2
|
import {clearAllMocks, isMocked, mock, unmock, mockStore} from './src/mock/store.js';
|
|
3
3
|
import {expect} from "./src/expect.js";
|
|
4
|
+
import {makeMockFnc} from "./src/mock/utils/changeModuleExports.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* 테스트 케이스를 정의합니다.
|
|
@@ -88,3 +89,5 @@ export const run = () => testManager.run();
|
|
|
88
89
|
export {expect};
|
|
89
90
|
|
|
90
91
|
export {mock, clearAllMocks, unmock, isMocked, mockStore};
|
|
92
|
+
|
|
93
|
+
export const fn = makeMockFnc;
|
package/package.json
CHANGED
package/src/cli/runTests.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import {getFilePath} from "
|
|
3
|
-
import {transformFiles} from "
|
|
2
|
+
import {getFilePath} from "./utils/messages.js";
|
|
3
|
+
import {transformFiles} from "./utils/transformFiles.js";
|
|
4
4
|
import {NUM} from "../constants/index.js";
|
|
5
5
|
|
|
6
6
|
export const runTests = async (jsTe, mockedPaths, testFiles) => {
|
package/src/cli/setupFiles.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {findAllSourceFiles, findTestFiles} from "
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {transformFiles} from "../utils/transformFiles.js";
|
|
1
|
+
import {findAllSourceFiles, findTestFiles} from "./utils/findFiles.js";
|
|
2
|
+
import {collectMockedPaths} from "./utils/collectMocks.js";
|
|
3
|
+
import {transformFiles} from "./utils/transformFiles.js";
|
|
5
4
|
|
|
6
5
|
export const setupFiles = () => {
|
|
7
6
|
const testFiles = findTestFiles(process.cwd());
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import {transformSync} from "@babel/core";
|
|
3
|
-
import {createMockCollectorPlugin} from "
|
|
4
|
-
import {BABEL} from "
|
|
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();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import {transformSync} from "@babel/core";
|
|
3
|
-
import {babelTransformImport} from "
|
|
4
|
-
import {red} from "
|
|
5
|
-
import {BABEL} from "
|
|
3
|
+
import {babelTransformImport} from "../../babelPlugins/babelTransformImport.js";
|
|
4
|
+
import {red} from "../../utils/consoleColor.js";
|
|
5
|
+
import {BABEL} from "../../constants/babel.js";
|
|
6
6
|
|
|
7
7
|
const originalFiles = new Map();
|
|
8
8
|
|
package/src/matchers.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {formatErrorMsg, formatThrowErrorMsg} from "./utils/formatString.js";
|
|
2
2
|
|
|
3
3
|
const runArgFnc = (actual) => {
|
|
4
4
|
if (typeof actual === 'function') {
|
|
@@ -10,14 +10,14 @@ const runArgFnc = (actual) => {
|
|
|
10
10
|
export const toBe = (actual, expected) => {
|
|
11
11
|
const value = runArgFnc(actual);
|
|
12
12
|
if (value !== expected) {
|
|
13
|
-
throw new Error(
|
|
13
|
+
throw new Error(formatErrorMsg(expected, value));
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export const toEqual = (actual, expected) => {
|
|
18
18
|
const value = runArgFnc(actual);
|
|
19
19
|
if (JSON.stringify(value) !== JSON.stringify(expected)) {
|
|
20
|
-
throw new Error(
|
|
20
|
+
throw new Error(formatErrorMsg(expected, value));
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
23
|
|
|
@@ -26,23 +26,23 @@ export const toThrow = (actual, expected) => {
|
|
|
26
26
|
runArgFnc(actual);
|
|
27
27
|
} catch (e) {
|
|
28
28
|
if (!e.message.includes(expected)) {
|
|
29
|
-
throw new Error(
|
|
29
|
+
throw new Error(formatErrorMsg(expected, e.message));
|
|
30
30
|
}
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
throw new Error(
|
|
33
|
+
throw new Error(formatThrowErrorMsg(expected));
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
export const toBeTruthy = (actual) => {
|
|
37
37
|
const value = runArgFnc(actual);
|
|
38
38
|
if (!value) {
|
|
39
|
-
throw new Error(
|
|
39
|
+
throw new Error(formatErrorMsg(true, value));
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export const toBeFalsy = (actual) => {
|
|
44
44
|
const value = runArgFnc(actual);
|
|
45
45
|
if (value) {
|
|
46
|
-
throw new Error(
|
|
46
|
+
throw new Error(formatErrorMsg(false, value));
|
|
47
47
|
}
|
|
48
48
|
};
|
package/src/mock/store.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {changeModuleExports} from "./utils/changeModuleExports.js";
|
|
2
|
+
|
|
1
3
|
export const mockStore = new Map();
|
|
2
4
|
|
|
3
5
|
export const clearAllMocks = () => {
|
|
@@ -5,7 +7,9 @@ export const clearAllMocks = () => {
|
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
export const mock = (modulePath, mockExports) => {
|
|
8
|
-
|
|
10
|
+
const mockedExports = changeModuleExports(mockExports);
|
|
11
|
+
mockStore.set(modulePath, mockedExports);
|
|
12
|
+
return mockStore.get(modulePath);
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
export const unmock = (modulePath) => {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {mockFunctions} from "./mockFunctions.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 목업 함수로 변환하는 로직
|
|
5
|
+
* @param {function} [implementation] - 목업 함수 로직 (선택, 기본값: () => null)
|
|
6
|
+
* @returns {(function(...*): *) & MockMethods} 호출 가능하면서 목업 메서드를 가진 함수
|
|
7
|
+
*/
|
|
8
|
+
export const makeMockFnc = (implementation = (() => null)) => {
|
|
9
|
+
const state = {
|
|
10
|
+
returnQueue: [],
|
|
11
|
+
curImplement: implementation,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const mockFn = (...args) => {
|
|
15
|
+
if (state.returnQueue.length > 0) {
|
|
16
|
+
return state.returnQueue.shift();
|
|
17
|
+
}
|
|
18
|
+
return state.curImplement(...args);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const methods = mockFunctions(mockFn, state);
|
|
22
|
+
Object.assign(mockFn, methods);
|
|
23
|
+
|
|
24
|
+
return mockFn;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const changeModuleExports = (moduleExports) => {
|
|
28
|
+
const result = {};
|
|
29
|
+
|
|
30
|
+
for (const moduleName in moduleExports) {
|
|
31
|
+
result[moduleName] = makeMockFnc(moduleExports[moduleName]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 목업 함수의 메서드 타입 정의
|
|
3
|
+
* @typedef {Object} MockMethods
|
|
4
|
+
* @property {function(function): MockMethods} mockImplementation - 구현 설정
|
|
5
|
+
* @property {function(...*): MockMethods} mockReturnValueOnce - 일회성 반환값 설정
|
|
6
|
+
* @property {function(*): MockMethods} mockReturnValue - 반환값 설정
|
|
7
|
+
* @property {function(): void} mockClear - 목업 상태 초기화
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {function} mockFn
|
|
12
|
+
* @param {Object} state
|
|
13
|
+
* @returns {{mockImplementation(*): this, mockReturnValueOnce(...[*]): this, mockReturnValue(*): this, mockClear(): this}|*}
|
|
14
|
+
*/
|
|
15
|
+
export const mockFunctions = (mockFn, state) => {
|
|
16
|
+
return {
|
|
17
|
+
mockImplementation(newImpl) {
|
|
18
|
+
state.curImplement = newImpl;
|
|
19
|
+
return mockFn;
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
mockReturnValueOnce(...value) {
|
|
23
|
+
state.returnQueue.push(...value);
|
|
24
|
+
return mockFn;
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
mockReturnValue(value) {
|
|
28
|
+
state.curImplement = () => value;
|
|
29
|
+
return mockFn;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
mockClear() {
|
|
33
|
+
state.returnQueue = [];
|
|
34
|
+
state.curImplement = () => null;
|
|
35
|
+
return mockFn;
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
};
|
package/src/testManager.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import {formatFailureMessage, formatSuccessMessage
|
|
1
|
+
import {formatFailureMessage, formatSuccessMessage} from "./utils/formatString.js";
|
|
2
2
|
import {clearAllMocks} from "./mock/store.js";
|
|
3
3
|
import {NUM, RESULT_MSG} from "./constants/index.js";
|
|
4
|
-
import {getTestResultMsg} from "./utils/messages.js";
|
|
4
|
+
import {getTestResultMsg} from "./cli/utils/messages.js";
|
|
5
5
|
|
|
6
6
|
class TestManager {
|
|
7
7
|
#tests = [];
|
|
8
8
|
#testDepth = [];
|
|
9
9
|
#beforeEachArr = [];
|
|
10
|
+
#placeHolder = {
|
|
11
|
+
's': (value) => value,
|
|
12
|
+
'o': (value) => JSON.stringify(value),
|
|
13
|
+
};
|
|
10
14
|
|
|
11
15
|
describe(str, fn) {
|
|
12
16
|
this.#testDepth.push(str);
|
|
@@ -78,12 +82,16 @@ class TestManager {
|
|
|
78
82
|
return {passed, failed};
|
|
79
83
|
}
|
|
80
84
|
|
|
85
|
+
#getMatcherForReplace = () => {
|
|
86
|
+
return new RegExp(`%([${Object.keys(this.#placeHolder).join('')}])`, 'g')
|
|
87
|
+
};
|
|
88
|
+
|
|
81
89
|
#formatDescription(args, description) {
|
|
82
90
|
let argIndex = 0;
|
|
83
|
-
return description.replace(getMatcherForReplace(), (match, type) => {
|
|
91
|
+
return description.replace(this.#getMatcherForReplace(), (match, type) => {
|
|
84
92
|
if (argIndex >= args.length) return match;
|
|
85
93
|
|
|
86
|
-
const formatter = placeHolder[type];
|
|
94
|
+
const formatter = this.#placeHolder[type];
|
|
87
95
|
|
|
88
96
|
return formatter ? formatter(args[argIndex++]) : match;
|
|
89
97
|
});
|
|
@@ -13,19 +13,10 @@ export const formatFailureMessage = (test, error) => {
|
|
|
13
13
|
return messages.join('\n');
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export const
|
|
16
|
+
export const formatErrorMsg = (expect, actual) => {
|
|
17
17
|
return `Expected ${JSON.stringify(expect)} but got ${JSON.stringify(actual)}`;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
export const
|
|
20
|
+
export const formatThrowErrorMsg = (expect) => {
|
|
21
21
|
return `Expected function to throw an error containing "${expect}", but it did not throw`;
|
|
22
22
|
};
|
|
23
|
-
|
|
24
|
-
export const placeHolder = {
|
|
25
|
-
's': (value) => value,
|
|
26
|
-
'o': (value) => JSON.stringify(value),
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const getMatcherForReplace = () => {
|
|
30
|
-
return new RegExp(`%([${Object.keys(placeHolder).join('')}])`, 'g')
|
|
31
|
-
};
|