diff --git a/.eslintrc.json b/.eslintrc.json index 5b3c55f..3d5502a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,9 +1,5 @@ { "root": true, - "env": { - "node": true, - "es6": true - }, "parserOptions": { "ecmaVersion": 8, "sourceType": "module" @@ -29,11 +25,7 @@ "typescript": {} } }, - "env": { - "browser": true, - "node": true, - "es6": true - }, + "env": { "browser": true, "jest": true, "node": true, "es6": true }, "extends": [ "eslint:recommended", "plugin:import/errors", @@ -43,9 +35,9 @@ "plugin:react/recommended", "plugin:react-hooks/recommended", "plugin:jsx-a11y/recommended", + "plugin:jest-dom/recommended", "plugin:prettier/recommended", - "plugin:testing-library/react", - "plugin:jest-dom/recommended" + "plugin:storybook/recommended" ], "rules": { "no-restricted-imports": [ @@ -104,6 +96,14 @@ // a common eslint issue with nextjs when using CSS in JS "react/no-unknown-property": ["error", { "ignore": ["jsx"] }] } + }, + // Only uses Testing Library lint rules in test files + { + "files": [ + "**/__tests__/**/*.[jt]s?(x)", + "**/?(*.)+(spec|test).[jt]s?(x)" + ], + "extends": ["plugin:testing-library/react"] } ] } diff --git a/.github/ISSUE_TEMPLATE/new-feature.md b/.github/ISSUE_TEMPLATE/new-feature.md new file mode 100644 index 0000000..2a27ff8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new-feature.md @@ -0,0 +1,22 @@ +--- +name: New feature +about: New component +title: "" +labels: "" +assignees: "" +--- + +**Task title** +The task title + +**Task description** +Put the description here (Mandatory) + +**Subtasks** +Put the subtasks here if any (optional) + +**Screenshots** +Put at least one screenshot here + +**Link to the component on Figma** +Put the link here diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..6812c1d --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,22 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v4 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v3 + with: + fail-on-severity: moderate diff --git a/.github/workflows/issue-link.yml b/.github/workflows/issue-link.yml new file mode 100644 index 0000000..cdcfeef --- /dev/null +++ b/.github/workflows/issue-link.yml @@ -0,0 +1,17 @@ +name: 'Issue Links' +on: + pull_request: + types: [opened] + +jobs: + issue-links: + runs-on: ubuntu-latest + # https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token + permissions: + pull-requests: write + steps: + - uses: tkt-actions/add-issue-links@v1.8.2 + with: + repo-token: '${{ secrets.GITHUB_TOKEN }}' # required + resolve: "true" + branch-prefix: 'issue-' # required diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..dfbcd16 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,98 @@ +name: CI +on: + push: + branches: + - main + - develop + pull_request: {} + +jobs: + lint: + name: ๐งช Test, ๐งน ESLint, ๐ Stylelint, ๐ Prettier, and สฆ TypeScript + runs-on: ubuntu-latest + steps: + - name: โฌ๏ธ Checkout repo + uses: actions/checkout@v4 + + - name: โ Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: ๐ฆ Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + + - name: ๐๏ธ Get pnpm store directory + id: store + run: echo "::set-output name=path::$(pnpm store path --silent)" + + - name: ๐ Cache pnpm dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.store.outputs.path }} + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + + - name: ๐งฐ Install dependencies + run: pnpm install + + - name: โฌฃ Build project + run: pnpm build + + - name: ๐งช Run tests + run: pnpm test + + - name: ๐งน Lint code + run: pnpm lint:next + + - name: ๐ Check styles + run: pnpm check-styles + + - name: ๐ Check formatting + run: pnpm check-format + + - name: สฆ Check types + run: pnpm check-types + + cypress-run: + name: ๐ฒ Cypress Tests + needs: lint + runs-on: ubuntu-latest + steps: + - name: โฌ๏ธ Checkout repo + uses: actions/checkout@v4 + + - name: โ Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: ๐ฆ Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + + - name: ๐๏ธ Get pnpm store directory + id: store + run: echo "::set-output name=path::$(pnpm store path --silent)" + + - name: ๐ Cache pnpm dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.store.outputs.path }} + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + + - name: ๐งฐ Install dependencies + run: pnpm install + + # - run: mv .env.example .env + - name: ๐ Run Cypress tests + uses: cypress-io/github-action@v6 + with: + build: pnpm build + start: pnpm start diff --git a/.storybook/main.ts b/.storybook/main.ts index d8fb820..60b5dbf 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,22 +1,19 @@ -import type { StorybookConfig } from '@storybook/nextjs'; +import type { StorybookConfig } from '@storybook/nextjs' 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" - ], - "framework": { - "name": "@storybook/nextjs", - "options": {} - }, - "docs": { - "autodocs": "tag" - } -}; -export default config; \ No newline at end of file + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-onboarding', + '@storybook/addon-interactions' + ], + framework: { + name: '@storybook/nextjs', + options: {} + }, + docs: { + autodocs: 'tag' + } +} +export default config diff --git a/.storybook/preview.ts b/.storybook/preview.ts index ece2369..7850968 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,15 +1,15 @@ import type { Preview } from '@storybook/react' const preview: Preview = { - parameters: { - actions: { argTypesRegex: '^on[A-Z].*' }, - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/i, - }, - }, - }, -}; + parameters: { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i + } + } + } +} -export default preview; \ No newline at end of file +export default preview diff --git a/cypress/.eslintrc.js b/cypress/.eslintrc.js index a7c5984..0559944 100644 --- a/cypress/.eslintrc.js +++ b/cypress/.eslintrc.js @@ -1,6 +1,6 @@ module.exports = { - root: true, - plugins: ['eslint-plugin-cypress'], - parser: '@typescript-eslint/parser', - env: { 'cypress/globals': true }, -}; + root: true, + plugins: ['eslint-plugin-cypress'], + parser: '@typescript-eslint/parser', + env: { 'cypress/globals': true } +} diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json index 71d9a9f..adb333d 100644 --- a/cypress/tsconfig.json +++ b/cypress/tsconfig.json @@ -1,9 +1,9 @@ { - "compilerOptions": { - "esModuleInterop": true, - "target": "es5", - "lib": ["es5", "dom"], - "types": ["node", "cypress", "@testing-library/cypress"] - }, - "include": ["**/*.ts"] + "compilerOptions": { + "esModuleInterop": true, + "target": "es5", + "lib": ["es5", "dom"], + "types": ["node", "cypress", "@testing-library/cypress"] + }, + "include": ["**/*.ts"] } diff --git a/next.config.js b/next.config.js index fbdaf80..09b6ac5 100644 --- a/next.config.js +++ b/next.config.js @@ -6,6 +6,7 @@ // Github app is just an example const nextConfig = { + reactStrictMode: true, env: { GITHUB_APP_CLIENT_ID: '', GITHUB_APP_CLIENT_SECRET: '', diff --git a/package.json b/package.json index 4a102d1..ad04c49 100644 --- a/package.json +++ b/package.json @@ -29,25 +29,29 @@ "dev": "next dev", "build": "next build", "start": "next start", - "eslint": "eslint --cache --ext js,jsx,ts,tsx --report-unused-disable-directives --max-warnings 0 --ignore-path .gitignore", - "lint": "next lint", - "lint:fix": "eslint --cache --fix --ext .js,.jsx,.ts,.tsx", - "lint:css": "stylelint --cache \"**/*.{css,scss}\"", - "lint:css:fix": "stylelint --cache \"**/*.{css,scss}\" --fix", - "prettier": "prettier --ignore-path .gitignore --write --check \"**/*.+(js|jsx|ts|tsx|css|scss|json)\"", - "format": "prettier . --check", - "format:fix": "prettier . --write", - "test": "jest", + "test": "if-env CI=1 pnpm test:coverage || pnpm test:jest", + "test:jest": "jest", + "test:coverage": "cross-env CI=1 jest --coverage", "test:watch": "jest --watch", - "test:coverage": "jest --coverage", "cy:install": "cypress install", "cy:run": "cypress run", "cy:open": "cypress open", "test:e2e": "start-server-and-test dev http://localhost:3000 \"cypress open --e2e\"", "test:e2e:headless": "start-server-and-test dev http://localhost:3000 \"cypress run --e2e\"", - "component": "cypress open --component", - "component:h": "cypress run --component", - "prepare": "husky install", + "lint": "eslint --cache --fix --ext js,jsx,ts,tsx ./src --report-unused-disable-directives --max-warnings 0 --ignore-path .gitignore", + "lint:next": "next lint", + "lint:css": "stylelint --cache \"**/*.{css,scss}\"", + "lint:css:fix": "stylelint --cache --fix \"**/*.{css,scss}\"", + "prettier": "prettier --ignore-path .gitignore --write \"**/*.+(js|json|ts|tsx|css|scss|)\"", + "format": "pnpm prettier --check", + "format:fix": "pnpm prettier --write", + "check-types": "tsc --project tsconfig.json --pretty --noEmit", + "check-format": "pnpm prettier --list-different", + "check-style": "pnpm lint:css", + "validate-and-build": "npm-run-all --parallel check-types check-format lint build", + "validate": "npm-run-all --parallel check-types lint-staged", + "lint-staged": "npx lint-staged", + "postinstall": "husky install", "generate": "plop", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build" @@ -61,6 +65,7 @@ "devDependencies": { "@commitlint/cli": "^18.4.2", "@commitlint/config-conventional": "^18.4.2", + "@jest/globals": "^29.7.0", "@storybook/addon-essentials": "7.5.3", "@storybook/addon-interactions": "7.5.3", "@storybook/addon-links": "7.5.3", @@ -80,6 +85,7 @@ "@typescript-eslint/eslint-plugin": "^6.11.0", "@typescript-eslint/parser": "^6.11.0", "autoprefixer": "^10.4.16", + "cross-env": "^7.0.3", "cypress": "^13.6.0", "cz-git": "^1.7.1", "eslint": "^8.54.0", @@ -97,14 +103,19 @@ "eslint-plugin-tailwindcss": "^3.13.0", "eslint-plugin-testing-library": "^6.1.2", "husky": "^8.0.3", + "if-env": "^1.0.4", + "is-ci": "^3.0.1", + "is-ci-cli": "^2.2.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", + "npm-run-all": "^4.1.5", "plop": "^4.0.0", "postcss": "^8", "postcss-syntax": "^0.36.2", "prettier": "^3.1.0", "prettier-plugin-tailwindcss": "^0.5.7", "react-query": "^3.39.3", + "start-server-and-test": "^2.0.3", "storybook": "7.5.3", "stylelint": "^15.10.0", "stylelint-config-idiomatic-order": "^9.0.0", @@ -134,9 +145,11 @@ } }, "lint-staged": { - "**/*.{js,jsx,ts,tsx}": [ + "**/*.{ts,tsx}": [ + "pnpm prettier", "pnpm eslint" ], + "**/*.{test,spec}.{ts,tsx}": "pnpm test", "**/*.{css,scss}": [ "stylelint --cache --fix && pnpm prettier" ] diff --git a/src/app/page.tsx b/src/app/page.tsx index db0c6bc..37d9236 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -32,6 +32,7 @@ export default function Home() {