realstone2 ๋‹˜์˜ ์ƒ์„ธํŽ˜์ด์ง€ ๏ผž [3ํŒ€ ์—ฌ์ง„์„] Chapter ๐Ÿฆ 3-1. ํ”„๋ก ํŠธ์—”๋“œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๐Ÿฆ

๋‚œ์ด๋„์— ๋งž๋Š” ํ…œํ”Œ๋ฆฟ์„ ์„ ํƒํ•ด์„œ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”!


7์ฃผ์ฐจ ๊ณผ์ œ ์ฒดํฌํฌ์ธํŠธ

๊ธฐ๋ณธ

HARD

7์ฃผ์ฐจ ๊ณผ์ œ ์ฒดํฌํฌ์ธํŠธ

๊ธฐ๋ณธ๊ณผ์ œ

  • ์ด 11๊ฐœ์˜ ํŒŒ์ผ, 115๊ฐœ์˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ๋ฌด์‚ฌํžˆ ์ž‘์„ฑํ•˜๊ณ  ํ†ต๊ณผ์‹œํ‚จ๋‹ค.

์งˆ๋ฌธ

Q. handlersUtils์— ๋‚จ๊ธด ์งˆ๋ฌธ์— ๋‹ต๋ณ€ํ•ด์ฃผ์„ธ์š”.

์ผ๋‹จ ๋ฌธ์ œ๋Š” handler์—์„œ json์„ ์ˆ˜์ •ํ•˜๋Š” handler๊ฐ€ ์ „์—ญ์œผ๋กœ ์„ค์ • ๋˜์–ด์žˆ๋‹ค๋Š” ์ ์ด๋‹ค. ๋ณ‘๋ ฌ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋ ๊ฒฝ์šฐ ๋ชจ๋‘๊ฐ€ ๊ฐ™์€ json์„ ์ˆ˜์ •ํ•˜๊ฒŒ๋˜๋Š” ๊ฒƒ์ด ๋ฌธ์ œ๋‹ค.

์–ด๋–ป๊ฒŒํ•˜๋ฉด ๋ณ‘๋ ฌ์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•  ๋•Œ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰์‹œํ‚ฌ๊นŒ?

  1. test๋งˆ๋‹ค ๋…๋ฆฝ์ ์œผ๋กœ events๋ฅผ ์…‹ํŒ…ํ•ด์•ผํ•œ๋‹ค.
  2. test๋งˆ๋‹ค server handler๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•ด์•ผํ•œ๋‹ค.

์งฑ๋Œ์„ ๊ณ„์† ๊ตด๋ ค๋ด๋„ API์ž์ฒด์—์„œ ์ˆ˜์ •ํ•˜๋Š” ๋‚ด์šฉ์ด๋‹ค๋ณด๋‹ˆ events๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์…‹ํŒ…ํ•˜๋ ค๋ฉด ๊ฒฐ๊ตญ ํ…Œ์ŠคํŠธ๋งˆ๋‹ค ์ƒˆ๋กœ handler๋ฅผ ์ƒ์„ฑํ•ด์•ผ๋˜๋Š”๊ฒŒ ์•„๋‹Œ๊ฐ€? ๋ผ๋Š” ๊ฒฐ๋ก ์„ ์ง€์—ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ํ…Œ์ŠคํŠธ๋งˆ๋‹ค ์ƒˆ๋กœ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์…‹ํŒ…ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

1. ํ…Œ์ŠคํŠธ๋งˆ๋‹ค setupServer ์„ค์ •ํ•˜๊ธฐ

https://mswjs.io/docs/api/setup-server

While we commend setting up request interception globally, as a part of your testing setup, you may also use setupServer in individual tests, if you want to. Just make sure to choose one pattern and follow it throughout your testsโ€”multiple setupServer calls is not a good idea!

๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด๋ดค์„ ๋•Œ setupServer๋Š” ๊ธ€๋กœ๋ฒŒ๋กœ ํ•œ๋ฒˆ ์„ ์–ธํ•˜๊ฑฐ๋‚˜, ํ…Œ์ŠคํŠธ๋ณ„๋กœ ์„ค์ •ํ•ด์•ผํ•œ๋‹ค๊ณ  ์ ํ˜€์žˆ๋‹ค.

์ค‘๋ณต์œผ๋กœ ์„ ์–ธํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

์ง€๊ธˆ ๊ตฌ์กฐ์—์„œ setupServer๋ฅผ ํ…Œ์ŠคํŠธ๋งˆ๋‹ค ๋™์ž‘์‹œํ‚ค๋ ค๋ฉด, global๋กœ mockingํ•˜๊ณ  ์žˆ๋Š” ๋กœ์ง์„ ์ œ๊ฑฐํ•ด์•ผํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ๋˜๋ฉด ๋…๋ฆฝ์ ์œผ๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋™์ž‘์‹œํ‚ฌ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ํŠน๋ณ„ํžˆ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•ด์•ผ๋  ์ด์œ ๊ฐ€ ์—†๋Š” ๊ณณ์—์„œ๋„ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋งค๋ฒˆ setupServer ๋กœ์ง์„ ๋„ฃ์–ด์ค˜์•ผํ•œ๋‹ค.

๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์—†์„๊นŒ?

2. handler override ํ•˜๊ธฐ

https://mswjs.io/docs/best-practices/network-behavior-overrides/#resetting-request-handlers

override๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์„๊นŒ ์ฐพ์•„๋ณด๋˜์ค‘ ๋ฌธ์„œ ์ œ๋ชฉ์ด override์ธ ๋‚ด์šฉ์„ ์ฐพ์•˜๋‹ค.

server.use()์™€ resetHandlers()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‚ด๊ฐ€ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ–ˆ๋˜ ๋‚ด์šฉ์„ ํ’€์–ด๋‚ผ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

  1. ์ „์—ญ์ ์œผ๋กœ setup server handler๋“ค์ด ์กด์žฌ
  2. ํ…Œ์ŠคํŠธ ๋‚ด๋ถ€์—์„œ ๊ฐ๊ฐ handler๋ฅผ use()ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด override๋ฅผ ํ•ด์ค˜์„œ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘์‹œํ‚จ๋‹ค.
  3. overrideํ•œ ํ…Œ์ŠคํŠธ์—์„œ๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚  ๋•Œ resetHandlers()๋ฅผ ์‹คํ–‰์‹œ์ผœ ์›์ƒ๋ณต๊ตฌ

๊ทธ๋ฆผ์œผ๋กœ ๊ทธ๋ ค๋ณด๋ฉด ์ด๋Ÿฐ ๋ชจ์Šต์ด์ง€ ์•Š์„๊นŒ? image

