TDD란
성공/실패 케이스를 작성한 테스트 코드를 먼저 구현하고 해당 테스트 케이스에 맞게 코드를 구현하는 것
이전까지 진행한 방식은 컴포넌트를 먼저 만들고 기능 구현을 한 다음에 테스트 코드를 붙인 거라 TDD라고 할 수는 없다고 한다.
회원가입 로직으로 TDD를 진행해보자.
SignupPage.tsx에 있던 ui는 모두 지워준다.
// signup.cy.js
describe('회원가입 테스트', () => {
it('사용자는 이메일과 비밀번호를 사용해서 회원가입한다', () => {
// given - 회원가입 페이지에 접근한다
cy.visit('/signup');
// when - 이메일과 비밀번호를 입력한다 + 비밀번호와 비밀번호 확인값이 일치한다
// then - 회원가입 버튼이 활성화 되어 회원가입에 성공하고 로그인 페이지로 이동한다
});
});
npm run ci, npm run cypress를 하면 cypress 화면이 뜬다.
정상적으로 회원가입 페이지에 접속했다.
// signup.cy.js
describe('회원가입 테스트', () => {
it('사용자는 이메일과 비밀번호를 사용해서 회원가입한다', () => {
// given - 회원가입 페이지에 접근한다
cy.visit('/signup');
cy.get('[data-cy=signupButton]').as('signupButton');
cy.get('@signupButton').should('be.disabled');
// when - 이메일과 비밀번호를 입력한다 + 비밀번호와 비밀번호 확인값이 일치한다
cy.get('[data-cy=emailInput]').as('emailInput');
cy.get('[data-cy=passwordInput]').as('passwordInput');
cy.get('[data-cy=confirmPasswordInput]').as('confirmPasswordInput');
cy.get('@emailInput').type('email@email.com');
cy.get('@passwordInput').type('password');
cy.get('@confirmPasswordInput').type('password');
cy.get('@passwordInput')
.invoke('val')
.then(passwordValue => {
expect(passwordValue.trim()).to.not.be.empty;
cy.get('@confirmPasswordInput')
.invoke('val')
.should('eq', passwordValue);
cy.get('@signupButton').should('not.be.disabled');
});
// then - 회원가입 버튼이 활성화 되어 회원가입에 성공하고 로그인 페이지로 이동한다
cy.intercept(
{
method: 'POST',
url: '/user/signup',
},
{
msg: 'SUCCESS',
}
).as('signup');
cy.get('@signupButton').click();
cy.url().should('include', '/login');
});
});
이렇게 테스트 로직을 짰는데 현재 ui 부분을 모두 지웠기 때문에 해당 값을 가져오지 못해 에러가 발생한다.
이제 다시 ui를 그려주자.
1. 회원가입 버튼 비활성화
2. 이메일/비밀번호/비밀번호 확인 Input에 입력이 되면 그 값이 state에 저장되도록
3. 비밀번호/비밀번호 확인 값 일치
4. 회원가입 버튼 활성화
5. 회원가입 버튼 클릭 시 useSignup 훅으로 회원가입 요청
6. 회원가입 요청이 성공하면 alert로 회원가입 성공 메세지 + 로그인 페이지로 이동
이 로직대로 진행한다.
// SignupPage.tsx
<Wrapper>
<input data-cy="emailInput" />
<input data-cy="passwordInput" />
<input data-cy="confirmPasswordInput" />
<button data-cy="signupButton" disabled={true}>
회원가입
</button>
</Wrapper>
우선 이렇게 ui를 구성하고 가면 버튼 부분에서 에러가 발생한다.
회원가입 버튼이 아직 비활성화 되어 있다고 한다.
활성화 시키려면 이메일/비밀번호/비밀번호 확인이 입력되고 비밀번호/비밀번호 확인 값이 같아야 한다.
const isSignupBtnActive = !!email && !!password && password === confirmPassword;
이 코드를 적어주고 button에 disabled={!isSignupBtnActive}를 걸어주자.
응 또 에러야~
이건 아까 위에서 적은 2번 (state에 저장되도록)이 되지 않아서 그렇다.
// SignupPage.tsx
<Wrapper>
<Input data-cy="emailInput" onChange={e => setEmail(e.target.value)} />
<Input
data-cy="passwordInput"
onChange={e => setPassword(e.target.value)}
/>
<Input
data-cy="confirmPasswordInput"
onChange={e => setConfirmPassword(e.target.value)}
/>
<SignupButton data-cy="signupButton" disabled={!isSignupBtnActive}>
회원가입
</SignupButton>
</Wrapper>
위 코드처럼 바꿔줬다.
응 아직도야~
이제 회원가입 버튼 클릭 시 로그인 화면으로 넘어가게 해준다.
<SignupButton
data-cy="signupButton"
disabled={!isSignupBtnActive}
onClick={() => handleSignup({ username: email, password })}
>
위와 같이 코드를 수정해주면 진짜 끝!
이야 대단해~
chatGPT를 사용해서 마저 테스트하기
비밀번호/비밀번호 확인값이 같이 않을 때 에러 메세지가 뜨는 것까지 테스트 해보자.
이전에 삭제한 SignupPage의 ui를 다시 되돌리고 해야 에러가 안 난다 ㅎㅎ...
// signup.cy.js
it('비밀번호와 비밀번호 확인 값이 일치하지 않는 경우 에러 메세지가 나타난다', () => {
// given - 가입 페이지로 이동
cy.visit('/signup');
// when - 비밀번호와 비밀번호 확인에 각각 다른 값 입력
cy.get('[data-cy=passwordInput]').type('password123');
cy.get('[data-cy=confirmPasswordInput').type('miss');
// then - 에러 메세지 확인
cy.get('[data-testid=error-message]')
.should('be.visible')
.and('have.text', '비밀번호가 일치하지 않습니다');
});
이 케이스를 추가해준다.
끝!
참고 강의
'⚛️ React > 📜 Test Code' 카테고리의 다른 글
[Test Code] cypress cloud / aws amplify에서 테스트 진행하기 (0) | 2024.07.16 |
---|---|
[Test Code] 스토리북 사용법 (0) | 2024.07.09 |
[Test Code] Cypress로 본격적인 테스트 코드 작성하기(fixture, recoil mocking) (0) | 2024.07.02 |
[Test Code] Cypress로 테스트 하기 (0) | 2024.07.02 |
[Test Code] react-query 공식 문서를 따라 테스트 코드를 하면 안되는 이유 + nock으로 mocking 하기 (0) | 2024.06.26 |