티스토리 뷰
💥 Title 컴포넌트
- Title.tsx
color는 ? 을 붙여서 옵셔널로 지정했기 때문에 color가 없을 경우엔 undefined가 나올 수 있다.
그래서 color가 없을 때의 경우도 따로 적어줘야 한다.
그렇기 때문에 color ? theme.color[color] : theme.color.primary 라는 코드를 적어주었다.
TitleStyle은 children, size, color 중 children은 사용하지 않을 예정이라 Omit 을 사용해서 빼주었다.
import { render, screen } from '@testing-library/react'
import { BookStoreThemeProvider } from '../../context/themeContext'
import Title from './Title'
describe("Title 컴포넌트 테스트", () => {
it('렌더를 확인', () => {
// 1. 렌더
render(
<BookStoreThemeProvider>
<Title size="large">제목</Title>
</BookStoreThemeProvider>
)
// 2. 확인
expect(screen.getByText("제목")).toBeInTheDocument()
})
it("size props 적용", () => {
const { container } = render(
<BookStoreThemeProvider>
<Title size="large">제목</Title>
</BookStoreThemeProvider>
)
expect(container?.firstChild).toHaveStyle({fontSize: "2rem"})
})
it('color props 적용', () => {
const { container } = render(
<BookStoreThemeProvider>
<Title size="large" color="primary">제목</Title>
</BookStoreThemeProvider>
)
expect(container?.firstChild).toHaveStyle({ color: "brown" })
})
})
- Title.spec.tsx
이렇게 Title.tsx의 테스트 파일도 만들어보았는데 어느 부분이 문제인 진 모르겠으나,
2번째, 3번째의 경우엔 자꾸 failed가 뜨고 있다. 시간내서 한 번 찾아봐야할 것 같다 😥
이렇게 1번째는 render, expect 둘 다 잘 되고있는데, 2번째, 3번째의 경우에만 이렇다...
firstChild부분엔 빨간줄이 뜨고 있고, toHaveStyle이 문제인가 싶었는데 구글링 해보니 썩 맘에 드는 해결방법을 찾지 못했다.
이 부분은, 따로 동기들이나 멘토님께 한 번 여쭤보면서 고쳐봐야겠다🤔
💥 Button 컴포넌트
- Button.tsx
Button 컴포넌트 역시 Title 컴포넌트와 크게 다르지 않게 만들었다.
ButtonStyle 역시 children, size, scheme, disabled, isLoading 중 children은 사용하지 않을거라 Omit을 사용해서 빼주었다.
import { render, screen } from '@testing-library/react'
import { BookStoreThemeProvider } from '../../context/themeContext'
import Button from './Button'
describe("Button 컴포넌트 테스트", () => {
it('렌더를 확인', () => {
// 1. 렌더
render(
<BookStoreThemeProvider>
<Button size="large" scheme="primary">버튼</Button>
</BookStoreThemeProvider>
)
// 2. 확인
expect(screen.getByText("버튼")).toBeInTheDocument()
})
})
- Button.spec.tsx
Button 테스트는 Title과는 다르게 Failed가 안 뜨는 부분만 확인해보았다.
이건 Title과 같이 passed가 나는 걸 볼 수 있다.
💥 Input 컴포넌트
- InputText.tsx
input 요소를 사용하다보면 Focus를 준다거나, 타겟에서 value에서 직접 가져온다던가.. 제어하는 상황이 꽤나 많은 편인데
이럴 때 필요한 게 forwardRef 이다.
그래서 이번엔 forwardRef 작성방식을 선택해서 만들었다.
이거 빼곤 다른 점은 딱히 없다.
import { render, screen } from '@testing-library/react'
import { BookStoreThemeProvider } from '../../context/themeContext'
import InputText from './InputText'
describe("InputText 컴포넌트 테스트", () => {
it('렌더를 확인', () => {
// 1. 렌더
render(
<BookStoreThemeProvider>
<InputText placeholder="여기에 입력"></InputText>
</BookStoreThemeProvider>
)
// 2. 확인
expect(screen.getByPlaceholderText("여기에 입력")).toBeInTheDocument()
})
})
- InputText.spec.tsx
테스트 역시, failed 뜨는 부분 제외하고 간단하게만 테스트 해보았다.
문제 없이 잘 passed가 뜨는 걸 볼 수 있다 😆
💥 헤더와 푸터
- Header
import { styled } from "styled-components";
import logo from "../../assets/images/logo.png";
import { FaSignInAlt, FaRegUser } from "react-icons/fa";
const CATEGORY = [
{
id: null,
name: "전체",
},
{
id: 0,
name: "동화",
},
{
id: 1,
name: "소설",
},
{
id: 2,
name: "사회",
}
]
function Header() {
return (
<HeaderStyle>
<h1 className="logo">
<img src={logo} alt="book store" />
</h1>
<nav className="category">
<ul>
{
CATEGORY.map((item) => (
<li key={item.id}>
<a href={item.id === null ? '/books' : `/books?category_id=${item.id}`}>
{item.name}
</a>
</li>
))
}
</ul>
</nav>
<nav className="auth">
<ul>
<li>
<a href="/login">
<FaSignInAlt />로그인
</a>
</li>
<li>
<a href="/login">
<FaRegUser />회원가입
</a>
</li>
</ul>
</nav>
</HeaderStyle>
);
}
const HeaderStyle = styled.header`
width: 100%;
margin: 0 auto;
max-width: ${({ theme }) => theme.layout.width.large};
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 0;
border-bottom: 1px solid ${({ theme }) => theme.color.background};
.logo {
img {
width: 200px;
}
}
.category {
ul {
display: flex;
gap: 32px;
li {
a {
font-size: 1.5rem;
font-weight: 500;
text-decoration: none;
color: ${({ theme }) => theme.color.text};
&:hover {
color: ${({ theme }) => theme.color.primary};
}
}
}
}
}
.auth {
ul{
display: flex;
gap: 16px;
li {
a {
font-size: 1rem;
font-weight: 500;
text-decoration: none;
display: flex;
align-item: center;
line-height: 1;
svg {
margin-right: 6px;
}
}
}
}
}
`
export default Header;
- Header.tsx
Header는 전체적으로 가로의 형태가 되도록 만들었다.
보통 가로로 나열하는 건 display: flex 를 많이 사용한다.
로그인, 회원가입은 react-icons 라이브러리를 사용하여 아이콘을 앞에 배치해 두었다.
로고의 색상인 orange 색으로 가운데에 있는 카테고리에 hover 시 색상이 바뀌게 스타일해놓았다.
- Footer
import styled from "styled-components";
import logo from "../../assets/images/logo.png";
function Footer() {
return (
<FooterStyle>
<h1 className="logo">
<img src={logo} alt="book store" />
</h1>
<div className="copyright">
<p>copyright(c), 2025, Book Store.</p>
</div>
</FooterStyle>
)
}
const FooterStyle = styled.footer`
width: 100%;
margin: 0 auto;
max-width: ${({ theme }) => theme.layout.width.large};
border-top: 1px solid ${({ theme }) => theme.color.background};
padding: 20px 0;
display: flex;
justify-content: space-between;
.logo {
img {
width: 140px;
}
}
.copyright {
p {
font-size: 0.75rem;
color: ${({ theme }) => theme.color.text};
}
}
`
export default Footer;
- Footer.tsx
Footer는 Header와 비슷한 디자인을 하되, 조금 더 작은 느낌을 주었다.
이미지 역시 Header보단 작게 만들었고, copyright 역시 엄청 잘 보여야할 부분은 아니기에 font-size도 작게 하였다.
'웹 개발 공부하기' 카테고리의 다른 글
[02.05] 로그인 API, 도서 API - Front (1) | 2025.02.13 |
---|---|
[02.04] 라우트 작성과 회원가입 API (3) | 2025.02.07 |
[01.31] 글로벌 스타일, 스타일드컴포넌트, 테마 (0) | 2025.02.05 |
[01.24] Book Store 프로젝트 프론트 준비! (1) | 2025.01.29 |
[01.23] 리액트를 이용한 Task 생성 앱 만들기 4 (1) | 2025.01.29 |