Skip to content

Commit 914075f

Browse files
authored
Merge pull request #22 from klmhyeonwoo/feature/utils-workspace-yeom
feat: sleep util function
2 parents af356d7 + 5b2b242 commit 914075f

5 files changed

Lines changed: 215 additions & 1 deletion

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const empty = commonUtil.isEmpty(""); // true
5454
const notEmpty = commonUtil.isEmpty("hello"); // false
5555
const nullCheck = commonUtil.isNull(null); // true
5656
const notNull = commonUtil.isNull("hello"); // false
57+
await commonUtil.sleep(1000); // Pauses execution for 1 second
5758

5859
// Cookie utilities
5960
cookieUtil.setCookie("theme", "dark");
@@ -87,6 +88,7 @@ const theme = cookieUtil.getCookie("theme");
8788

8889
- `isEmpty(value: unknown): boolean` - Checks if a value is empty (null, undefined, "", 0, [], {}, empty Set/Map, NaN, or invalid Date)
8990
- `isNull(value: unknown): value is null` - Type guard that checks if a value is null and narrows the type
91+
- `sleep(ms: number): Promise<void>` - Pauses execution for a specified number of milliseconds
9092

9193
### CookieUtil
9294

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
2+
import { sleep } from ".";
3+
4+
describe("sleep", () => {
5+
// 각 'test'가 실행되기 전에 가짜 타이머를 활성화합니다.
6+
beforeEach(() => {
7+
// Vitest에게 setTimeout, setInterval 같은 타이머 함수들을
8+
// 직접 제어할 수 있는 가짜(Fake) 함수로 대체하도록 지시합니다.
9+
// 이렇게 하면 실제로 시간을 기다리지 않고 테스트할 수 있습니다.
10+
vi.useFakeTimers();
11+
});
12+
13+
// 각 테스트가 끝난 후 실제 타이머로 복원하여 다른 테스트에 영향을 주지 않도록 합니다.
14+
afterEach(() => {
15+
// 가짜로 만들었던 타이머 함수들을 원래의 실제(Real) 함수로 되돌립니다.
16+
// 테스트 간의 독립성을 보장하기 위한 좋은 습관입니다.
17+
// useFakeTimers 사용 이후에 이 과정을 하지 않으면, 다른 테스트에도 영향을 줄 수 있습니다.
18+
vi.useRealTimers();
19+
});
20+
21+
test("지정된 시간(ms) 이후에 resolve 되어야 한다", async () => {
22+
const promise = sleep(2000);
23+
24+
// 가짜 시간을 2000ms (2초) 만큼 앞으로 '빨리 감기'합니다.
25+
// 이 시간 안에 실행되기로 예약된 setTimeout 콜백이 즉시 실행됩니다.
26+
// Async 버전은 이로 인해 resolve되는 Promise가 완료될 때까지 기다립니다.
27+
await vi.advanceTimersByTimeAsync(2000);
28+
29+
// Promise가 성공적으로 완료되었는지 확인합니다.
30+
await expect(promise).resolves.toBeUndefined();
31+
});
32+
33+
test("지정된 시간 이전에는 resolve 되면 안 된다", async () => {
34+
const onResolve = vi.fn();
35+
36+
sleep(3000).then(onResolve);
37+
38+
await vi.advanceTimersByTimeAsync(2999);
39+
40+
// 이때 onResolve 함수는 아직 호출되지 않았어야 합니다.
41+
expect(onResolve).not.toHaveBeenCalled();
42+
43+
await vi.advanceTimersByTimeAsync(1);
44+
45+
// 이제 onResolve 함수가 정확히 1번 호출되었어야 합니다.
46+
expect(onResolve).toHaveBeenCalledTimes(1);
47+
});
48+
49+
test("ms가 0일 때 다음 틱(tick)에 resolve 되어야 한다", async () => {
50+
const onResolve = vi.fn();
51+
52+
const promise = sleep(0).then(onResolve);
53+
54+
expect(onResolve).not.toHaveBeenCalled();
55+
56+
// 시간을 특정 시간만큼 감는 대신, 현재 대기 중인 타이머만 즉시 실행합니다.
57+
// setTimeout(fn, 0)과 같은 코드를 테스트할 때 유용합니다.
58+
await vi.runOnlyPendingTimersAsync();
59+
60+
expect(onResolve).toHaveBeenCalledTimes(1);
61+
62+
await expect(promise).resolves.toBeUndefined();
63+
});
64+
65+
test("음수 값은 0처럼 처리되어야 한다", async () => {
66+
const onResolve = vi.fn();
67+
const promise = sleep(-5).then(onResolve);
68+
69+
// -5ms는 0ms처럼 처리되어 즉시(다음 tick)에 실행되어야 합니다.
70+
await vi.runOnlyPendingTimersAsync();
71+
72+
expect(onResolve).toHaveBeenCalledTimes(1);
73+
74+
await expect(promise).resolves.toBeUndefined();
75+
});
76+
});

