From ea92d171911bdab1773ef9239135c0f7adc68173 Mon Sep 17 00:00:00 2001 From: wookki Date: Sun, 24 Dec 2023 00:38:46 +0900 Subject: [PATCH 1/2] =?UTF-8?q?chore:=20tanstack-query-dev-tools=20?= =?UTF-8?q?=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 21 +++--- src/__tests__/page.test.tsx | 21 +++--- src/components/query/HydrateClient.tsx | 2 +- src/lib/getQueryClient.ts | 7 +- src/providers/StoreProvider.tsx | 20 +++--- src/providers/TanstackQueryProvider.tsx | 5 +- src/stores/hooks.ts | 13 ++-- src/stores/store.ts | 14 ++-- src/stories/Button.stories.ts | 24 +++---- src/stories/Button.tsx | 24 ++++--- src/stories/Header.stories.ts | 13 ++-- src/stories/Header.tsx | 91 +++++++++++++------------ src/stories/Page.stories.ts | 15 ++-- src/stories/Page.tsx | 29 +++++--- yarn.lock | 18 ++++- 15 files changed, 179 insertions(+), 138 deletions(-) diff --git a/package.json b/package.json index a13c0fb9..18b6f81f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "build": "next build", "start": "next start", "lint": "next lint", + "lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", "test": "jest", @@ -17,7 +18,10 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.0.1", + "@tanstack/query-core": "^4", "@tanstack/react-query": "^4", + "@tanstack/react-query-devtools": "^4", + "axios": "^1.6.2", "next": "^13", "react": "^18", "react-dom": "^18", @@ -33,27 +37,26 @@ "@storybook/react": "^7.6.6", "@storybook/test": "^7.6.6", "@tanstack/eslint-plugin-query": "^5.12.1", - "@tanstack/react-query-devtools": "^4", "@testing-library/jest-dom": "^6.1.5", "@testing-library/react": "^14.1.2", "@types/jest": "^29.5.11", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", - "eslint": "^8", - "eslint-config-next": "14.0.4", - "eslint-plugin-storybook": "^0.6.15", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "storybook": "^7.6.6", - "ts-node": "^10.9.2", "@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/parser": "^6.15.0", + "eslint": "^8", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-next": "14.0.4", "eslint-plugin-import": "^2.29.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-storybook": "^0.6.15", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "storybook": "^7.6.6", + "ts-node": "^10.9.2", "typescript": "^5" } -} \ No newline at end of file +} diff --git a/src/__tests__/page.test.tsx b/src/__tests__/page.test.tsx index 8b1cef97..576dbeac 100644 --- a/src/__tests__/page.test.tsx +++ b/src/__tests__/page.test.tsx @@ -1,13 +1,14 @@ -import '@testing-library/jest-dom' -import { render, screen } from '@testing-library/react' -import Page from '../app/page' +import "@testing-library/jest-dom"; +import { render, screen } from "@testing-library/react"; -describe('Page', () => { - it('renders a heading', () => { - render() +import Page from "../app/page"; - const heading = screen.getByRole('heading', { level: 1 }) +describe("Page", () => { + it("renders a heading", () => { + render(); - expect(heading).toBeInTheDocument() - }) -}) \ No newline at end of file + const heading = screen.getByRole("heading", { level: 1 }); + + expect(heading).toBeInTheDocument(); + }); +}); diff --git a/src/components/query/HydrateClient.tsx b/src/components/query/HydrateClient.tsx index 1d61efe2..2088f96f 100644 --- a/src/components/query/HydrateClient.tsx +++ b/src/components/query/HydrateClient.tsx @@ -6,4 +6,4 @@ function HydrateClient(props: HydrateProps) { return ; } -export default HydrateClient; \ No newline at end of file +export default HydrateClient; diff --git a/src/lib/getQueryClient.ts b/src/lib/getQueryClient.ts index a16c7599..4fd56e30 100644 --- a/src/lib/getQueryClient.ts +++ b/src/lib/getQueryClient.ts @@ -1,5 +1,6 @@ -import { QueryClient } from "@tanstack/query-core"; import { cache } from "react"; -const getQueryClient = cache(() => new QueryClient()); -export default getQueryClient; \ No newline at end of file +import { QueryClient } from "@tanstack/query-core"; + +const getQueryClient = cache(() => { return new QueryClient(); }); +export default getQueryClient; diff --git a/src/providers/StoreProvider.tsx b/src/providers/StoreProvider.tsx index 320c75dc..b7c0db5a 100644 --- a/src/providers/StoreProvider.tsx +++ b/src/providers/StoreProvider.tsx @@ -1,20 +1,22 @@ -'use client' -import { useRef } from 'react' -import { Provider } from 'react-redux' -import { makeStore, AppStore } from '@stores/store' +"use client"; + +import { useRef } from "react"; +import { Provider } from "react-redux"; + +import { makeStore, AppStore } from "@stores/store"; function StoreProvider({ - children + children, }: { children: React.ReactNode }) { - const storeRef = useRef() + const storeRef = useRef(); if (!storeRef.current) { // Create the store instance the first time this renders - storeRef.current = makeStore() + storeRef.current = makeStore(); } - return {children} + return {children}; } -export default StoreProvider \ No newline at end of file +export default StoreProvider; diff --git a/src/providers/TanstackQueryProvider.tsx b/src/providers/TanstackQueryProvider.tsx index 35505ecc..17c0bd03 100644 --- a/src/providers/TanstackQueryProvider.tsx +++ b/src/providers/TanstackQueryProvider.tsx @@ -1,8 +1,9 @@ "use client"; +import { useState } from "react"; + import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; -import { useState } from "react"; function TanstackQueryProvider({ children }: { children: React.ReactNode }) { const [client] = useState(new QueryClient()); @@ -15,4 +16,4 @@ function TanstackQueryProvider({ children }: { children: React.ReactNode }) { ); } -export default TanstackQueryProvider \ No newline at end of file +export default TanstackQueryProvider; diff --git a/src/stores/hooks.ts b/src/stores/hooks.ts index 233256a8..9c034267 100644 --- a/src/stores/hooks.ts +++ b/src/stores/hooks.ts @@ -1,8 +1,9 @@ -import { useDispatch, useSelector, useStore } from 'react-redux' -import type { TypedUseSelectorHook } from 'react-redux' -import type { RootState, AppDispatch, AppStore } from './store' +import type { RootState, AppDispatch, AppStore } from "./store"; +import type { TypedUseSelectorHook } from "react-redux"; + +import { useDispatch, useSelector, useStore } from "react-redux"; // Use throughout your app instead of plain `useDispatch` and `useSelector` -export const useAppDispatch: () => AppDispatch = useDispatch -export const useAppSelector: TypedUseSelectorHook = useSelector -export const useAppStore: () => AppStore = useStore \ No newline at end of file +export const useAppDispatch: () => AppDispatch = useDispatch; +export const useAppSelector: TypedUseSelectorHook = useSelector; +export const useAppStore: () => AppStore = useStore; diff --git a/src/stores/store.ts b/src/stores/store.ts index 90c44401..d8f1f988 100644 --- a/src/stores/store.ts +++ b/src/stores/store.ts @@ -1,13 +1,13 @@ -import { configureStore } from '@reduxjs/toolkit' +import { configureStore } from "@reduxjs/toolkit"; export const makeStore = () => { return configureStore({ - reducer: {} - }) -} + reducer: {}, + }); +}; // Infer the type of makeStore -export type AppStore = ReturnType +export type AppStore = ReturnType; // Infer the `RootState` and `AppDispatch` types from the store itself -export type RootState = ReturnType -export type AppDispatch = AppStore['dispatch'] \ No newline at end of file +export type RootState = ReturnType; +export type AppDispatch = AppStore["dispatch"]; diff --git a/src/stories/Button.stories.ts b/src/stories/Button.stories.ts index 742c3aa7..5e29e9ac 100644 --- a/src/stories/Button.stories.ts +++ b/src/stories/Button.stories.ts @@ -1,20 +1,20 @@ -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, StoryObj } from "@storybook/react"; -import { Button } from './Button'; +import { Button } from "./Button"; // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta = { - title: 'Example/Button', + title: "Example/Button", component: Button, parameters: { // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout - layout: 'centered', + layout: "centered", }, // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs - tags: ['autodocs'], + tags: ["autodocs"], // More on argTypes: https://storybook.js.org/docs/api/argtypes argTypes: { - backgroundColor: { control: 'color' }, + backgroundColor: { control: "color" }, }, } satisfies Meta; @@ -25,26 +25,26 @@ type Story = StoryObj; export const Primary: Story = { args: { primary: true, - label: 'Button', + label: "Button", }, }; export const Secondary: Story = { args: { - label: 'Button', + label: "Button", }, }; export const Large: Story = { args: { - size: 'large', - label: 'Button', + size: "large", + label: "Button", }, }; export const Small: Story = { args: { - size: 'small', - label: 'Button', + size: "small", + label: "Button", }, }; diff --git a/src/stories/Button.tsx b/src/stories/Button.tsx index e3cb2f23..6bd099e2 100644 --- a/src/stories/Button.tsx +++ b/src/stories/Button.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import './button.css'; +import React from "react"; +import "./button.css"; interface ButtonProps { /** @@ -13,7 +13,7 @@ interface ButtonProps { /** * How large should the button be? */ - size?: 'small' | 'medium' | 'large'; + size?: "small" | "medium" | "large"; /** * Button contents */ @@ -27,26 +27,28 @@ interface ButtonProps { /** * Primary UI component for user interaction */ -export const Button = ({ +export function Button({ primary = false, - size = 'medium', + size = "medium", backgroundColor, label, ...props -}: ButtonProps) => { - const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; +}: ButtonProps) { + const mode = primary ? "storybook-button--primary" : "storybook-button--secondary"; return ( ); -}; +} diff --git a/src/stories/Header.stories.ts b/src/stories/Header.stories.ts index 046982e6..267a58d1 100644 --- a/src/stories/Header.stories.ts +++ b/src/stories/Header.stories.ts @@ -1,14 +1,15 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { Header } from './Header'; +import type { Meta, StoryObj } from "@storybook/react"; + +import { Header } from "./Header"; const meta = { - title: 'Example/Header', + title: "Example/Header", component: Header, // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs - tags: ['autodocs'], + tags: ["autodocs"], parameters: { // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout - layout: 'fullscreen', + layout: "fullscreen", }, } satisfies Meta; @@ -18,7 +19,7 @@ type Story = StoryObj; export const LoggedIn: Story = { args: { user: { - name: 'Jane Doe', + name: "Jane Doe", }, }, }; diff --git a/src/stories/Header.tsx b/src/stories/Header.tsx index 01504601..48a66d80 100644 --- a/src/stories/Header.tsx +++ b/src/stories/Header.tsx @@ -1,7 +1,7 @@ -import React from 'react'; +import React from "react"; -import { Button } from './Button'; -import './header.css'; +import { Button } from "./Button"; +import "./header.css"; type User = { name: string; @@ -14,43 +14,50 @@ interface HeaderProps { onCreateAccount: () => void; } -export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => ( -
-
-
- - - - - - - -