Q. ํ…Œ์ŠคํŠธ๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌ๋™์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์ž‘์„ฑํ–ˆ๋˜ ์„ค์ •๋“ค์„ ์†Œ๊ฐœํ•ด์ฃผ์„ธ์š”. ์œ„์—์„œ ์ž‘์„ฑํ•œ ๋‚ด์šฉ์ฒ˜๋Ÿผ server.use() resetHandlers()๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

  • ex)
export const setupMockHandlerCreationError = () => {
  afterEach(() => {
    server.resetHandlers();
  });

  server.use(
    http.post('/api/events', () => {
      return HttpResponse.json({ message: 'Error' }, { status: 500 });
    })
  );
};

์‹ฌํ™” ๊ณผ์ œ

  • App ์ปดํฌ๋„ŒํŠธ ์ ์ ˆํ•œ ๋‹จ์œ„์˜ ์ปดํฌ๋„ŒํŠธ, ํ›…, ์œ ํ‹ธ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ–ˆ๋Š”๊ฐ€?
  • ํ•ด๋‹น ๋ชจ๋“ˆ๋“ค์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ํ…Œ์ŠคํŠธ๋ฅผ 5๊ฐœ ์ด์ƒ ์ž‘์„ฑํ–ˆ๋Š”๊ฐ€?

ใ…Žใ…Žใ…Ž... ์•ˆํ–ˆ์Šต๋‹ˆ๋‹ค... ์•„๋‹ˆ.. ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค..

๊ณผ์ œ ์…€ํ”„ํšŒ๊ณ 

ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋Š” ๋‚˜์˜ ๊ด€์‹ฌ์‚ฌ๋„ ์•„๋‹ˆ์˜€๊ณ , ์Šคํƒ€ํŠธ์—…์—์„œ ๊ณผ์—ฐ ํ•„์š”ํ•œ ๋‚ด์šฉ์ผ๊นŒ? ์‹ถ์€ ์˜๊ตฌ์‹ฌ๋„ ๊ฐ–๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค๋ณด๋‹ˆ ๋‹น์—ฐํžˆ ํ…Œ์ŠคํŠธ์ฝ”๋“œ ์ž์ฒด๋ฅผ ์ฒ˜์Œ ๊ณต๋ถ€ํ•ด๋ดค๋‹ค.

๊ณต๋ถ€ํ•ด๋ณธ ํ›„๊ธฐ๋กœ๋Š” ์ด๋…€์„.. ์šฐ๋ฆฌ ํšŒ์‚ฌ์—์„œ๋„ ๋‹น์žฅ ํ•˜๋‚˜์”ฉ ์‚ฌ์šฉํ•ด๋ด๋„ ๊ดœ์ฐฎ๊ฒ ๋Š”๋ฐ...? ๋ผ๋Š” ์ƒ๊ฐ์„ ํ–ˆ๋‹ค. ํšŒ์‚ฌ์—๋Š” ํ•ต์‹ฌ๊ธฐ๋Šฅ์ด ์˜ทํŽธ์ง‘, ์˜ท๋“ฑ๋ก, ์ฝ”๋””๋“ฑ๋ก ๋“ฑ๋“ฑ ์•ฑ ์ดˆ๊ธฐ๋ถ€ํ„ฐ ์žˆ์—ˆ๋˜ ๊ธฐ์ดˆ๊ธฐ๋Šฅ์ด์žˆ๋‹ค. ํ•ด๋‹น ๊ธฐ๋Šฅ๋“ค์„ ๊ฐœ์„ ํ•˜๊ฑฐ๋‚˜ ๊ณ ๋„ํ™”ํ•  ๋•Œ๋งˆ๋‹ค ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ๋“ค์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š”๊ฒƒ์ด๊ณ , ๊ธฐํš๋„ ์ž˜ ๋ชจ๋ฅด๊ฒ ๊ณ , ๊ธฐ๋Œ€๊ฐ’๋„ ๋ญ”์ง€ ๋ชจ๋ฅด๊ฒ ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ์ด๋Ÿฐ ๊ณณ์— ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ๋„์ž…ํ•ด๋†“์œผ๋ฉด, ์•ˆ์ •์ ์œผ๋กœ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๊ณ  ํŒ€์›๋“ค์—๊ฒŒ ๋„์ž…์„ ๊ณ ๋ คํ•ด๋ณด์ž๊ณ  ์ „๋‹ฌํ•ด๋‘” ์ƒํƒœ์ด๋‹ค.

๊ณผ์ œ๋Š” ๋‚œ์ด๋„๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ, ๋‚˜๋Š” hard๋ฅผ ์„ ํƒํ•˜์˜€๋‹ค. ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋Š” ์™„์ „ ์ฒ˜์Œ ์ ‘ํ•ด๋ณด๊ธดํ•˜์ง€๋งŒ, hard ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ „๋ถ€ ์ˆ˜ํ–‰ํ•ด์•ผ์ง€ ๊ณต๋ถ€ํ–ˆ๋‹ค๊ณ  ๋А๋‚„ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•˜๊ณ  ์‹ฌํ™”๊ณผ์ œ๋Š” ์ฒ˜์Œ๋ถ€ํ„ฐ ํฌ๊ธฐํ•˜๊ณ , ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ํ•™์Šตํ•˜์ž๋Š” ๋ชฉํ‘œ๋ฅผ ๊ฐ–๊ณ  ๊ณผ์ œ์— ์ž„ํ–ˆ๋‹ค. ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ๋‹ค ์ž‘์„ฑํ•˜๊ณ  ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ๊ณผ์ •๋„ ๊ฒช์–ด๋ณด๊ณ  ์‹ถ์—ˆ์ง€๋งŒ, ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋งŒ์œผ๋กœ๋„ ์‰ฝ์ง€ ์•Š์€ ์ฃผ๊ฐ„์ด์—ˆ๋‹ค.

๊ทธ๋ž˜๋„ ์˜ค๋žœ๋งŒ์— AI๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ตฌ๊ธ€๋งํ•˜๊ณ  ๋ฌธ์„œ๋ฅผ ์ฐพ์•„๊ฐ€๋ฉฐ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์˜ ์žฌ๋ฏธ๋„ ๋А๊ผˆ๋‹ค. ์˜ค๋žœ๋งŒ์— ๋ฐ‘๋ฐ”๋‹ฅ๋ถ€ํ„ฐ ๋ชจ๋ฅด๋Š” ๊ฒƒ์„ ํ•™์Šตํ•˜๋‹ˆ ์žฌ๋ฏธ์žˆ์—ˆ๊ณ , AI๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  ๊ณผ์ œํ•˜๋ผ๊ณ  ํ•˜์‹  ์ฝ”์น˜๋‹˜์˜ ๊นŠ์€ ๋œป์„ ๋А๋‚„ ์ˆ˜ ์žˆ์—ˆ๋˜ ์ฃผ๊ฐ„์ด์—ˆ๋‹ค.

