はじめに
2023年アドベントカレンダー8日目です。
今回から、「ユーザーはトップページを開くことができる」を進めていきます。
Let's Go!!
以前作成したデザインによると、
このような画面のようです。
今回は「ユーザーはトップページを開くことができる」なので、ブログの一覧をDBから取得するような処理は描かず、赤枠の部分だけ作成することにします。
TDD(テスト駆動開発)で進めていきます
ざっくりと今回の進め方を図解しました。
E2Eテスト
/// <reference types="cypress" />
describe('トップ画面の表示', () => {
beforeEach(() => {
cy.visit(cy.config('baseUrl'))
})
it('h1タグで"Life Sync"が表示されていること', () => {
cy.get('h1').should('have.text', 'Life Sync')
})
it('h2タグで"ブログ一覧"の文字が表示されていること', () => {
cy.get('h2').should('have.text', 'ブログ一覧')
})
it('"新規登作成"のボタンが表示されていること', () => {
cy.get('button').should('have.text', '新規作成')
})
})
npm run dev
npm run test:e2e
トップ画面の表示
1) h1タグで"Life Sync"が表示されていること
2) h2タグで"ブログ一覧"の文字が表示されていること
3) "新規登作成"のボタンが表示されていること
0 passing
3 failing
何も作成していないので、当然のようにテストは失敗します。
では次はUnit Testと行きたいところですが、今回のストーリーでは、ビジネスロジックを書くつもりはないので、E2Eテストのみで実装へ進みます。
コンポーネント設計
作成したい画面をよく見て、コンポーネント設計をしてみます。
簡単にこのような形で分解しました。
細かく分けるアトミックデザインのような考え方もありますが、自分は関心ごと単位で分けるくらいに抑えることが多いです。コンポーネントが増えると逆にメンテナンス性が下がることもありますので、、、
(参考)アトミックデザインとは
https://udemy.benesse.co.jp/design/web-design/atomic-design.html
実装
今回のストーリーでは、Header
, PrimaryButton
を作っていきます。
まずは最低限テストが通ることを目指します。
import React from 'react'
export const Header = () => {
return <h1>Life Sync</h1>
}
import React, { ButtonHTMLAttributes, FC, MouseEventHandler } from 'react'
interface Props {
text: string
type: ButtonHTMLAttributes<HTMLButtonElement>['type']
onClick?: MouseEventHandler<HTMLButtonElement>
}
export const Primary: FC<Props> = ({ text, type, onClick }) => {
const clickHander = onClick ? onClick : () => {}
return <button type={type} onClick={clickHander}>{text}</button>
}
これをpage.tsxで呼び出してみます。
'use client'
import { Blogs } from '@/components/Blogs'
import { Primary } from '@/components/Buttons/Primary'
export default function Home() {
return (
<main className='p-8 flex flex-col gap-4'>
<div className='flex justify-between'>
<h2 className='font-bold text-lg'>ブログ一覧</h2>
<Primary text='新規作成' type='button' onClick={moveBlogNew} />
</div>
</main>
)
}
さあテストを通してみましょう
npm run test:e2e
トップ画面の表示
✓ h1タグで"Life Sync"が表示されていること (380ms)
✓ h2タグで"ブログ一覧"の文字が表示されていること (353ms)
✓ "新規登作成"のボタンが表示されていること (344ms)
3 passing (1s)
通りました!
次はスタイルをデザイン案を見ながら適用します
再度E2Eテストを回します。
npm run test:e2e
トップ画面の表示
✓ h1タグで"Life Sync"が表示されていること (380ms)
✓ h2タグで"ブログ一覧"の文字が表示されていること (353ms)
✓ "新規登作成"のボタンが表示されていること (344ms)
3 passing (1s)
いい感じですね👍
まず最低限テストが通る実装をして、そのあとにリファクタリングをするようにしましょう
完成コード
Header.tsx
import React from 'react'
export const Header = () => {
return (
<div className='w-full px-6 py-3 border-b-2 border-stone-800'>
<h1 className='font-bold text-2xl'>Life Sync</h1>
</div>
)
}
Buttons/Primary.tsx
import React, { ButtonHTMLAttributes, FC, MouseEventHandler } from 'react'
interface Props {
text: string
type: ButtonHTMLAttributes<HTMLButtonElement>['type']
onClick?: MouseEventHandler<HTMLButtonElement>
}
export const Primary: FC<Props> = ({ text, type, onClick }) => {
const clickHander = onClick ? onClick : () => {}
return (
<button
type={type}
className='bg-green-500 py-2 px-4 rounded-lg w-fit text-white hover:bg-green-600'
onClick={clickHander}
>
{text}
</button>
)
}