package/commonUtil/sleep/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* 지정된 시간(ms)만큼 코드 실행을 지연시키는 Promise를 반환합니다.
3+
* 음수 방지
4+
* @param ms 지연시킬 시간 (밀리초 단위)
5+
* @returns {Promise<void>} 시간이 지나면 resolve되는 Promise
6+
*/
7+
export function sleep(ms: number): Promise<void> {
8+
const delay = Math.max(0, ms | 0);
9+
return new Promise((resolve) => setTimeout(resolve, delay));
10+
}

vite.config.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ export default defineConfig({
44
test: {
55
coverage: {
66
reporter: ["text", "json-summary", "json"],
7-
exclude: [],
7+
exclude: [
8+
"**/node_modules/**",
9+
"**/dist/**",
10+
"**/vite-env.d.ts",
11+
"**/vite.config.ts",
12+
"package/index.ts",
13+
"package/*/index.ts",
14+
],
815
},
916
reporters: ["default", "junit"],
1017
outputFile: "vitest-report.xml",

vitest-report.xml

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<testsuites name="vitest tests" tests="48" failures="0" errors="0" time="0.019278585">
3+
<testsuite name="package/commonUtil/isEmpty/index.test.ts" timestamp="2025-08-30T12:03:11.810Z" hostname="users-MacBook-Pro.local" tests="16" failures="0" errors="0" skipped="0" time="0.002465375">
4+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 비어있지 않은 값에 대해 false를 반환해야 함 &gt; 비어있지 않은 문자열에 대해 false를 반환한다" time="0.000749166">
5+
</testcase>
6+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 비어있지 않은 값에 대해 false를 반환해야 함 &gt; 0이 아닌 숫자에 대해 false를 반환한다" time="0.000143375">
7+
</testcase>
8+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 비어있지 않은 값에 대해 false를 반환해야 함 &gt; 비어있지 않은 배열에 대해 false를 반환한다" time="0.000110625">
9+
</testcase>
10+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 비어있지 않은 값에 대해 false를 반환해야 함 &gt; 0에 대해 false를 반환한다" time="0.000050042">
11+
</testcase>
12+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 비어있지 않은 값에 대해 false를 반환해야 함 &gt; 비어있지 않은 객체에 대해 false를 반환한다" time="0.000103041">
13+
</testcase>
14+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 비어있지 않은 값에 대해 false를 반환해야 함 &gt; 불린 값에 대해 false를 반환한다" time="0.000066375">
15+
</testcase>
16+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 빈 값에 대해 true를 반환해야 함 &gt; 빈 문자열에 대해 true를 반환한다" time="0.000044208">
17+
</testcase>
18+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 빈 값에 대해 true를 반환해야 함 &gt; 빈 배열에 대해 true를 반환한다" time="0.000038333">
19+
</testcase>
20+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 빈 값에 대해 true를 반환해야 함 &gt; 빈 객체에 대해 true를 반환한다" time="0.000055375">
21+
</testcase>
22+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 빈 값에 대해 true를 반환해야 함 &gt; null과 undefined에 대해 true를 반환한다" time="0.000082708">
23+
</testcase>
24+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 엣지 케이스 &gt; NaN을 처리한다" time="0.000042875">
25+
</testcase>
26+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 엣지 케이스 &gt; Date 객체를 처리한다" time="0.000063834">
27+
</testcase>
28+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 엣지 케이스 &gt; Set과 Map을 처리한다" time="0.000088375">
29+
</testcase>
30+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 엣지 케이스 &gt; 함수를 처리한다" time="0.000045084">
31+
</testcase>
32+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 엣지 케이스 &gt; 심볼을 처리한다" time="0.000033458">
33+
</testcase>
34+
<testcase classname="package/commonUtil/isEmpty/index.test.ts" name="isEmpty 유틸 함수 테스트 &gt; 엣지 케이스 &gt; 빈 심볼의 경우 true를 반환한다" time="0.000031834">
35+
</testcase>
36+
</testsuite>
37+
<testsuite name="package/commonUtil/sleep/index.test.ts" timestamp="2025-08-30T12:03:11.812Z" hostname="users-MacBook-Pro.local" tests="4" failures="0" errors="0" skipped="0" time="0.005190709">
38+
<testcase classname="package/commonUtil/sleep/index.test.ts" name="sleep &gt; 지정된 시간(ms) 이후에 resolve 되어야 한다" time="0.0021435">
39+
</testcase>
40+
<testcase classname="package/commonUtil/sleep/index.test.ts" name="sleep &gt; 지정된 시간 이전에는 resolve 되면 안 된다" time="0.001051667">
41+
</testcase>
42+
<testcase classname="package/commonUtil/sleep/index.test.ts" name="sleep &gt; ms가 0일 때 다음 틱(tick)에 resolve 되어야 한다" time="0.000560541">
43+
</testcase>
44+
<testcase classname="package/commonUtil/sleep/index.test.ts" name="sleep &gt; 음수 값은 0처럼 처리되어야 한다" time="0.000797">
45+
</testcase>
46+
</testsuite>
47+
<testsuite name="package/numberUtil/sum/index.test.ts" timestamp="2025-08-30T12:03:11.813Z" hostname="users-MacBook-Pro.local" tests="2" failures="0" errors="0" skipped="0" time="0.001379125">
48+
<testcase classname="package/numberUtil/sum/index.test.ts" name="1 + 2 + 3은 6이다." time="0.000742209">
49+
</testcase>
50+
<testcase classname="package/numberUtil/sum/index.test.ts" name="5 + 10 + 15는 30이다." time="0.00007575">
51+
</testcase>
52+
</testsuite>
53+
<testsuite name="package/numberUtil/subtract/index.test.ts" timestamp="2025-08-30T12:03:11.813Z" hostname="users-MacBook-Pro.local" tests="4" failures="0" errors="0" skipped="0" time="0.001465541">
54+
<testcase classname="package/numberUtil/subtract/index.test.ts" name="2 - 1은 1이다." time="0.000714459">
55+
</testcase>
56+
<testcase classname="package/numberUtil/subtract/index.test.ts" name="5 - 10 - 15는 -20이다." time="0.000075">
57+
</testcase>
58+
<testcase classname="package/numberUtil/subtract/index.test.ts" name="-1 - (-2)는 1이다." time="0.000057083">
59+
</testcase>
60+
<testcase classname="package/numberUtil/subtract/index.test.ts" name="인자 없는 경우 0을 반환한다." time="0.000063208">
61+
</testcase>
62+
</testsuite>
63+
<testsuite name="package/objectUtil/clearNullProperties/index.test.ts" timestamp="2025-08-30T12:03:11.814Z" hostname="users-MacBook-Pro.local" tests="1" failures="0" errors="0" skipped="0" time="0.001439167">
64+
<testcase classname="package/objectUtil/clearNullProperties/index.test.ts" name="만약 Null이 객체에 존재한다면, Null이 없는 객체가 반환된다." time="0.000938917">
65+
</testcase>
66+
</testsuite>
67+
<testsuite name="package/stringUtil/escapeHtml/index.test.ts" timestamp="2025-08-30T12:03:11.814Z" hostname="users-MacBook-Pro.local" tests="1" failures="0" errors="0" skipped="0" time="0.001372417">
68+
<testcase classname="package/stringUtil/escapeHtml/index.test.ts" name="HTML 특수 문자를 이스케이프한다." time="0.000737458">
69+
</testcase>
70+
</testsuite>
71+
<testsuite name="package/objectUtil/deepFreeze/index.test.ts" timestamp="2025-08-30T12:03:11.814Z" hostname="users-MacBook-Pro.local" tests="1" failures="0" errors="0" skipped="0" time="0.001219417">
72+
<testcase classname="package/objectUtil/deepFreeze/index.test.ts" name="객체의 불변성이 유지된다." time="0.000718334">
73+
</testcase>
74+
</testsuite>
75+
<testsuite name="package/stringUtil/unescapeHtml/index.test.ts" timestamp="2025-08-30T12:03:11.814Z" hostname="users-MacBook-Pro.local" tests="1" failures="0" errors="0" skipped="0" time="0.001217">
76+
<testcase classname="package/stringUtil/unescapeHtml/index.test.ts" name="HTML 특수 문자를 언이스케이프한다." time="0.000711459">
77+
</testcase>
78+
</testsuite>
79+
<testsuite name="package/validationUtil/checkEmail/index.test.ts" timestamp="2025-08-30T12:03:11.814Z" hostname="users-MacBook-Pro.local" tests="2" failures="0" errors="0" skipped="0" time="0.001385209">
80+
<testcase classname="package/validationUtil/checkEmail/index.test.ts" name="올바른 이메일인 경우 true 값을 리턴합니다." time="0.000735875">
81+
</testcase>
82+
<testcase classname="package/validationUtil/checkEmail/index.test.ts" name="올바르지 않은 이메일인 경우 false 값을 리턴합니다." time="0.000121917">
83+
</testcase>
84+
</testsuite>
85+
<testsuite name="package/validationUtil/checkHttpUrl/index.test.ts" timestamp="2025-08-30T12:03:11.814Z" hostname="users-MacBook-Pro.local" tests="16" failures="0" errors="0" skipped="0" time="0.002144625">
86+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효한 HTTP/HTTPS URL 문자열이 주어졌을 때 &gt; &apos;http://example.com&apos;에 대해 true를 반환한다" time="0.000696875">
87+
</testcase>
88+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효한 HTTP/HTTPS URL 문자열이 주어졌을 때 &gt; &apos;https://example.com&apos;에 대해 true를 반환한다" time="0.00007175">
89+
</testcase>
90+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효한 HTTP/HTTPS URL 문자열이 주어졌을 때 &gt; &apos;https://www.example.com&apos;에 대해 true를 반환한다" time="0.000051583">
91+
</testcase>
92+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효한 HTTP/HTTPS URL 문자열이 주어졌을 때 &gt; &apos;http://example.com/path/to/resource&apos;에 대해 true를 반환한다" time="0.000051292">
93+
</testcase>
94+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효한 HTTP/HTTPS URL 문자열이 주어졌을 때 &gt; &apos;https://example.com?query=123&amp;key=value&apos;에 대해 true를 반환한다" time="0.000051583">
95+
</testcase>
96+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효한 HTTP/HTTPS URL 문자열이 주어졌을 때 &gt; &apos;http://localhost:3000&apos;에 대해 true를 반환한다" time="0.000049292">
97+
</testcase>
98+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효한 HTTP/HTTPS URL 문자열이 주어졌을 때 &gt; &apos;https://sub.domain.co.uk/page#section&apos;에 대해 true를 반환한다" time="0.000038291">
99+
</testcase>
100+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효하지 않은 URL 문자열이 주어졌을 때 &gt; &apos;www.example.com&apos;에 대해 false를 반환한다" time="0.00006725">
101+
</testcase>
102+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효하지 않은 URL 문자열이 주어졌을 때 &gt; &apos;example.com&apos;에 대해 false를 반환한다" time="0.000055959">
103+
</testcase>
104+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효하지 않은 URL 문자열이 주어졌을 때 &gt; &apos;/relative/path&apos;에 대해 false를 반환한다" time="0.00006425">
105+
</testcase>
106+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효하지 않은 URL 문자열이 주어졌을 때 &gt; &apos;ftp://example.com&apos;에 대해 false를 반환한다" time="0.000040708">
107+
</testcase>
108+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효하지 않은 URL 문자열이 주어졌을 때 &gt; &apos;mailto:test@example.com&apos;에 대해 false를 반환한다" time="0.000029666">
109+
</testcase>
110+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효하지 않은 URL 문자열이 주어졌을 때 &gt; &apos;http:// example.com&apos;에 대해 false를 반환한다" time="0.000036834">
111+
</testcase>
112+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효하지 않은 URL 문자열이 주어졌을 때 &gt; &apos;https://&apos;에 대해 false를 반환한다" time="0.000034541">
113+
</testcase>
114+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효하지 않은 URL 문자열이 주어졌을 때 &gt; &apos;just a random string&apos;에 대해 false를 반환한다" time="0.000053084">
115+
</testcase>
116+
<testcase classname="package/validationUtil/checkHttpUrl/index.test.ts" name="URL 유효성 검사 &gt; 유효하지 않은 URL 문자열이 주어졌을 때 &gt; &apos;&apos;에 대해 false를 반환한다" time="0.000040125">
117+
</testcase>
118+
</testsuite>
119+
</testsuites>

0 commit comments

Comments
 (0)