๊ณผ์ œ ํƒˆ๋ฝ์„ ๋ณด๋Š” ๊ฒƒ์€ ๋„ˆ๋ฌด ์Šฌํ”„์ง€๋งŒ, hard๊ณ ๋ฅธ ๊ณณ์„ ํ›„ํšŒํ•˜์ง€ ์•Š๋Š”๋‹ค! ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ํ•™์Šตํ–ˆ์œผ๋‹ˆ๊นŒ!!!

๊ธฐ์ˆ ์  ์„ฑ์žฅ

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ์ดํ•ด

Testing Library??? Jest?? Vitest??

์ด๋ฒˆ์— ๋ฐœ์ œ๋ฅผ ๋“ค์œผ๋ฉด์„œ ํ…Œ์ŠคํŒ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ญ๊ณ , jest์™€ vitest๋Š” ๋ฌด์—‡์ด์ง€ ์ •๋ฆฌ๊ฐ€ ๋˜์ง€ ์•Š์•˜๋‹ค.

  • Vitest, Jest vitest์™€ jest๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋Ÿฌ๋„ˆ์ด๋‹ค. ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ  ๊ฒฐ๊ณผ๋ฌผ์„ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ์‹œ์Šคํ…œ์ด๋‹ค.

  • Testing Library? vitest์™€ jest๋ฅผ ์ด์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ๋Œ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ์ด๋‹ค.

์•ฝ๊ฐ„ ์ง„๊ฒฉ์˜๊ฑฐ์ธ ์„ธ๊ณ„๊ด€์œผ๋กœ ๋น„๊ตํ•ด๋ณด์ž๋ฉด,, testing library๋Š” ์ž…์ฒด๊ธฐ๋™์žฅ์น˜ test๋Š” ๊ฑฐ์ธ vitest, jest๋Š” ์กฐ์‚ฌ๋ณ‘๋‹จ, ์ฃผ๋‘”๋ณ‘๋‹จ ์ด๋Ÿฐ ๋А๋‚Œ์ด๋ž„๊นŒ..?

ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๋ฐฉ๋ฒ•

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ์‹์—๋Š” ๋‘๊ฐ€์ง€ ๋ฐฉ์‹์ด ์žˆ๋‹ค.

  1. ๊ตฌํ˜„ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ ๊ตฌํ˜„ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ๊ตฌํ˜„ ์„ธ๋ถ€์‚ฌํ•ญ์— ๋”ฐ๋ผ์„œ ๊ฐœ๋ฐœ์ž ๊ด€์ , ์ฝ”๋“œ ๊ตฌ์กฐ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ๋‚ด๋ถ€ ๋กœ์ง์— ๋Œ€ํ•ด์„œ ์ปค๋ฒ„๋ฆฌ์ง€๊ฐ€ ๋†’๋‹ค.

  2. ๋ช…์„ธ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ ๋ช…์„ธ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ๋Š” ์‚ฌ์šฉ์ž ๊ด€์ , ์š”๊ตฌ์‚ฌํ•ญ ๋ฌธ์„œ์— ๋”ฐ๋ผ์„œ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด์„œ "์ดˆ๊ธฐ ์ƒํƒœ์—์„œ๋Š” ์•Œ๋ฆผ์ด ์—†์–ด์•ผ ํ•œ๋‹ค" ๋ผ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ ์•Œ๋žŒ์ด ์—†์–ด์•ผ ํ•œ๋‹ค๋Š” ๋ช…์„ธ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์ผ๊นŒ ๊ตฌํ˜„ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์ผ๊นŒ?

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค.

it('์ดˆ๊ธฐ ์ƒํƒœ์—์„œ๋Š” ์•Œ๋ฆผ์ด ์—†์–ด์•ผ ํ•œ๋‹ค', async () => {
  const { result: eventsResult } = renderHook(() => useEventOperations(false));

  await screen.findByText('์ผ์ • ๋กœ๋”ฉ ์™„๋ฃŒ!');

  const events = eventsResult.current.events;

  const { result } = renderHook(() => useNotifications(events));

  expect(result.current.notifications).toEqual([]);
});

useEventOperations, useNotifications ๋“ฑ์˜ hook ๋‚ด๋ถ€์—์„œ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„์ด ๋˜์–ด์žˆ๋Š”์ง€๋Š” ํ…Œ์ŠคํŠธํ•˜์ง€ ์•Š์•˜๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๊ฐ€ ๋ช…์„ธ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ์ด๋‹ค.

์˜ฌ๋ฐ”๋ฅธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

๋‹ต๋ณ€์€ ์ •์ ์ด์–ด์•ผํ• ๊นŒ? ๋™์ ์ด์–ด๋„ ๋ ๊นŒ?

์ฒ˜์Œ ๊ณผ์ œ๋ฅผ ์ง„ํ–‰ํ–ˆ์„ ๋•Œ๋Š” ๊ณ ์ •๋œ ํ…Œ์ŠคํŠธ ๋ฐฉ์‹์— ๋Œ€ํ•ด์„œ ์˜๋ฌธ์„ ํ’ˆ์—ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋‚˜ ๋‚ ์งœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ๋งค๋ฒˆ ๊ฒฐ๊ณผ๊ฐ’์„ ํ•˜๋“œ์ฝ”๋”ฉ์œผ๋กœ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ๋น„ํšจ์œจ์ ์œผ๋กœ ๋ณด์˜€๋‹ค. ๊ทธ๋ž˜์„œ ์ „๋ถ€ ๋™์ ์œผ๋กœ ๋‹ต๋ณ€์ด ๋‚˜์˜ค๋„๋ก ์ž‘์„ฑํ–ˆ์—ˆ๋‹ค.

it('holidays๋Š” ์˜ค๋Š˜ ๋‚ ์งœ์— ํ•ด๋‹นํ•˜๋Š” ๊ณตํœด์ผ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค', async () => {
  const { result } = renderHook(() => useCalendarView());

  const holidays = HOLIDAY_RECORD_BY_MONTH[format('YYYY-MM')];

  expect(result.current.holidays).toEqual(holidays);
});

it(`currentDate๋Š” ์˜ค๋Š˜ ๋‚ ์งœ์ธ ${format('YYYY-MM-DD')}์ด์–ด์•ผ ํ•œ๋‹ค`, () => {
  const { result } = renderHook(() => useCalendarView());

  assertDate(result.current.currentDate, new Date());
});

