diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index f23dc57..0affdec 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -9,7 +9,6 @@ on: push: branches: - main - - develop workflow_dispatch: jobs: @@ -64,7 +63,30 @@ jobs: key: dev-depends-${{ matrix.os }}-bun${{ matrix.bun-version }}-${{ hashFiles('package.json') }} - name: Lint run: bun run lint - + test: + name: JavaScript Test on Ubuntu + needs: setup + runs-on: ${{ matrix.os }} + strategy: + matrix: + bun-version: [latest] + os: [ubuntu-latest] + steps: + - uses: actions/checkout@v4 + - name: Use Bun ${{ matrix.bun-version }} + uses: oven-sh/setup-bun@v1 + with: + bun-version: ${{ matrix.bun-version }} + - name: Cache Restore devDependencies + id: cache-restore-dev-depends + uses: actions/cache/restore@v3 + with: + path: '**/node_modules' + key: dev-depends-${{ matrix.os }}-bun${{ matrix.bun-version }}-${{ hashFiles('package.json') }} + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Test + run: bun run test build: name: JavaScript Build on Ubuntu needs: setup diff --git a/.storybook/main.ts b/.storybook/main.ts index a747d83..57b6f7a 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,39 +1,33 @@ -import type { StorybookConfig } from "@storybook/nextjs"; +import { dirname, join } from "node:path"; +import type { StorybookConfig } from "@storybook/experimental-nextjs-vite"; import path from "node:path"; const config: StorybookConfig = { stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], addons: [ - "@storybook/addon-links", - "@storybook/addon-essentials", - "@storybook/addon-onboarding", - "@storybook/addon-interactions", - "@storybook/addon-viewport", + getAbsolutePath("@storybook/addon-links"), + getAbsolutePath("@storybook/addon-essentials"), + getAbsolutePath("@storybook/addon-onboarding"), + getAbsolutePath("@storybook/addon-interactions"), + getAbsolutePath("@storybook/addon-viewport"), { name: "storybook-addon-next", options: { nextConfigPath: path.resolve(__dirname, "../next.config.js"), }, }, + getAbsolutePath("@storybook/experimental-addon-test"), ], - webpackFinal: (config) => { - if (config.resolve) { - // typescriptのエイリアスをstorybookでも使えるようにする - config.resolve.alias = { - ...config.resolve.alias, - "@": path.resolve(__dirname, "../src"), - }; - } - return config; - }, framework: { - name: "@storybook/nextjs", + name: getAbsolutePath("@storybook/experimental-nextjs-vite"), options: {}, }, - docs: { - autodocs: "tag", - }, + docs: {}, staticDirs: ["../public"], }; export default config; + +function getAbsolutePath(value: string) { + return dirname(require.resolve(join(value, "package.json"))); +} diff --git a/.storybook/vitest.setup.ts b/.storybook/vitest.setup.ts new file mode 100644 index 0000000..45f4af3 --- /dev/null +++ b/.storybook/vitest.setup.ts @@ -0,0 +1,10 @@ +import { beforeAll } from "vitest"; +import { setProjectAnnotations } from "@storybook/react"; +// biome-ignore lint/style/noNamespaceImport: +import * as projectAnnotations from "./preview"; + +// This is an important step to apply the right configuration when testing your stories. +// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations +const project = setProjectAnnotations([projectAnnotations]); + +beforeAll(project.beforeAll); diff --git a/biome.json b/biome.json index d8bf09b..943d4e2 100644 --- a/biome.json +++ b/biome.json @@ -1,8 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", - "organizeImports": { - "enabled": false - }, + "$schema": "https://biomejs.dev/schemas/1.9.3/schema.json", "files": { "ignore": [ "node_modules", @@ -52,32 +49,53 @@ }, "complexity": { "noExcessiveCognitiveComplexity": "off", + "noUselessStringConcat": "error", + "noUselessUndefinedInitialization": "error", "noVoid": "error", + "useDateNow": "error", "useSimplifiedLogicExpression": "error" }, "correctness": { "noConstantMathMinMaxClamp": "error", + "noInvalidNewBuiltin": "error", + "noNewSymbol": "error", "noUndeclaredVariables": "warn", + "noUnusedFunctionParameters": "error", + "noUnusedImports": "error", + "noUnusedPrivateClassMembers": "error", "noUnusedVariables": "warn", "useExhaustiveDependencies": "warn", "useHookAtTopLevel": "error" }, "nursery": { - "noDoneCallback": "error", "noDuplicateElseIf": "error", - "noDuplicateJsonKeys": "error", - "noEvolvingTypes": "error", - "noMisplacedAssertion": "error" + "noDynamicNamespaceImportAccess": "error", + "noEnum": "error", + "noExportedImports": "error", + "noIrregularWhitespace": "error", + "noSubstr": "error", + "noUselessEscapeInRegex": "error", + "useAdjacentOverloadSignatures": "error", + "useTrimStartEnd": "error" }, "recommended": true, "style": { + "noDoneCallback": "error", "noImplicitBoolean": "warn", + "noNamespace": "error", "noNamespaceImport": "error", "noNegationElse": "error", - "noParameterAssign": "off", + "noParameterAssign": "warn", "noParameterProperties": "off", "noShoutyConstants": "warn", + "noYodaExpression": "error", "useBlockStatements": "error", + "useCollapsedElseIf": "error", + "useConsistentArrayType": "error", + "useConsistentBuiltinInstantiation": "error", + "useDefaultSwitchClause": "error", + "useExplicitLengthCheck": "error", + "useForOf": "error", "useFragmentSyntax": "error", "useNamingConvention": { "level": "off", @@ -86,14 +104,24 @@ "strictCase": true } }, + "useNodeAssertStrict": "error", "useShorthandArrayType": "error", "useShorthandAssign": "error", - "useSingleCaseStatement": "error" + "useSingleCaseStatement": "error", + "useThrowNewError": "error", + "useThrowOnlyError": "error" }, "suspicious": { "noEmptyBlockStatements": "error", - "noSkippedTests": "error" + "noEvolvingTypes": "error", + "noMisplacedAssertion": "error", + "noSkippedTests": "error", + "useErrorMessage": "error", + "useNumberToFixedDigitsArgument": "error" } } + }, + "organizeImports": { + "enabled": false } } \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 586122c..e3aced8 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index b09af58..53432d1 100644 --- a/package.json +++ b/package.json @@ -9,65 +9,75 @@ "lint": "next lint && bun run biome check .", "lint:fix": "next lint --fix && bun run biome check . --write", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "storybook build", + "test": "vitest" }, "dependencies": { "@baselime/node-opentelemetry": "^0.5.8", - "@biomejs/biome": "^1.8.3", - "@radix-ui/react-avatar": "^1.1.0", - "@radix-ui/react-dialog": "^1.1.1", + "@biomejs/biome": "^1.9.3", + "@radix-ui/react-avatar": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-slot": "^1.1.0", "@vercel/analytics": "^1.3.1", "@vercel/speed-insights": "^1.0.12", "animate.css": "^4.1.1", - "autoprefixer": "10.4.19", + "autoprefixer": "10.4.20", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "eslint-plugin-jest-dom": "^5.4.0", "eslint-plugin-testing-library": "^6.3.0", "geist": "^1.3.1", "htmr": "^1.0.2", - "lucide-react": "^0.408.0", + "lucide-react": "^0.447.0", "microcms-js-sdk": "^3.1.2", - "next": "14.2.7", - "postcss": "8.4.39", - "qrcode.react": "^3.2.0", + "next": "14.2.14", + "postcss": "8.4.47", + "qrcode.react": "^4.0.1", "react": "18.3.1", "react-dom": "18.3.1", - "tailwind-merge": "^2.5.2", + "tailwind-merge": "^2.5.3", "tailwind-variants": "^0.2.1", - "tailwindcss": "3.4.6", + "tailwindcss": "3.4.13", "tailwindcss-animate": "^1.0.7", "the-new-css-reset": "^1.11.3", - "typescript": "5.4.5", - "umt": "^1.8.2", - "vaul": "^0.9.2" + "typescript": "5.6.2", + "umt": "^1.9.0", + "vaul": "^1.0.0" }, "devDependencies": { - "@storybook/addon-essentials": "^8.2.9", - "@storybook/addon-interactions": "^8.2.9", - "@storybook/addon-links": "^8.2.9", - "@storybook/addon-onboarding": "^8.2.9", - "@storybook/addon-viewport": "^8.2.9", - "@storybook/blocks": "^8.2.9", - "@storybook/nextjs": "^8.2.9", - "@storybook/react": "^8.2.9", - "@storybook/test": "^8.2.9", - "@types/node": "20.14.11", - "@types/react": "18.3.3", + "@storybook/addon-essentials": "^8.3.5", + "@storybook/addon-interactions": "^8.3.5", + "@storybook/addon-links": "^8.3.5", + "@storybook/addon-onboarding": "^8.3.5", + "@storybook/addon-viewport": "^8.3.5", + "@storybook/blocks": "^8.3.5", + "@storybook/experimental-addon-test": "^8.3.5", + "@storybook/experimental-nextjs-vite": "^8.3.5", + "@storybook/nextjs": "^8.3.5", + "@storybook/react": "^8.3.5", + "@storybook/test": "^8.3.5", + "@types/node": "22.7.4", + "@types/react": "18.3.11", "@types/react-dom": "18.3.0", - "dependency-cruiser": "^16.4.1", + "@vitejs/plugin-react": "^4.3.2", + "@vitest/browser": "^2.1.2", + "@vitest/coverage-v8": "^2.1.2", + "dependency-cruiser": "^16.4.2", "encoding": "^0.1.13", - "eslint": "^8.57.0", - "eslint-config-next": "^14.2.8", - "eslint-plugin-import": "^2.30.0", + "eslint": "^8.57.1", + "eslint-config-next": "^14.2.14", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-security": "^3.0.1", - "eslint-plugin-storybook": "^0.8.0", + "eslint-plugin-storybook": "^0.9.0", "eslint-plugin-unicorn": "^54.0.0", - "storybook": "^8.2.9", - "turbo": "^2.1.1" + "happy-dom": "^15.7.4", + "playwright": "^1.47.2", + "storybook": "^8.3.5", + "turbo": "^2.1.3", + "vite": "^5.4.8", + "vitest": "^2.1.2" }, "packageManager": "yarn@1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447" -} \ No newline at end of file +} diff --git a/src/stories/Button/index.stories.tsx b/src/stories/Button/index.stories.tsx index 6b00d99..d1c1a76 100644 --- a/src/stories/Button/index.stories.tsx +++ b/src/stories/Button/index.stories.tsx @@ -1,4 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react"; +import { userEvent, within } from "@storybook/test"; import { Button } from "@/components/ui/button"; const meta: Meta = { @@ -11,4 +12,8 @@ export const Primary: Story = { args: { children: "Button", }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole("button")); + }, }; diff --git a/src/styles/globals.css b/src/styles/globals.css index f7fc73b..872f844 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -75,9 +75,8 @@ } } - body { - display: flex; - justify-content: center; - align-items: center; -} \ No newline at end of file + display: flex; + justify-content: center; + align-items: center; +} diff --git a/tsconfig.json b/tsconfig.json index a56f6a7..0c3c328 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,8 +12,8 @@ "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, - "module": "CommonJS", - "moduleResolution": "node", + "module": "ESNext", + "moduleResolution": "Bundler", "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, @@ -54,6 +54,7 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", + "vitest.config.mts" ], "exclude": [ "node_modules" diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100755 index 0000000..2430c27 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + } +} \ No newline at end of file diff --git a/vitest.config.mts b/vitest.config.mts new file mode 100644 index 0000000..1f63b8b --- /dev/null +++ b/vitest.config.mts @@ -0,0 +1,43 @@ +import path from "node:path"; + +import { storybookTest } from "@storybook/experimental-addon-test/vitest-plugin"; +import { defineConfig } from "vitest/config"; +import react from "@vitejs/plugin-react"; + +// More info at: https://storybook.js.org/docs/writing-tests/vitest-plugin +export default defineConfig({ + plugins: [ + react(), + // See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest + storybookTest(), + ], + resolve: { + alias: { + "@": path.resolve(import.meta.dirname, "src"), + }, + }, + optimizeDeps: { + include: ["@storybook/experimental-addon-test/internal/test-utils"], + }, + test: { + globals: true, + environment: "happy-dom", + name: "storybook", + coverage: { + provider: "v8", + }, + browser: { + enabled: true, + headless: true, + name: "chromium", + provider: "playwright", + }, + // Make sure to adjust this pattern to match your stories files. + include: ["**/*.stories.?(m)[jt]s?(x)"], + setupFiles: ["./.storybook/vitest.setup.ts"], + typecheck: { + enabled: true, + tsconfig: "tsconfig.test.json", + }, + }, +});