티스토리 뷰

💥 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도 작게 하였다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함