์—ฌ๊ธฐ๊นŒ์ง€๋Š” ์•„๋งˆ ์ทจํ–ฅ์ฐจ์ด ์ •๋„๋กœ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. ๋ฌธ์ œ ์—†์„ ๊ฒƒ ๊ฐ™๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ "๊ฒ€์ƒ‰์–ด์— ๋งž๋Š” ์ด๋ฒคํŠธ๋งŒ ํ•„ํ„ฐ๋งํ•ด์•ผ ํ•œ๋‹ค" ๋ผ๋Š” ํ…Œ์ŠคํŠธ์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ์ง์ ‘ filterํ•ด์„œ ๊ฒฐ๊ณผ๊ฐ’์„ ์ถ”๋ก ํ•œ๋‹ค๋ฉด..?

 expect(result).toEqual(data.filter(...))

์ด๋Ÿฐ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  data.filter()๋„.. ํ…Œ์ŠคํŠธ ๋Œ๋ ค์•ผํ•˜๋Š”๊ฑฐ์•„๋‹ˆ์•ผ...? ์ƒ๊ฐํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„์ฐจ ์‹ถ์—ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ญ” ์ƒ๊ฐ์„ํ•œ๊ฑฐ์•ผ! ํ•˜๋ฉฐ ๋ฌดํ•œ ํ…Œ์ŠคํŠธ ๊ตด๋ ˆ์— ๋น ์ง€๋Š” ์ƒ์ƒ์„ ํ•˜๊ณ  ์ด๊ฑด ์ž˜๋ชป๋๋‹ค๊ณ  ๋А๊ผˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋ฐ”๋กœ ์ฝ”์น˜๋‹˜๋“ค๊ป˜ ์—ฌ์ญค๋ดค๋‹ค. ์ทจํ–ฅ์ฐจ์ด๊ฐ€ ์žˆ๊ธดํ•˜์ง€๋งŒ ํ…Œ์ŠคํŠธ์ฝ”๋“œ์˜ ๋‹ต๋ณ€์€ ์ •์ ์œผ๋กœ ์ ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ํ•˜์…จ๋‹ค.

ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋Š” ๋„ˆ๋ฌด ์ฝ”๋”ฉํ•˜๋“ฏ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ์ข‹์ง€ ์•Š๊ตฌ๋‚˜๋ผ๊ณ  ๋А๊ผˆ๋‹ค.

๋™๋“ฑ ๋ถ„ํ•  ๊ทธ๋ฃน

ํ…Œ์ŠคํŠธ ์„ค๊ณ„ ๊ธฐ๋ฒ• ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

์ž…๋ ฅ๊ฐ’๋“ค์„ ์˜๋ฏธ์ ์œผ๋กœ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋Š” ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋ˆ„๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.

์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ๋ณด๋ฉด "์ผ์ •์ด ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค", "์ผ์ •์ด ํ‘œ์‹œ๋œ๋‹ค" ๋‘ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋‰œ๋‹ค. ์ด ๋•Œ๋Š” ์˜๋ฏธ๊ฐ€ ์žˆ๋Š” ๋™๋“ฑ ๋ถ„ํ•  ๊ทธ๋ฃน์ด๋‹ค.

it('์ฃผ๋ณ„ ๋ทฐ๋ฅผ ์„ ํƒ ํ›„ ํ•ด๋‹น ์ฃผ์— ์ผ์ •์ด ์—†์œผ๋ฉด, ์ผ์ •์ด ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค.', async () => {
  const user = userEvent.setup();

  vi.setSystemTime(new Date('2025-09-01'));

  ...

  expect(screen.queryByText('ํŒ€ ํšŒ์˜')).not.toBeInTheDocument();
});

it('์ฃผ๋ณ„ ๋ทฐ ์„ ํƒ ํ›„ ํ•ด๋‹น ์ผ์ž์— ์ผ์ •์ด ์กด์žฌํ•œ๋‹ค๋ฉด ํ•ด๋‹น ์ผ์ •์ด ์ •ํ™•ํžˆ ํ‘œ์‹œ๋œ๋‹ค', async () => {
  const user = userEvent.setup();

  vi.setSystemTime(new Date('2025-09-12'));
  ...

  expect(within(weekViewContainer).getByText('ํŒ€ ํšŒ์˜')).toBeVisible();
});

๊ทธ๋Ÿฌ๋‚˜ ๋งŒ์•ฝ ์•„๋ž˜์ฒ˜๋Ÿผ ๊ฐ™์€ ๋ถ„ํ•  ๊ทธ๋ฃน์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์ž˜๋ชป๋œ ํ…Œ์ŠคํŠธ ์„ค๊ณ„๋‹ค


 it('์ฃผ๋ณ„ ๋ทฐ๋ฅผ ์„ ํƒ ํ›„ 9์›” 1์ฃผ์ฐจ์— ์ผ์ •์ด ์—†์œผ๋ฉด, ์ผ์ •์ด ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค.', async () => {
  const user = userEvent.setup();

  ...

  expect(screen.queryByText('ํŒ€ ํšŒ์˜')).not.toBeInTheDocument();
});

it('์ฃผ๋ณ„ ๋ทฐ๋ฅผ ์„ ํƒ ํ›„ 9์›” 2์ฃผ์ฐจ์— ์ผ์ •์ด ์—†์œผ๋ฉด, ์ผ์ •์ด ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค.', async () => {
  const user = userEvent.setup();

  ...

  expect(screen.queryByText('ํŒ€ ํšŒ์˜')).not.toBeInTheDocument();
});

๊ฒฝ๊ณ„๊ฐ’ ํ…Œ์ŠคํŠธ

ํ…Œ์ŠคํŠธ์˜ ๊ฒฝ๊ณ„๊ฐ’์—๋Š” ๊ฐœ๋ฐœ์ž์˜ ์‹ค์ˆ˜๊ฐ€ ๋งŽ์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋Š” ์œ„์น˜์ด๋‹ค. ์•„๋ž˜์ฒ˜๋Ÿผ ๊ฒฝ๊ณ„๊ฐ’์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ถ„๋ฅ˜๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์€ ์˜๋ฏธ์žˆ๋‹ค.

it('์ฃผ์˜ ๋(์ผ์š”์ผ)์— ๋Œ€ํ•ด ์˜ฌ๋ฐ”๋ฅธ ์ฃผ์˜ ๋‚ ์งœ๋“ค์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค', () => {
  expect(getWeekDates(new Date('2025-07-07'))).toEqual([
    new Date('2025-07-06'),
    new Date('2025-07-07'),
    new Date('2025-07-08'),
    new Date('2025-07-09'),
    new Date('2025-07-10'),
    new Date('2025-07-11'),
    new Date('2025-07-12'),
  ]);
});

