Logo
Hyunsu Blog
declare_typescript

๐Ÿ“†Published :Jun 14, 2024 โ€ข

๐Ÿ“†Updated :Jun 14, 2024 โ€ข

โ˜•๏ธ1min

ํ…Œ์ŠคํŒ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ์ž๋™์™„์„ฑ์œผ๋กœ๋Š” ์•ˆ๋ ๊นŒ? ํƒ€์ž…์„ ์–ธ์œผ๋กœ ์ž์ฃผ์“ฐ๋Š” ๋ฉ”์„œ๋“œ ์ž๋™์™„์„ฑ ํ•ด๋ณด๊ธฐ



1. ๋“ค์–ด๊ฐ€๋ฉฐ



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






2. d.ts ํƒ€์ž…์„ ์–ธ์œผ๋กœ ๋ฆฌ์•กํŠธ ํ…Œ์ŠคํŒ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฉ”์„œ๋“œ ์ž๋™ ์™„์„ฑ ํ™œ์šฉํ•˜๊ธฐ



๋จผ์ € @testing-library/react ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ์—์„œ screen, render๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


import { render, screen } from '@testing-library/react'; test('renders learn react link', () => { render(<App />); const linkElement = screen.getByText(/learn react/i); expect(linkElement).toBeInTheDocument(); });

๋จผ์ € ์ƒ๊ฐ ๋‚˜๋Š” ์•„์ด๋””์–ด๋Š” _t.๋ฅผ ํ•˜๋ฉด ์ž๋™ ์™„์„ฑ์œผ๋กœ ์ž์ฃผ ์“ฐ๋Š” ๋ฉ”์„œ๋“œ ๋“ค์„ ๋‚˜์˜ค๊ฒŒ ํ•˜๋ฉด ์–ด๋–จ๊นŒ ์˜€๋Š”๋ฐ์š”.

์ด ์•„์ด๋””์–ด๋ฅผ ์‹คํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋จผ์ € ์˜ˆ์‹œ๋กœ screen. ์—์„œ ๋ฉ”์„œ๋“œ๋“ค์€ ์–ด๋–ป๊ฒŒ ์ •์˜๋˜์—ˆ๋Š”์ง€ ํƒ€์ž…์ •์˜ ํŒŒ์ผ์„ ํ™•์ธํ•ด ๋ด…๋‹ˆ๋‹ค. @testing-library/react์˜ ํƒ€์ž… ์„ ์–ธ ํŒŒ์ผ(.d.ts ํŒŒ์ผ)์€ node_modules/@testing-library/react ๋””๋ ‰ํ† ๋ฆฌ ์•„๋ž˜์— ์œ„์น˜ํ•ด ์žˆ๋Š”๋ฐ์š”. screen ์ด ๋•๋ถ„์— screen ์˜ ์†์„ฑ๋“ค์€ ๋ชจ๋‘ ์ž๋™์™„์„ฑ์ด ๋ฉ๋‹ˆ๋‹ค.



๊ทธ๋Ÿผ _t๋ฅผ ํ†ตํ•ด screen, render ๊ฐ€ ๋‚˜์˜ค๊ฒŒ ํ•˜๋ ค๋ฉด ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์— ํƒ€์ž…์„ ์–ธ ํŒŒ์ผ์—์„œ ํƒ€์ž…์„ ์ง€์ •ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

๋จผ์ € ์ž๋™์™„์„ฑ์œผ๋กœ ์„ค์ •ํ•  ๋ฉ”์„œ๋“œ๋“ค์„ ๊ฐ์ฒด์— ๋‹ด์•„๋‘ก๋‹ˆ๋‹ค.

export const testUtils = { render, screen, fireEvent, renderHook, act, } //global.d.ts import { testUtils } from '@/types/test-utils' declare global { const _t: typeof testUtils } export {}

