묻고 답해요
150만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
순위 정보를
불러오고 있어요
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
prop이나 state 값을 검증하지 않는다는 의미가 궁금합니다!
const textField = screen.getByPlaceholderText('텍스트를 입력해 주세요.'); expect(textField).toHaveClass('my-class');이부분에서 className이란 내부 props, state 값을 검증하는 게 아닌가 싶어서 질문을 드렸습니다. 물론, className에 따라 변경되는 DOM을 파악한다는 의미로도 해석이 될 수는 있을 것 같긴 하지만 더 정확한 문맥을 알고 싶어서 질문드렸습니다..!
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
4.3. 강의와 깃헙 소스코드가 다른 부분
안녕하세요. 강의 잘 듣고 있습니다.다름이 아니라 강의와 깃헙 소스코드가 달라서 문의드려요. mocks/zustand.js의 코드인데요.const { create: actualCreate } = await vi.importActual('zustand'); import { act } from '@testing-library/react'; // 앱에 선언된 모든 스토어에 대해 재설정 함수를 저장 const storeResetFns = new Set(); // 스토어를 생성할 때 초기 상태를 가져와 리셋 함수를 생성하고 set에 추가합니다. export const create = createState => { const store = actualCreate(createState); const initialState = store.getState(); storeResetFns.add(() => store.setState(initialState, true)); return store; }; // 테스트가 구동되기 전 모든 스토어를 리셋합니다. beforeEach(() => { // 👈 이 부분 act(() => storeResetFns.forEach(resetFn => resetFn())); });깃헙 소스코드는 위와 같이 beforeEach를 사용하지만 강의에서는 afterEach로 설명해주시고 있습니다.주석도 마찬가지로 다릅니다.무엇이 맞는 걸까요?
-
미해결실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
react-cookie로 쿠키값 테스트코드로 가져오는 방법
describe('로그인이 성공했을 경우', () => { it('"아이디 저장" 체크박스를 체크했을 시 쿠키에 itall_admin 객체의 id key로 유저가 입력한 아이디를 저장한다.', async () => { const { user } = await render(<LoginPage />); const rememberIdCheckbox = screen.getByLabelText('아이디 저장'); const idInput = screen.getByPlaceholderText('아이디(이메일)'); const submitButton = screen.getByRole('button', { name: '로그인' }); const setCookies = vi.fn(); setCookies.mockReturnValueOnce('center.test@itall.com'); const cookieValue = setCookies(); await user.click(rememberIdCheckbox); await user.type(idInput, 'center.test@itall.com'); await user.click(submitButton); expect(cookieValue).toBe('center.test@itall.com'); }) })Forms.spec.ts파일에서 js-cookie 라이브러리 모킹해서 하시는 예시를 보고 react-cookie 사용한 프로젝트의 테스트코드를 작성중인데요. 혹시 라이브러리에서 제공하는 함수를 이렇게 setCookies라는 함수를 임의로 모킹해서 return값을 지정해서 저렇게 처리해도 되는걸까요..? 테스트는 당연히 통과되었습니다..
-
미해결실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
4.4 통합테스트에서 정적 데이터로 테스트하는 대신 role 값을 미리 설정해 직접 돔에 접근하는 방식은 어떤가요?
안녕하세요우선 좋은 강의를 제작해주셔서 감사드립니다공식 문서만으로 테스트 코드 작성을 공부했다면 훨씬 시간이 많이 들었을 텐데한글로 설명을 듣고 문서를 보니 좀 더 빠르게 이해할 수 있는 것 같습니다. // answer 브랜치 코드 it('특정 아이템의 수량이 변경되었을 때 값이 재계산되어 올바르게 업데이트 된다', async () => { const { user } = await render(<ProductInfoTable />); const [firstItem] = screen.getAllByRole('row'); const input = within(firstItem).getByRole('textbox'); await user.clear(input); await user.type(input, '5'); // 2427 + 809 * 2 = 4045 expect(screen.getByText('$4,045.00')).toBeInTheDocument(); });궁금한 점은 현재 제공해주신 정답 코드에서는모킹 데이터의 결과 포맷을 알기 때문에 '$4,045.00' 이라는 텍스트 값이 dom에 마운트 되어야 테스트를 통과 시키는 방식인데요 it('특정 아이템의 수량이 변경되었을 때 값이 재계산되어 올바르게 업데이트 된다', async () => { const { user } = await render(<ProductInfoTable />); const [firstItem] = screen.getAllByRole('row'); const input = within(firstItem).getByRole('textbox'); // role은 price를 담는 div에 미리 추가했다고 가정 const price = Number(within(firstItem).getByRole('price').textContent); const value = 5; await user.clear(input); await user.type(input, value.toString()); const pricedResult = within(firstItem).getByRole('price').textContent; // 2427 + 809 * 2 = 4045 expect(priceResult.includes((value*price).toLocaleString())).toBe(true); });제가 작성한 방식은엘리먼트마다 role을 미리 지정해 둔 다음에테스트할 때마다 element들의 값에 접근해서 테스트를 진행하는 방식입니다.제가 생각했을 때에는 이 방식을 사용하면 element마다 role을 직접 설정해주어 element의 용도를 파악하기 더 쉽고 getAllBy... 메소드로 가져온 요소들에 대해 순회하여 테스트할 때 테스트 결과 값을 동적으로 생성하기 때문에 더 유연하지 않을까 라는 생각이 들었습니다. 궁금한 점은 제가 작성한 방식을 현업에서도 사용하는지잘 사용되지 않는 방식이라면 어떤 이유에서 잘 사용되지 않는지가 궁금합니다
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
3.4. 타이머 테스트의 마지막 테스트 질문입니다.
it('연이어 호출해도 마지막 호출 기준으로 지정된 타이머 시간이 지난 경우에만 함수가 호출된다.', () => { const spy = vi.fn(); const debouncedFn = debounce(spy, 300); // 최초 호출 debouncedFn(); // 최초 호출 후 0.2초 후 호출 vi.advanceTimersByTime(200); debouncedFn(); // 두번째 호출 후 0.1초 후 호출 vi.advanceTimersByTime(100); debouncedFn(); // 세번째 호출 후 0.2초 후 호출 vi.advanceTimersByTime(200); debouncedFn(); // 👈 4번째 호출 // 네번째 호출 후 0.3초 후 호출 // 최초 호출 후에 함수 호출 간격이 0.3초 이상 -> 다섯번째 호출이 유일 vi.advanceTimersByTime(300); debouncedFn(); // 👈 5번째 호출 // 다섯번을 호출했지만 실제 spy함수는 단 한 번만 호출 expect(spy).toHaveBeenCalledTimes(1); }); 안녕하세요. 새해 복 많이 받으세요 :)다름이 아니라 위 코드에서 4번째 호출 후 바로 뒤, vi.advanceTimersByTime(300);로 인해 0.3초가 흘렀고 이로 인해 expect(spy).toHaveBeenCalledTimes(1); 이 맞다고 나온 것이 아닌지 궁금해서 질문드립니다.강의에서는 4번째 호출이 아닌 5번째 호출로 인해 호출된다고 하셨는데(최초 호출 후에 함수 호출 간격이 0.3초 이상인 경우는 다섯번째 호출이 유일하다고 하신 것 같아요) 5번째 호출 후에는 0.3초가 흘렀다는 가정 (vi.advanceTimersByTime(300);)이 없고 제가 혼자 테스트 해보며 5번째 호출 후에 vi.advanceTimersByTime(300);를 넣어 0.3초가 흘렀다고 가정을 하니 호출이 2번 되었다고 떠서요.제가 debounce를 헷갈려 했는데 제가 아직 잘 이해하지 못한 부분이 있는 건지 아니면 실제로 잘못 설명된 부분이 있는 건지 모르겠어서 질문 드립니다. 감사합니다.
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
mocking과 spy함수가 헷갈립니다.
mocking과 spy함수가 조금 헷갈립니다. 아래와 같이 정리하면 될까요?- spy 함수 : 빈 함수인데, vitest에서 이 함수를 감지하고 있고 함수가 call 되었는지, 인자는 무엇이었는지 검증하는 가짜 함수.- mocking : 종속성이 있는 라이브러리를 복사해두고, 그 중 사용해야 할 함수나 기능을 spy 함수로 대체하여 call 했는지 검사할 수 있는 프로세스.그러면 mocking 자체는 spy 함수 없이 사용하는 것은 의미가 없다고 보면 될까요?
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
테스트 코드 파일 위치
안녕하세요! 강의 잘 보고 있습니다. :)다름이 아니라 테스트 코드 파일들의 작성 위치가 궁금한데요, 보니까 그냥 파일 바로 아래에 새로운 테스트 코드 파일이 있는 것 같은데 이게 보편적인 위치일까요?따로 테스트 코드 폴더를 만들거나 하진 않는 건지 궁금해서 문의드립니다.감사합니다 :)
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
async-await 이 꼭 있어야하는지 질문입니다
안녕하세요. 강의 너무 재밌게 잘 보고 있습니다. 두가지 질문이 있어서 문의글 남깁니다. 질문 1. 테스트코드에서 async, await 가 필요없어 보이는 곳에도 꼭 붙이는 이유가 있나요? 예를들면, 아래 1번 코드에서 async await 이 반드시 필요한 이유가 있는건가요? 저는 2번처럼 async-await을 제거해도 테스트가 정상 통과 되어서요. 특별한 목적이 있어서 붙여야 하는건지 궁금합니다. ! 1) it('총 상품 금액은 "$500.00"로 노출된다', async () => { await render(<TestPayment />); expect(screen.getByText('500.00')).toBeInTheDocument(); }); 2)it('총 상품 금액은 "$500.00"로 노출된다', () => { render(<TestPayment />); expect(screen.getByText('500.00')).toBeInTheDocument(); }); 질문 2. render 함수를 util 로 만들어서 사용하시는데, userEvent.setup의 user 도 함께 들어있는 이유가 궁금합니다. userEvent를 쓰지 않는 테스트코드도 있는데, 꼭 함께 들어있어야하나 하는 생각이 들어서요 ㅎㅎ userEvent를 더 편리하게 사용하기 위함인가요? export default async (component, options = {}) => { const { routerProps } = options; const user = userEvent.setup(); return { user, ...render( <QueryClientProvider client={queryClient}> <MemoryRouter {...routerProps}>{component}</MemoryRouter> <Toaster /> </QueryClientProvider>, ), }; }; 감사합니다!
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
2.1 테스트 구동 실패
안녕하세요 2.1 class 단위 테스트를 작성하고 `npm run test`로 테스트를 구동 했을 때, 다음과 같이 테스트를 실패하고 있습니다. `nvm use`, 'npm ci'를 모두 마친 상황인데, 어떤 문제를 해결해야 할까요? 혹시나 싶어 스토리북을 구동했을 때는, 문제 없이 scripts 명령어를 입력했을 때 실행이 되는 것을 확인할 수 있었습니다.!github branch의 unit-test-example을 pull 받아서 진행했습니다!운영체제: Windows 11 import { screen } from '@testing-library/react'; import React from 'react'; import TextField from '@/components/TextField'; import render from '@/utils/test/render'; it('className Prop으로 설정한 css class가 적용된다.', async () => { // Arrange - 테스트를 위한 환경 만들기 // -> className을 지닌 컴포넌트 렌더링 await render(<TextField className="my-class" />); // Act - 테스트할 동작 발생 // -> 렌더링에 대한 검증이기 때문에 이 단계는 생략 // -> 클릭이나 메서드 호출, prop 변경 등등에 대한 작업이 여기에 해당 합니다. // Assert - 올바른 동작이 실행되었는지 검증 // -> 렌덩링 이후 DOM에 해당 class가 존재하는지 검증 // TextField는 placeholder 요소가 있습니다. // vitest의 expect 함수를 사용하여 기대 결과를 검증 expect( screen .getByPlaceholderText('텍스트를 입력해 주세요.') .toHaveClass('my-class'), ); }); FAIL src/components/tests/TextField.spec.jsx [ src/components/tests/TextField.spec.jsx ] Error: C:\Users\js953\Desktop\Github\fe-test\test-example-shopping-mall\src\components\tests\TextField.spec.jsx 21:3 error Expect must have a corresponding matcher call vitest/valid-expect ✖ 1 problem (1 error, 0 warnings) ❯ formatError node_modules/vite/dist/node/chunks/dep-abb4f102.js:43916:46 ❯ TransformContext.error node_modules/vite/dist/node/chunks/dep-abb4f102.js:43912:19 ❯ TransformContext.transform node_modules/vite-plugin-eslint/dist/index.mjs:1:1989 ❯ Object.transform node_modules/vite/dist/node/chunks/dep-abb4f102.js:44206:30 ❯ loadAndTransform node_modules/vite/dist/node/chunks/dep-abb4f102.js:54851:29 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ Test Files 1 failed (1) Tests no tests Start at 12:45:37 Duration 1.63s (transform 743ms, setup 883ms, collect 0ms, tests 0ms, environment 408ms, prepare 109ms) FAIL Tests failed. Watching for file changes... press h to show help, press q to quit ```Test result not found. If you set `vitest.commandLine` please check: Did you set `vitest.commandLine` to `run` mode? (This extension requires `watch` mode to get the results from Vitest api) Does it have the ability to append extra arguments? (For example it should be `yarn test --` rather than `yarn test`) Are there tests with the same name? Can you run vitest successfully on this file? Does it need custom option to run? Vitest output: DEV v0.33.0 C:/Users/js953/Desktop/Github/fe-test/test-example-shopping-mall API started at http://127.0.0.1:60930 ❯ src/components/tests/TextField.spec.jsx (0 test)
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
testing api 아이콘(비커)이 뜨지 않습니다.
강의에서 진행하는 브랜치와 동일한 브랜치에서 진행하고 있습니다.의존성 설치도 모두 진행하였고 vitest도 설치했으며 node 버전도 일치합니다.테스트 코드 작성 완료 후에 이 아이콘을 찾아봤는데 도저히 보이질 않습니다.Github 이슈와 stackoverflow 모두 찾아보면서 해답이 될 만한 내용들을 따라해보았으나 위 아이콘은 도저히 찾을 수 없었습니다.혹시 따로 설정을 하신 건가요??
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
screen.findAllByTestId 질문
it('보여줄 상품 리스트가 더 있는 경우 show more 버튼이 노출되며, 버튼을 누르면 상품 리스트를 더 가져온다.', async () => { const { user } = await render(<ProductList limit={PRODUCT_PAGE_LIMIT} />); await screen.findAllByTestId('product-card'); const showMoreButton = screen.getByRole('button', { name: 'Show more', }); expect(showMoreButton).toBeInTheDocument(); await user.click(showMoreButton); expect(await screen.findAllByTestId('product-card')).toHaveLength( PRODUCT_PAGE_LIMIT * 2, ); });여기서 render 이후에 await screen.findAllByTestId('product-card'); 를 하는 이유가 있나요? 저걸 해주지 않으면 버튼이나 상품 아이템을 그리지 못하는 건 아는데... 그려지는 이유를 모르겠어서요 await로 찾을때까지 대기하는 걸로 이해하면 될까요?1. 그렇다면 render 호출 이후 요소를 찾지 않아도 되는 경우에도 await screen.findAllByTestId('product-card');를 해주어야 하는걸까요?2. 아래와 같이 하는거랑 차이가 있나요?it('보여줄 상품 리스트가 더 있는 경우 show more 버튼이 노출되며, 버튼을 누르면 상품 리스트를 더 가져온다.', async () => { const { user } = await render(<ProductList limit={PRODUCT_PAGE_LIMIT} />); const showMoreButton = await screen.findByRole('button', { name: 'Show more', }); expect(showMoreButton).toBeInTheDocument(); await user.click(showMoreButton); expect(await screen.findAllByTestId('product-card')).toHaveLength( PRODUCT_PAGE_LIMIT * 2, ); });
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
1의 1.2. 올바른 테스트 작성을 위한 규칙에서 "아이템스 풀업스" 용어는 정확히 무엇이고, 어떤 의미인가요?
풀업은 턱걸이에서 듣던 용어인데요.용어를 찾아봐도 없는데, 정확히 전문 용어는 아닌 것 같고,어떤 의미로 사용되었는지 궁금합니다.
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
2.4장 마지막 border 스타일 검증 시 질문
강의의 예시와 같이expect(textInput).toHaveStyle({ borderWidth: 2, borderColor: rgb(25, 118, 210) })으로 할 경우 정상적으로 test passed가 되긴 하는데,expect(textInput).toHaveStyle({ borderWidth: 1, borderColor: rgb(25, 118, 210) })처럼 변경할 경우에도 test passed가 되네요. testing-library/jest-dom#toHaveStyle 이나 비슷한 다른 이슈를 좀 확인해보니, 예시처럼이 아닌expect(textInput).toHaveStyle({ borderWidth: '1px', borderColor: rgb(25, 118, 210) })처럼 세팅해야 예상한대로 fail이 되는 것 같습니다. 그래서 border style을 검증하는 쪽 테스트 코드의 expect 부분도expect(textInput).toHaveStyle({ borderWidth: '2px', borderColor: rgb(25, 118, 210) })로 수정이 되어야 하지 않을까.. 조심스레 제안드려봅니다 ㅎ
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
2.1장 ClassName props으로 설정한 css class 가 적용된다 가 유의미한 테스트일까요
안녕하세요테스트 강의 내주셔서 감사합니다! 실제로 프론트 테스트 코드를 작성해본 적이 없어서 재밌고 유익하네요.질문은 단위테스트 설명하는 부분의 예제 코드 관련입니다.2.1장에서 단위테스트 예제로 보여주신 내용은 "ClassName props으로 설정한 css class 가 적용된다"인데요앞장인 1장에서 설명한 내용인 "유의미한 테스트 혹은 인터페이스를 기준으로 작성한다" 와 맞지 않는 것 같아서요..AAA패턴을 보여주기 위한 예시 코드정도로 생각하면 될까요.
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
Storybook이 안켜져요
강사님의 깃허브의 코드를 클론해서 npm i 까지 했습니다.이후 npm run dev 나 npm run storybook dev -p 6006을 실행하면 오류가 떠서 켜지지가 않아요..ㅠ살려주세요. 초기 세팅이 잘 안되네요
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
act 함수와 renderHook 함수 내 rerender 차
안녕하세요 궁금한게 있습니다. act 함수에 대해 이해했는데 act 함수없이 아래와 같이 해도 테스트가 통과되더라구요. 혹시 차이가 있을까요?it('훅의 toggleIsModalOpened()를 호출하면 isModalOpened 상태가 toggle된다.', () => { const { result, rerender } = renderHook(useConfirmModal); result.current.toggleIsModalOpened(); rerender(); expect(result.current.isModalOpened).toBe(true); });
-
미해결실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
vitest를 설치했는데 이 작업 영역에서 아직 발견된 테스트가 없습니다.라는 문구가 떠서 테스트를 진행할 수 없습니다..
안녕하세요.2.1 단위 테스트란 무엇일까? 강의를 들으며 따라하고 있습니다.강의에서 진행하고 있는 unit-test-example 브랜치에서 TextField.spec.jsx 파일을 따라 치며 테스트를 하려고 하는데 vscode 테스트 메뉴에서 '이 작업 영역에서 아직 발견된 테스트가 없습니다.'라는 문구와 '추가 테스트 확장 설치'라는 버튼만 떠서 테스트 진행을 하지 못하고 있습니다.강의에서 소개해주신 vitest를 설치하고 vscode를 껐다가 다시 켜봐도 테스트를 찾을 수 없다고 뜨고 있는데 제가 어떻게 하면 될까요?
-
해결됨실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트
안녕하세요. README 링크가 이상해 제보합니다.
REAMDE 1부 - 4장 > 정답코드 링크가 잘못 작성된 것 같아 제보드립니다https://github.com/practical-fe-testing/test-example-shopping-mall/blob/main/shopping-mall-integration-test-with-answer
주간 인기글
순위 정보를
불러오고 있어요