ํ•™์Šต ํšจ๊ณผ ๋ถ„์„

์‹ค๋ฌด ์ ์šฉ ๊ฐ€๋Šฅ์„ฑ

ํšŒ์‚ฌ์—๋Š” ํ•ต์‹ฌ๊ธฐ๋Šฅ์ด ์˜ทํŽธ์ง‘, ์˜ท๋“ฑ๋ก, ์ฝ”๋””๋“ฑ๋ก ๋“ฑ๋“ฑ ์•ฑ ์ดˆ๊ธฐ๋ถ€ํ„ฐ ์žˆ์—ˆ๋˜ ๊ธฐ์ดˆ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค. ํ•ด๋‹น ๊ธฐ๋Šฅ๋“ค์„ ๊ฐœ์„ ํ•˜๊ฑฐ๋‚˜ ๊ณ ๋„ํ™”ํ•  ๋•Œ๋งˆ๋‹ค ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ๋“ค์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š”๊ฒƒ์ด๊ณ , ๊ธฐํš๋„ ์ž˜ ๋ชจ๋ฅด๊ฒ ๊ณ , ๊ธฐ๋Œ€๊ฐ’๋„ ๋ญ”์ง€ ๋ชจ๋ฅด๊ฒ ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ์Šคํ”„๋ฆฐํŠธ์—์„œ ํ•ด๋‹น ์ž‘์—…์„ ํ•˜๊ฒŒ ๋œ๋‹ค๋Š” ์–˜๊ธฐ๋งŒ ๋“ค์–ด๋„ ๋จธ๋ฆฌ๊ฐ€ ์•„ํ”„๊ณ , ์‹œ๊ฐ„์ด ๋น„์ •์ƒ์ ์œผ๋กœ ๋งŽ์ด ์†Œ๋ชจ๋œ๋‹ค.

์›๋ž˜๋Š” ์–ด์ฉ” ์ˆ˜ ์—†์ง€.. ์‹น ๋‹ค ์—Ž์–ด๋ฒ„๋ ค์•ผ๋˜๋Š”๋ฐ, ๊ธฐํš๋ถ€ํ„ฐ ๊ฐœ๋ฐœ๊นŒ์ง€ ์ƒˆ๋กœ ํ•ด์•ผ๋˜๋Š”๊ฑฐ ์•„๋‹ˆ์•ผ? ๋ผ๋Š” ์ƒ๊ฐ๋งŒ ํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ, ์ด๋ฒˆ์— ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด์„œ ์ƒ๊ฐ์ด ์กฐ๊ธˆ ๋ฐ”๋€Œ์—ˆ๋‹ค.

์˜คํ”„๋‹˜์ด Q&A ์„น์…˜์ค‘ ๋ˆ„๊ตฐ๊ฐ€ ๋น„ํšจ์œจ์ ์ธ ํ…Œ์ŠคํŠธ์ฝ”๋“œ ๊ฐ™๋‹ค๊ณ  ํ•ด๋„ ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋กœ ์ธํ•ด ์‹ฌ๋ฆฌ์ ์ธ ์•ˆ์ •๊ฐ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ทธ๊ฑธ๋กœ๋„ ์˜๋ฏธ์žˆ๋‹ค๊ณ  ํ•˜์…จ๋‹ค. ์ด ๋ง์”€์ด ์ข€ ์™€๋‹ฟ๊ฒŒ ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์˜›๋‚  ๊ธฐ๋Šฅ์„ ๊ฑด๋“œ๋ฆด ๋•Œ๋งˆ๋‹ค ๋ฌด์Šจ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ• ์ง€ ๋ชจ๋ฅด๊ฒ ์œผ๋‹ˆ ๋ถˆ์•ˆํ•˜๊ณ  ์ž‘์—…ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์•˜๋Š”๋ฐ, ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋กœ ๋‚˜์—๊ฒŒ ์‹ฌ๋ฆฌ์ ์ธ ์•ˆ์ •๊ฐ์„ ์ค€๋‹ค๋ฉด ๊ฐœ๋ฐœํ•˜๊ธฐ๊ฐ€ ์ •๋ง ํŽธํ•  ๊ฒƒ ๊ฐ™๋‹ค.

ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ํ•™์Šตํ•œ ํ›„ ์ƒ๊ฐ

ํ…Œ์ŠคํŠธ ์ฝ”๋“œํ•˜๋ฉด ์—„์ฒญ ๋ฉ€๊ฒŒ๋งŒ ๋А๊ปด์กŒ๊ณ , ์šฐ๋ฆฌ ํšŒ์‚ฌ์ฒ˜๋Ÿผ ์ž‘์€, ๋น ๋ฅด๊ฒŒ ๊ธฐ๋Šฅ ๊ฐœ๋ฐœํ•˜๊ธฐ ๋ฐ”์œ ๊ณณ์€ ์˜๋ฏธ๊ฐ€ ์—†์„ ๊ฒƒ์ด์•ผ. ๋ผ๊ณ ๋งŒ ์ƒ๊ฐํ–ˆ๋Š”๋ฐ, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์˜คํžˆ๋ ค ๋น ๋ฅธ ์ถ”์นœ๋ ฅ์„ ์ค„ ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์„ ํ–ˆ๋‹ค. ํšŒ์‚ฌ์—์„œ ํ•œ๋‹ฌ์— ํ•œ๋ฒˆ์”ฉ ํŒ€ ํšŒ๊ณ ๋ฅผ ํ•˜๋Š”๋ฐ, ์ด ๋•Œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ๋Œ€ํ•œ ์ƒ๊ฐ์„ ๋‚˜๋ˆ ๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

๊ณผ์ œ ํ”ผ๋“œ๋ฐฑ

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ฒ˜์Œ ์ ‘ํ•˜๋‹ค๋ณด๋‹ˆ ๊ณผ์ œ์–‘์ด ๋ฒ…์ฐจ๊ฒŒ ๋А๊ปด์ง€๊ธด ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚œ์ด๋„๋ฅผ ๋‚˜๋ˆ ์ฃผ์‹œ๊ธด ํ•˜์…จ์ง€๋งŒ, ์‰ฌ์šด๊ฑธ ๊ณ ๋ฅด๊ณ  ์‹ถ์ง€ ์•Š์•˜๊ณ ... ์‹ฌํ™”๊ณผ์ œ ๋ฆฌํŒฉํ† ๋ง์€ ๊ณผ๊ฐํ•˜๊ฒŒ ํฌ๊ธฐํ•˜๊ณ  ํ…Œ์ŠคํŠธ์ฝ”๋“œ์— ์ง‘์ค‘ํ•˜์—ฌ ํ•™์Šตํ•˜๊ณ ์ž ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์— ์ œ๊ฐ€ ์„ ํƒํ•œ ๊ธธ์ด๊ธด ํ•˜์ง€๋งŒ ์‹ฌํ™”๊ณผ์ œ ์‹คํŒจํ•ด์„œ ์Šฌํ”„๋„ค์š” ใ…œ

