@dannysir/js-te 0.3.3 → 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/dist/index.cjs +79 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +79 -2
- package/dist/index.mjs.map +1 -1
- package/index.js +3 -0
- package/package.json +1 -1
- package/src/mock/store.js +5 -1
- package/src/mock/utils/changeModuleExports.js +35 -0
- package/src/mock/utils/mockFunctions.js +38 -0
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/dist/index.cjs
CHANGED
|
@@ -44,6 +44,79 @@ 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
|
+
* @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
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
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;
|
|
118
|
+
};
|
|
119
|
+
|
|
47
120
|
const mockStore = new Map();
|
|
48
121
|
|
|
49
122
|
const clearAllMocks = () => {
|
|
@@ -51,7 +124,9 @@ const clearAllMocks = () => {
|
|
|
51
124
|
};
|
|
52
125
|
|
|
53
126
|
const mock = (modulePath, mockExports) => {
|
|
54
|
-
|
|
127
|
+
const mockedExports = changeModuleExports(mockExports);
|
|
128
|
+
mockStore.set(modulePath, mockedExports);
|
|
129
|
+
return mockStore.get(modulePath);
|
|
55
130
|
};
|
|
56
131
|
|
|
57
132
|
const unmock = (modulePath) => {
|
|
@@ -309,10 +384,13 @@ const beforeEach = (fn) => testManager.beforeEach(fn);
|
|
|
309
384
|
*/
|
|
310
385
|
const run = () => testManager.run();
|
|
311
386
|
|
|
387
|
+
const fn = makeMockFnc;
|
|
388
|
+
|
|
312
389
|
exports.beforeEach = beforeEach;
|
|
313
390
|
exports.clearAllMocks = clearAllMocks;
|
|
314
391
|
exports.describe = describe;
|
|
315
392
|
exports.expect = expect;
|
|
393
|
+
exports.fn = fn;
|
|
316
394
|
exports.isMocked = isMocked;
|
|
317
395
|
exports.mock = mock;
|
|
318
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/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","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 \"../../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\";\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
|
@@ -42,6 +42,79 @@ 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
|
+
* @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
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
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;
|
|
116
|
+
};
|
|
117
|
+
|
|
45
118
|
const mockStore = new Map();
|
|
46
119
|
|
|
47
120
|
const clearAllMocks = () => {
|
|
@@ -49,7 +122,9 @@ const clearAllMocks = () => {
|
|
|
49
122
|
};
|
|
50
123
|
|
|
51
124
|
const mock = (modulePath, mockExports) => {
|
|
52
|
-
|
|
125
|
+
const mockedExports = changeModuleExports(mockExports);
|
|
126
|
+
mockStore.set(modulePath, mockedExports);
|
|
127
|
+
return mockStore.get(modulePath);
|
|
53
128
|
};
|
|
54
129
|
|
|
55
130
|
const unmock = (modulePath) => {
|
|
@@ -307,5 +382,7 @@ const beforeEach = (fn) => testManager.beforeEach(fn);
|
|
|
307
382
|
*/
|
|
308
383
|
const run = () => testManager.run();
|
|
309
384
|
|
|
310
|
-
|
|
385
|
+
const fn = makeMockFnc;
|
|
386
|
+
|
|
387
|
+
export { beforeEach, clearAllMocks, describe, expect, fn, isMocked, mock, mockStore, run, test, unmock };
|
|
311
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/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","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 \"../../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\";\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/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
|
+
};
|