Acme

+export function Header({ + user, onLogin, onLogout, onCreateAccount, +}: HeaderProps) { + return ( +
+
+
+ + + + + + + +

Acme

+
+
+ {user ? ( + <> + + Welcome, + {" "} + {user.name} + ! + +
-
- {user ? ( - <> - - Welcome, {user.name}! - -
-
-
-); + + ); +} diff --git a/src/stories/Page.stories.ts b/src/stories/Page.stories.ts index f7a06817..5349089b 100644 --- a/src/stories/Page.stories.ts +++ b/src/stories/Page.stories.ts @@ -1,14 +1,15 @@ -import type { Meta, StoryObj } from '@storybook/react'; -import { within, userEvent, expect } from '@storybook/test'; +import type { Meta, StoryObj } from "@storybook/react"; -import { Page } from './Page'; +import { within, userEvent, expect } from "@storybook/test"; + +import { Page } from "./Page"; const meta = { - title: 'Example/Page', + title: "Example/Page", component: Page, parameters: { // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout - layout: 'fullscreen', + layout: "fullscreen", }, } satisfies Meta; @@ -21,12 +22,12 @@ export const LoggedOut: Story = {}; export const LoggedIn: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); - const loginButton = canvas.getByRole('button', { name: /Log in/i }); + const loginButton = canvas.getByRole("button", { name: /Log in/i }); await expect(loginButton).toBeInTheDocument(); await userEvent.click(loginButton); await expect(loginButton).not.toBeInTheDocument(); - const logoutButton = canvas.getByRole('button', { name: /Log out/i }); + const logoutButton = canvas.getByRole("button", { name: /Log out/i }); await expect(logoutButton).toBeInTheDocument(); }, }; diff --git a/src/stories/Page.tsx b/src/stories/Page.tsx index e1174830..236a6e23 100644 --- a/src/stories/Page.tsx +++ b/src/stories/Page.tsx @@ -1,7 +1,7 @@ -import React from 'react'; +import React from "react"; -import { Header } from './Header'; -import './page.css'; +import { Header } from "./Header"; +import "./page.css"; type User = { name: string; @@ -14,18 +14,20 @@ export const Page: React.FC = () => {
setUser({ name: 'Jane Doe' })} - onLogout={() => setUser(undefined)} - onCreateAccount={() => setUser({ name: 'Jane Doe' })} + onLogin={() => { return setUser({ name: "Jane Doe" }); }} + onLogout={() => { return setUser(undefined); }} + onCreateAccount={() => { return setUser({ name: "Jane Doe" }); }} />

Pages in Storybook

- We recommend building UIs with a{' '} + We recommend building UIs with a + {" "} component-driven - {' '} + + {" "} process starting with atomic components and ending with pages.

@@ -44,18 +46,23 @@ export const Page: React.FC = () => {

- Get a guided tutorial on component-driven development at{' '} + Get a guided tutorial on component-driven development at + {" "} Storybook tutorials - . Read more in the{' '} + . Read more in the + {" "} docs .

- Tip Adjust the width of the canvas with the{' '} + Tip + {" "} + Adjust the width of the canvas with the + {" "} Date: Sun, 24 Dec 2023 01:04:27 +0900 Subject: [PATCH 2/2] chore: resolve lint error --- package.json | 2 +- src/stories/Button.tsx | 7 ------- src/stories/Page.stories.ts | 1 + src/stories/Page.tsx | 6 +++--- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 18b6f81f..8526d0bf 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.0.1", + "@storybook/test": "^7.6.6", "@tanstack/query-core": "^4", "@tanstack/react-query": "^4", "@tanstack/react-query-devtools": "^4", @@ -35,7 +36,6 @@ "@storybook/blocks": "^7.6.6", "@storybook/nextjs": "^7.6.6", "@storybook/react": "^7.6.6", - "@storybook/test": "^7.6.6", "@tanstack/eslint-plugin-query": "^5.12.1", "@testing-library/jest-dom": "^6.1.5", "@testing-library/react": "^14.1.2", diff --git a/src/stories/Button.tsx b/src/stories/Button.tsx index 6bd099e2..e9395916 100644 --- a/src/stories/Button.tsx +++ b/src/stories/Button.tsx @@ -42,13 +42,6 @@ export function Button({ {...props} > {label} - ); } diff --git a/src/stories/Page.stories.ts b/src/stories/Page.stories.ts index 5349089b..c959802e 100644 --- a/src/stories/Page.stories.ts +++ b/src/stories/Page.stories.ts @@ -24,6 +24,7 @@ export const LoggedIn: Story = { const canvas = within(canvasElement); const loginButton = canvas.getByRole("button", { name: /Log in/i }); await expect(loginButton).toBeInTheDocument(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-call await userEvent.click(loginButton); await expect(loginButton).not.toBeInTheDocument(); diff --git a/src/stories/Page.tsx b/src/stories/Page.tsx index 236a6e23..e30fff12 100644 --- a/src/stories/Page.tsx +++ b/src/stories/Page.tsx @@ -7,7 +7,7 @@ type User = { name: string; }; -export const Page: React.FC = () => { +export function Page() { const [user, setUser] = React.useState(); return ( @@ -38,7 +38,7 @@ export const Page: React.FC = () => {
  • Use a higher-level connected component. Storybook helps you compose such data from the - "args" of child component stories + of child component stories
  • Assemble data in the page component from your services. You can mock these services out @@ -77,4 +77,4 @@ export const Page: React.FC = () => {
); -}; +}