๋ฆฌ๋ทฐ ๋ฐ›๊ณ  ์‹ถ์€ ๋‚ด์šฉ

1. handlersUtils ํ•จ์ˆ˜ ๋กœ์ง

๊ณผ์ œ์˜ ํ•ต์‹ฌ์ด ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ๋ฌธ์ œ๊ฐ€ ์—†์–ด์•ผํ•œ๋‹ค๊ณ  ํ•˜์…จ๋Š”๋ฐ, ํ…Œ์ŠคํŠธ๊ฐ€ ๋ณ‘๋ ฌ๋กœ ๋ˆ๋‹ค๋ฉด, ์—ฌ๋Ÿฌ๊ณณ์—์„œ ๋™์‹œ์— server.use๋กœ override๋ฅผ ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š” ๊ฒƒ์ด ์•„๋‹Œ๊ฐ€? ํ•˜๋Š” ๊ฑฑ์ •์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋ฐ, ํ…Œ์ŠคํŠธ๊ฐ€ ๋ณ‘๋ ฌ๋กœ ๋ˆ๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ๋™์‹œ์— ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์€ ์•„๋‹Œ๊ฑธ๊นŒ์š”?

server.resetHandlers()๋ฅผ ํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด ์™ธ๋ถ€ ํ…Œ์ŠคํŠธ์— ์˜ํ–ฅ์ฃผ๋Š” ๊ฒƒ์„ ๋ณด์•˜์„ ๋•Œ๋Š” ๊ทธ๋ ‡์ง€๋งŒ์€ ์•„๋‹Œ๊ฑฐ๊ฐ™๊ณ .. ์•ฝ๊ฐ„ ํ˜ผ๋ž€์Šค๋Ÿฌ์šด ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

2. ํšŒ์‚ฌ์—์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋„์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•?

์œ„์— ํšŒ๊ณ ์— ์ ์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ ˆ๊ฑฐ์‹œ ๋กœ์ง๊ณผ ํ•จ๊ป˜ ๊ฐœ๋ฐœํ•  ๋•Œ ํ•„์š”์„ฑ์ด ๋А๊ปด์ง„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ํฌ์ธํŠธ๋กœ ํŒ€์›๋“ค๊ณผ ์–˜๊ธฐํ•ด์„œ ๋„์ž…์„ ํ•ด๋ณผ๊นŒ ์‹ถ์€๋ฐ, ์ค€์ผ๋‹˜์€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”? ์ œ๊ฐ€ ์ƒˆ๋กœ์šด๊ฑฐ ๋ฐฐ์› ๋‹ค๊ณ  ์‹ ๋‚˜์„œ ํŽธํ˜‘๋œ ์‹œ๊ฐ์œผ๋กœ ์ง€๊ธˆ ์ƒํ™ฉ์„ ๋ฐ”๋ผ๋ณธ๊ฒŒ ์•„๋‹๊นŒ? ๊ฑฑ์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

3. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ๊ธฐ๋Œ€๊ฐ’์„ ์–ด๋””๊นŒ์ง€ ์ •์ ์œผ๋กœ ๋‘์–ด์•ผํ•˜๊ณ  ๋™์ ์œผ๋กœ ๋งŒ๋“ค์–ด์•ผํ• ์ง€? (์ด๋ฏธ ์˜คํ”„์ฝ”์น˜๋‹˜๊ป˜์„œ ๋‹ต๋ณ€์„ ํ•ด์ฃผ์…จ์ง€๋งŒ, ์ค€์ผ๋‹˜๊ป˜๋„ ๋“ค์–ด๋ณด๊ณ  ์‹ถ๋„ค์š” ใ…Žใ…Ž..)

์˜ˆ๋ฅผ ๋“ค์–ด์„œ "๊ฒ€์ƒ‰์–ด์— ๋งž๋Š” ์ด๋ฒคํŠธ๋งŒ ํ•„ํ„ฐ๋งํ•ด์•ผ ํ•œ๋‹ค" ๋ผ๋Š” ํ…Œ์ŠคํŠธ์—์„œ์˜ ๊ฒฐ๊ณผ ๊ธฐ๋Œ€๊ฐ’์ด ์•„๋ž˜๋ผ๋ฉด,

[
  {
    id: '2',
    title: '์ค€์ผ๋‹˜ ์งฑ์งฑ๋งจ',
    date: '2025-10-15',
    startTime: '09:00',
    endTime: '10:00',
    description: '์ค€์ผ๋‹˜ ์งฑ์งฑ๋งจ',
    location: 'ํšŒ์˜์‹ค B',
    category: '์—…๋ฌด',
    repeat: { type: 'none', interval: 0 },
    notificationTime: 10,
  },
];

์ •๋‹ต์— ๋Œ€ํ•œ ๊ธฐ๋Œ€๊ฐ’์„ ์ •์ ์œผ๋กœ ๋ณด๊ด€ํ•ด์•ผํ• ์ง€ ์•„๋ž˜์ฒ˜๋Ÿผ filter๋กœ ๋Œ์•„์•ผ๋˜๋‚˜ ๊ณ ๋ฏผํ•˜์˜€์Šต๋‹ˆ๋‹ค.

eventList.filter(...)

filter์˜ ๋กœ์ง์ด ๋„๋Š”์ˆœ๊ฐ„ ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•ด์•ผ๋˜๋Š” ์ƒํ™ฉ์ด ์˜ค๋Š”๊ฒŒ ์•„๋‹Œ๊ฐ€? ๋ผ๋Š” ๋ฌดํ•œ ํ…Œ์ŠคํŠธ ๊ตด๋ ˆ์˜ ๋น ์ง€๋Š” ์ƒ์ƒ์„ ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ๋ฌด์กฐ๊ฑด ์ •์ ์œผ๋กœ ๋‘์–ด์•ผํ•˜๋‚˜? ์‹ถ๋‹ค๊ฐ€๋„ ์•„์ฃผ ๊ฐ„๋‹จํ•œ ๊ฒฐ๊ณผ๊ฐ’์ธ๋ฐ๋„ ์ •์ ์œผ๋กœ ๋‘๋Š” ๊ฒƒ์€ ๋˜ ๋ถˆํ•„์š”ํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ๋กœ ๋“ค์–ด๋ณด๋ฉด, "์ฃผ๊ฐ„ ๋ทฐ์—์„œ ๋‹ค์Œ์œผ๋กœ navigate" ํ•˜๋Š” ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