jest.setup ํŒŒ์ผ์—์„œ ๊ธ€๋กœ๋ฒŒ๋กœ ์„ ์–ธํ•ด๋‘” _t ๋ณ€์ˆ˜๋ฅผ ๋Ÿฐํƒ€์ž„์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ globalThis ๊ฐ์ฒด ๋‚ด _t๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

์™œ jest.setup ํŒŒ์ผ์—์„œ _t ๋ฅผ ๋‹ค์‹œ ํ• ๋‹นํ•˜์ฃ ? โœ…
. declare global ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ TypeScript์— ์ „์—ญ ๋ณ€์ˆ˜์˜ ์กด์žฌ์™€ ํƒ€์ž…์„ ์•Œ๋ฆฌ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์‹ค์ œ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์—์„œ ์ „์—ญ ๋ณ€์ˆ˜๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, setup.ts์™€ ๊ฐ™์€ ์ดˆ๊ธฐํ™” ํŒŒ์ผ์—์„œ ์‹ค์ œ๋กœ ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

//jest.setup.ts Object.defineProperty(globalThis, '_t', { value: testUtils, writable: false, configurable: false, })

_t. ์„ ํ•˜๋ฉด ์ž๋™์™„์„ฑ์œผ๋กœ ์ถ”๋ก ๋˜๋Š” ๋ฉ”์„œ๋“œ๋“ค์ด ๋ณด์ž…๋‹ˆ๋‹ค.


test-auto-complete


์ด์ œ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

//test it('์•„์ดํ…œ์ด ์ œ์ผ ์™ผ์ชฝ์— ์œ„์น˜ ํ•˜๊ณ  ์žˆ์„ ๋•Œ, ์™ผ์ชฝ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋” ์ด์ƒ ์ด๋™ ํ•˜์ง€ ์•Š๋Š”๋‹ค.', () => { _t.render(<Carousel>{childArray}</Carousel>) const track = _t.screen.getByTestId('carousel_track') const prevButton = _t.screen.getByTestId('carousel_prev_button') expect(track).toHaveStyle('transform: translateX(-0px)') _t.fireEvent.click(prevButton) expect(track).toHaveStyle('transform: translateX(-0px)') })

3. DX ๋ฐ ๊ฐ€๋…์„ฑ ๋น„๊ต

ํƒ€์ดํ•‘์˜ ์†๋„๊ฐ์€ ๋นจ๋ผ์กŒ๋‹ค๊ณ  ์ƒ๊ฐ๋˜๊ณ  ํŽธํ•˜๊ธฐ๋„ ํ–ˆ๋Š”๋ฐ์š”. ๊ทธ๋Ÿผ ๊ฐ€๋…์„ฑ์€ ์–ด๋–จ๊นŒ์š”?



์ฝ”๋“œ์˜ ์ „ ํ›„๋ฅผ ๋น„๊ตํ•ด ๋ณผ๊ฒŒ์š”.

before after


์–ด๋–ค๊ฐ€์š”??


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


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


3. ๋งˆ๋ฌด๋ฆฌ

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

Hi, I'm Hyunsu ๐Ÿ‘‹

Profile Image

์•ˆ๋…•ํ•˜์„ธ์š”. ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ฃผํ˜„์ˆ˜์ž…๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ํ’๋ถ€ํ•˜๊ณ  ๊ฐ€์น˜ ์žˆ๋Š” ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋Š” ์ผ์— ๋ฟŒ๋“ฏํ•จ์„ ๋Š๋‚๋‹ˆ๋‹ค.

์˜ต์‹œ๋””์–ธ(Obsidian)์—์„œ ํ˜„์žฌ ๋ธ”๋กœ๊ทธ๋กœ ํ•˜๋‚˜์”ฉ ๊ธ€์„ ์˜ฎ๊ธฐ๋Š” ๊ณผ์ •์— ์žˆ์–ด์š”. โ˜•๏ธ ๐Ÿ‘ฉโ€๐Ÿ’ป โ›ท

Github on ViewReach Me Out