보통 리액트는 컴포넌트를 기반으로 개발하게 되며 컴포넌트별로 CSS를 갖는 형식으로 스타일을 관리하게 된다. 하지만 모든 CSS를 한 곳에서 관리하지 않다 보면 CSS의 클래스 명이 중복되어 잘못된 스타일이 적용될 수 있다.
이런 문제를 해결하고자 style-components 라이브럴리가 탄생
style-components 장점
1) 클래스 이름 버그 해결
2) 더 쉬운 CSS 관리 : 모든 스타일이 특정 커모넌트에 연결되기 때문에 사용되지 않은 불필요한 스타일을 쉽게 제거
3) 간단한 동적 스타일 적용 : 컴포넌트의 상태에 따라 쉽고 직관적으로 동적 스타일 적용
4) CSS 자동 구성 : 페이지에 렌더링되는 컴포넌트를 추적하여 해당 스타일을 완전히 자동으로 추가
npx create-react-app my-app-style --template=typescript
cd my-app-style
npm install --save styled-components
npm install --save-dev @types/styled-components jest-styled-components
style-components 를 사용하여 리액트 컴포넌트를 생성하기 위해서는 Styled.[HTML 태그] 형식과 자바스크립트 템플릿 리터럴을 사용한다.
App.tsx파일)
Container 변수를 사용하기위해 App 함수내를 일부 수정한다.
<div className="App"> -> <Container> 대체
</div> -> </Container> 대체
const Container = Styled.div`
text-align: center;
`;
function App() {
return (
<Container>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</Container>
);
}
이제 Header 태그를 변경시도
const Header = Styled.header`
background-color: #282c34 !important;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
`;
AppLogo 태그를 변경시도
* 애니메이션을 분리하기 위해 keyframes 를 사용 / spin 변수에 담음
import Styled, {keyframes} from 'styled-components';
...
const spin = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
const AppLogo = Styled.img`
height: 40vmin;
pointer-events: none;
@media (prefers-reduced-motion: no-preference) {
animation: ${spin} infinite 20s linear;
}
`;
AppLink 태그를 변경시도
const AppLink = Styled.a`
color: #61dafb;
`;
Header / AppLogo / AppLink 3개 모두 App 함수 적용
function App() {
return (
<Container>
<Header>
<AppLogo src={logo} alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<AppLink
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</AppLink>
</Header>
</Container>
);
}
App.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
describe('<App />', () => {
it('renders component correctly', () => {
const { container } = render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
expect(container.getElementsByClassName('App-logo')).toHaveLength(1);
expect(container.getElementsByClassName('App-logo')[0]).toHaveAttribute(
'src',
'logo.svg'
);
expect(container.getElementsByTagName('p')).toHaveLength(1);
expect(container.getElementsByTagName('p')[0]).toHaveTextContent(
'Edit src/App.tsx and save to reload.'
);
expect(container).toMatchSnapshot();
});
});
npm run test
테스트 실행 결과 에러 메시지를 확인해 보면 App-logo 클래스를 통해 찾았던 HTML 요소를 찾지 못해 에러가 발생하는것을 확인할 수 있다.
styled-components를 사용하영 모든 HTML 요소에서 클래스를 제거하였기 때문에 당연히 테스트 에러가 발생한다.
const appLogo = screen.getByAltText('logo');
expect(appLogo).toBeInTheDocument();
expect(appLogo).toHaveAttribute('src', 'logo.svg');
react-testing-library의 screen을 활용하여 화면에서 logo라는 alt 속성을 가진 HTML 요소를 찾은 다음, 해당 요소가 화면에 표시되었는지를 Jest의 toBeInTheDocument 를 사용하여 확인한다.
또한, 해당 요소가 우리가 원하는 로고 이미지를 제대로 표시하는지 확인하기 위해 HTML의 src속성을 확인하여 logo.svg 이미지가 제대로 표시되는지 확인한다.
다시 npm run test
'2022 > 리액트+TDD(完)' 카테고리의 다른 글
react typescript 기본 테스트 코드 (0) | 2022.01.05 |
---|---|
TypeScript 적용3 - 절대경로 / Prettier 소개 (0) | 2022.01.04 |
TypeScript 적용1 (0) | 2022.01.03 |
리액트 테스트 도구 - react-testing-library (0) | 2021.11.05 |
리액트 테스트 도구 - Jest (0) | 2021.11.04 |