7์ผํ›„, 7์ผ์ „์œผ๋กœ ์ด๋™ํ•˜๋Š” ์•„์ฃผ ๊ฐ„๋‹จํ•œ ๋กœ์ง์ž„์—๋„ ์ด๊ฒƒ๋„ ์ •์ ์ธ ๋ฐ์ดํ„ฐ๋กœ ํ…Œ์ŠคํŠธ๊ฒฐ๊ณผ๊ฐ’์„ ์ž‘์„ฑํ•ด๋†”์•ผํ• ์ง€ ๊ณ ๋ฏผ์ž…๋‹ˆ๋‹ค.

์ •์ ์œผ๋กœ ๋‘๋ฉด mock ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๊ฐ’๋„ ๊ฐ™์ด ๋งค๋ฒˆ ์ˆ˜์ •ํ•ด์ค˜์•ผํ•œ๋‹ค๋Š” ๋ถˆํŽธํ•œ ์ ์ด ์žˆ์„ํ…๋ฐ, ๋ถˆํŽธํ•˜๋”๋ผ๋„ ์˜ฌ๋ฐ”๋ฅธ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ ค๋ฉด ์ •์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ• ๊นŒ์š”?

๊ณผ์ œ ํ”ผ๋“œ๋ฐฑ

์•ˆ๋…•ํ•˜์„ธ์š” ์ง„์„๋‹˜! 7์ฃผ์ฐจ ๊ณผ์ œ ์ž˜ ์ง„ํ–‰ํ•ด์ฃผ์…จ๋„ค์š” ใ…Žใ…Ž ๋‹ค๋งŒ ์‹ฌํ™”๊ณผ์ œ๋Š” ์‹œ๊ฐ„์ด ๋งŽ์ด ๋ถ€์กฑํ–ˆ๊ตฐ์š”.. ใ… ใ…  ์•„์‰ฝ์Šต๋‹ˆ๋‹ค.

handlersUtils ํ•จ์ˆ˜ ๋กœ์ง: ๊ณผ์ œ์˜ ํ•ต์‹ฌ์ด ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ๋ฌธ์ œ๊ฐ€ ์—†์–ด์•ผํ•œ๋‹ค๊ณ  ํ•˜์…จ๋Š”๋ฐ, ํ…Œ์ŠคํŠธ๊ฐ€ ๋ณ‘๋ ฌ๋กœ ๋ˆ๋‹ค๋ฉด, ์—ฌ๋Ÿฌ๊ณณ์—์„œ ๋™์‹œ์— server.use๋กœ override๋ฅผ ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š” ๊ฒƒ์ด ์•„๋‹Œ๊ฐ€? ํ•˜๋Š” ๊ฑฑ์ •์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋ฐ, ํ…Œ์ŠคํŠธ๊ฐ€ ๋ณ‘๋ ฌ๋กœ ๋ˆ๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ๋™์‹œ์— ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์€ ์•„๋‹Œ๊ฑธ๊นŒ์š”? server.resetHandlers()๋ฅผ ํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด ์™ธ๋ถ€ ํ…Œ์ŠคํŠธ์— ์˜ํ–ฅ์ฃผ๋Š” ๊ฒƒ์„ ๋ณด์•˜์„ ๋•Œ๋Š” ๊ทธ๋ ‡์ง€๋งŒ์€ ์•„๋‹Œ๊ฑฐ๊ฐ™๊ณ .. ์•ฝ๊ฐ„ ํ˜ผ๋ž€์Šค๋Ÿฌ์šด ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ๋ณ‘๋ ฌ ์‹คํ–‰์˜ ์˜๋ฏธ

Jest/Vitest์—์„œ "๋ณ‘๋ ฌ ์‹คํ–‰"์€ ์„œ๋กœ ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ ํŒŒ์ผ๋“ค์„ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ต๋‹ˆ๋‹ค!

# ์ด๋Ÿฐ ์‹์œผ๋กœ ์—ฌ๋Ÿฌ ํŒŒ์ผ์ด ๋™์‹œ์— ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค
test-file-1.test.ts (Worker 1) โ† ๋…๋ฆฝ์ ์ธ ํ”„๋กœ์„ธ์Šค
test-file-2.test.ts (Worker 2) โ† ๋…๋ฆฝ์ ์ธ ํ”„๋กœ์„ธ์Šค  
test-file-3.test.ts (Worker 3) โ† ๋…๋ฆฝ์ ์ธ ํ”„๋กœ์„ธ์Šค

ํ•˜์ง€๋งŒ ๋ณ„๋„์˜ ์„ค์ •์„ ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ•˜๋‚˜์˜ ํ…Œ์ŠคํŠธ ํŒŒ์ผ ๋‚ด๋ถ€์—์„œ๋Š” ํ…Œ์ŠคํŠธ๋“ค์ด ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ต๋‹ˆ๋‹ค..!

๊ณต์‹๋ฌธ์„œ ๋งํฌ: https://vitest.dev/guide/parallelism.html#file-parallelism

MSW Server ์ธ์Šคํ„ด์Šค

๊ฐ ํ…Œ์ŠคํŠธ ํŒŒ์ผ์€ ๋…๋ฆฝ์ ์ธ MSW server ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

// setupTests.ts์—์„œ ์ƒ์„ฑ๋œ server๋Š” ๊ฐ ํŒŒ์ผ๋งˆ๋‹ค ๋…๋ฆฝ์ 
export const server = setupServer(...handlers);

๋”ฐ๋ผ์„œ ํŒŒ์ผ A์—์„œ server.use()๋ฅผ ํ˜ธ์ถœํ•ด๋„ ํŒŒ์ผ B์˜ server์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ต๋‹ˆ๋‹ค! ์ฆ‰, ๋‹ค๋ฅด๊ฒŒ ์ด์•ผ๊ธฐํ•ด๋ณด์ž๋ฉด ๊ฐ™์€ ํŒŒ์ผ ๋‚ด์˜ ํ…Œ์ŠคํŠธ ๊ฐ„์—๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ์ˆ˜๋„ ์žˆ์–ด์š”.

// ๊ฐ™์€ ํ…Œ์ŠคํŠธ ํŒŒ์ผ์—์„œ
describe('Event tests', () => {
  test('should handle creation error', () => {
    setupMockHandlerCreationError(); // server.use()๋กœ POST ํ•ธ๋“ค๋Ÿฌ ์ถ”๊ฐ€
    // ํ…Œ์ŠคํŠธ ์‹คํ–‰...
  });

  test('should handle normal flow', () => {
    // ์ด์ „ ํ…Œ์ŠคํŠธ์˜ POST ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์—ฌ์ „ํžˆ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ!
    // afterEach๋Š” ํ…Œ์ŠคํŠธ ์™„๋ฃŒ ํ›„์— ์‹คํ–‰๋˜๋ฏ€๋กœ
  });
});

๊ทธ๋ž˜์„œ ์ด๋Ÿฌํ•œ ์ ‘๊ทผ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค!

export const createMockHandlerScope = (handlers: any[]) => {
  let originalHandlers: any[];
  
  return {
    setup: () => {
      // ํ˜„์žฌ ํ•ธ๋“ค๋Ÿฌ ๋ฐฑ์—…
      originalHandlers = server.listHandlers();
      server.use(...handlers);
    },
    cleanup: () => {
      // ์ •ํ™•ํžˆ ์ด์ „ ์ƒํƒœ๋กœ ๋ณต์›
      server.resetHandlers(...originalHandlers);
    }
  };
};

// ๋˜๋Š” ํ…Œ์ŠคํŠธ๋ณ„ ๋…๋ฆฝ์ ์ธ ์„ค์ •
export const withMockHandlers = (handlers: any[], testFn: () => void) => {
  const originalHandlers = server.listHandlers();
  
  beforeEach(() => {
    server.use(...handlers);
  });
  
  afterEach(() => {
    server.resetHandlers(...originalHandlers);
  });
  
  return testFn;
};

ํšŒ์‚ฌ์—์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋„์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•: ์œ„์— ํšŒ๊ณ ์— ์ ์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ ˆ๊ฑฐ์‹œ ๋กœ์ง๊ณผ ํ•จ๊ป˜ ๊ฐœ๋ฐœํ•  ๋•Œ ํ•„์š”์„ฑ์ด ๋А๊ปด์ง„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ํฌ์ธํŠธ๋กœ ํŒ€์›๋“ค๊ณผ ์–˜๊ธฐํ•ด์„œ ๋„์ž…์„ ํ•ด๋ณผ๊นŒ ์‹ถ์€๋ฐ, ์ค€์ผ๋‹˜์€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”? ์ œ๊ฐ€ ์ƒˆ๋กœ์šด๊ฑฐ ๋ฐฐ์› ๋‹ค๊ณ  ์‹ ๋‚˜์„œ ํŽธํ˜‘๋œ ์‹œ๊ฐ์œผ๋กœ ์ง€๊ธˆ ์ƒํ™ฉ์„ ๋ฐ”๋ผ๋ณธ๊ฒŒ ์•„๋‹๊นŒ? ๊ฑฑ์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ์ •๋ง ๋„์ž…ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ํŒ€์— "ํ…Œ์ŠคํŠธ"์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋ฅผ ๊บผ๋‚ด์ง€ ์•Š๊ณ  ์ผ๋‹จ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด์„œ PR์„ ์˜ฌ๋ฆฐ๋‹ค์Œ์— "์ด๋ ‡๊ฒŒ ํ•˜๋‹ˆ๊นŒ ~~ ๋“ฑ์˜ ํšจ๊ณผ๋ฅผ ๋А๊ผˆ์–ด์š”!" ๋ผ๊ณ  ์ถ”๊ฐ€ํ•ด๋ณด๋Š”๊ฑฐ์ฃ  ใ…Žใ…Ž

๋ฌด์กฐ๊ฑด ๋ชจ๋“  ์ฝ”๋“œ์— ๋„์ž…ํ•˜๊ธฐ๋ณด๋‹จ ๊ทธ๋ƒฅ ์ง„์„๋‹˜์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋ถ€๋ถ„์— ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ๋„์ž…ํ•˜๋ฉด ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด์š”.

์ด๋ ‡๊ฒŒ ์ผ๋‹จ ๋ˆˆ์— ๋ณด์ด๋Š” ๋ฐฉ์‹์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ๋ณด์—ฌ์ค€ ๋‹ค์Œ์— ํŒ€์›์˜ ๋ฐ˜์‘์„ ์‚ดํŽด๋ณด์„ธ์š”. "๊ตณ์ด?" ๋ผ๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ๊ณ„์† ๋…ธ์ถœ๋œ๋‹ค๋ฉด.. ์•„๋งˆ ๋„์ž…ํ•˜๊ธฐ ํž˜๋“ค ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค ใ… ใ… 

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ๊ธฐ๋Œ€๊ฐ’์„ ์–ด๋””๊นŒ์ง€ ์ •์ ์œผ๋กœ ๋‘์–ด์•ผํ•˜๊ณ  ๋™์ ์œผ๋กœ ๋งŒ๋“ค์–ด์•ผํ• ์ง€? (์ด๋ฏธ ์˜คํ”„์ฝ”์น˜๋‹˜๊ป˜์„œ ๋‹ต๋ณ€์„ ํ•ด์ฃผ์…จ์ง€๋งŒ, ์ค€์ผ๋‹˜๊ป˜๋„ ๋“ค์–ด๋ณด๊ณ  ์‹ถ๋„ค์š” ใ…Žใ…Ž..)

์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ชฉ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด์š” ใ…Žใ…Ž ๊ธฐ๋Œ€๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š๋„๋ก ๋ชฉ๋ฐ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ๊ณ ์ •ํ•ด๋†“๋Š”๊ฑฐ์ฃ . ๊ทธ๋Ÿฌ๋ฉด ๊ผญ ์ด๋Ÿด ๋•Œ ๋ชฉ๋ฐ์ดํ„ฐ๋ฅผ ์จ์•ผํ•˜๋Š”๊ฐ€!? ๋ผ๊ธฐ ๋ณด๋‹จ... ์ตœ์†Œํ•œ์˜ ๊ณ ์ •์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ด์š”. ๊ฐ€๋ น ๋‚ ์งœ๋งŒ ๊ณ ์ •ํ•ด๋†“๋Š”๋‹ค๊ฑฐ๋‚˜!?

์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๊ฐ€ ์ตœ์†Œํ™”๋œ ๋กœ์ง์ด๋ผ๋ฉด ์–ด๋–ค input์ด๋“  output์„ ๋ฑ‰์–ด๋‚ด๋Š” ๋ฐฉ์‹์€ ๋™์ผํ• ํ…Œ๋‹ˆ๊นŒ์š”! ๋Œ€์‹  ์—ฃ์ง€์ผ€์ด์Šค(๊ฒฝ๊ณ„๊ฐ’)์„ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ๊ผผ๊ผผํ•˜๊ฒŒ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ์ข‹๋‹ต๋‹ˆ๋‹ค!