Skip to content

Commit

Permalink
add nextjs version with pages folder
Browse files Browse the repository at this point in the history
  • Loading branch information
alan2207 committed Aug 18, 2024
1 parent 5d1c7e5 commit 99bc01a
Show file tree
Hide file tree
Showing 173 changed files with 20,017 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
yarn --cwd apps/react-vite lint-staged
yarn --cwd apps/react-vite lint-staged && yarn --cwd apps/nextjs-pages lint-staged
4 changes: 4 additions & 0 deletions apps/nextjs-pages/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
NEXT_PUBLIC_API_URL=http://localhost:8080/api
NEXT_PUBLIC_ENABLE_API_MOCKING=false
NEXT_PUBLIC_MOCK_API_PORT=8080
NEXT_PUBLIC_URL=http://localhost:3000
4 changes: 4 additions & 0 deletions apps/nextjs-pages/.env.example-e2e
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
NEXT_PUBLIC_API_URL=http://localhost:8080/api
NEXT_PUBLIC_ENABLE_API_MOCKING=false
NEXT_PUBLIC_MOCK_API_PORT=8080
NEXT_PUBLIC_URL=http://localhost:3000
154 changes: 154 additions & 0 deletions apps/nextjs-pages/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
module.exports = {
root: true,
env: {
node: true,
es6: true,
},
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
ignorePatterns: [
'node_modules/*',
'public/mockServiceWorker.js',
'generators/*',
],
extends: ['eslint:recommended', 'next/core-web-vitals'],
plugins: ['check-file'],
overrides: [
{
files: ['**/*.ts', '**/*.tsx'],
parser: '@typescript-eslint/parser',
settings: {
react: { version: 'detect' },
'import/resolver': {
typescript: {},
},
},
env: {
browser: true,
node: true,
es6: true,
},
extends: [
'eslint:recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:import/typescript',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
'plugin:prettier/recommended',
'plugin:testing-library/react',
'plugin:jest-dom/recommended',
'plugin:tailwindcss/recommended',
'plugin:vitest/legacy-recommended',
],
rules: {
'@next/next/no-img-element': 'off',
'import/no-restricted-paths': [
'error',
{
zones: [
// disables cross-feature imports:
// eg. src/features/discussions should not import from src/features/comments, etc.
{
target: './src/features/auth',
from: './src/features',
except: ['./auth'],
},
{
target: './src/features/comments',
from: './src/features',
except: ['./comments'],
},
{
target: './src/features/discussions',
from: './src/features',
except: ['./discussions'],
},
{
target: './src/features/teams',
from: './src/features',
except: ['./teams'],
},
{
target: './src/features/users',
from: './src/features',
except: ['./users'],
},
// enforce unidirectional codebase:

// e.g. src/app can import from src/features but not the other way around
{
target: './src/features',
from: './src/app',
},

// e.g src/features and src/app can import from these shared modules but not the other way around
{
target: [
'./src/components',
'./src/hooks',
'./src/lib',
'./src/types',
'./src/utils',
],
from: ['./src/features', './src/app'],
},
],
},
],
'import/no-cycle': 'error',
'linebreak-style': ['error', 'unix'],
'react/prop-types': 'off',
'import/order': [
'error',
{
groups: [
'builtin',
'external',
'internal',
'parent',
'sibling',
'index',
'object',
],
'newlines-between': 'always',
alphabetize: { order: 'asc', caseInsensitive: true },
},
],
'import/default': 'off',
'import/no-named-as-default-member': 'off',
'import/no-named-as-default': 'off',
'react/react-in-jsx-scope': 'off',
'jsx-a11y/anchor-is-valid': 'off',
'@typescript-eslint/no-unused-vars': ['error'],
'@typescript-eslint/explicit-function-return-type': ['off'],
'@typescript-eslint/explicit-module-boundary-types': ['off'],
'@typescript-eslint/no-empty-function': ['off'],
'@typescript-eslint/no-explicit-any': ['off'],
'prettier/prettier': ['error', {}, { usePrettierrc: true }],
'check-file/filename-naming-convention': [
'error',
{
'src/!(pages)/**': 'KEBAB_CASE',
},
{
ignoreMiddleExtensions: true,
},
],
},
},
{
plugins: ['check-file'],
files: ['src/**/!(__tests__)/*'],
rules: {
'check-file/folder-naming-convention': [
'error',
{
'**/*': 'KEBAB_CASE',
},
],
},
},
],
};
41 changes: 41 additions & 0 deletions apps/nextjs-pages/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/e2e/.auth/

# storybook
migration-storybook.log
storybook.log
storybook-static


# production
/dist

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*


# local
mocked-db.json

/.next
1 change: 1 addition & 0 deletions apps/nextjs-pages/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.hbs
7 changes: 7 additions & 0 deletions apps/nextjs-pages/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"tabWidth": 2,
"useTabs": false
}
20 changes: 20 additions & 0 deletions apps/nextjs-pages/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],

addons: [
'@storybook/addon-actions',
'@storybook/addon-links',
'@storybook/node-logger',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-docs',
'@storybook/addon-a11y',
],
framework: '@storybook/nextjs',
docs: {
autodocs: 'tag',
},
typescript: {
reactDocgen: 'react-docgen-typescript',
},
};
8 changes: 8 additions & 0 deletions apps/nextjs-pages/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';
import '../src/styles/globals.css';

export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
};

export const decorators = [(Story) => <Story />];
1 change: 1 addition & 0 deletions apps/nextjs-pages/.vite/vitest/results.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"1.6.0","results":[]}
9 changes: 9 additions & 0 deletions apps/nextjs-pages/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"dsznajder.es7-react-js-snippets",
"mariusalchimavicius.json-to-ts",
"bradlc.vscode-tailwindcss"
]
}
6 changes: 6 additions & 0 deletions apps/nextjs-pages/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
2 changes: 2 additions & 0 deletions apps/nextjs-pages/__mocks__/vitest-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// <reference types="vite/client" />
/// <reference types="vitest/globals" />
52 changes: 52 additions & 0 deletions apps/nextjs-pages/__mocks__/zustand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { act } from '@testing-library/react';
import { afterEach, vi } from 'vitest';
import * as zustand from 'zustand';

const { create: actualCreate, createStore: actualCreateStore } =
await vi.importActual<typeof zustand>('zustand');

// a variable to hold reset functions for all stores declared in the app
export const storeResetFns = new Set<() => void>();

const createUncurried = <T>(stateCreator: zustand.StateCreator<T>) => {
const store = actualCreate(stateCreator);
const initialState = store.getInitialState();
storeResetFns.add(() => {
store.setState(initialState, true);
});
return store;
};

// when creating a store, we get its initial state, create a reset function and add it in the set
export const create = (<T>(stateCreator: zustand.StateCreator<T>) => {
// to support curried version of create
return typeof stateCreator === 'function'
? createUncurried(stateCreator)
: createUncurried;
}) as typeof zustand.create;

const createStoreUncurried = <T>(stateCreator: zustand.StateCreator<T>) => {
const store = actualCreateStore(stateCreator);
const initialState = store.getInitialState();
storeResetFns.add(() => {
store.setState(initialState, true);
});
return store;
};

// when creating a store, we get its initial state, create a reset function and add it in the set
export const createStore = (<T>(stateCreator: zustand.StateCreator<T>) => {
// to support curried version of createStore
return typeof stateCreator === 'function'
? createStoreUncurried(stateCreator)
: createStoreUncurried;
}) as typeof zustand.createStore;

// reset all stores after each test run
afterEach(() => {
act(() => {
storeResetFns.forEach((resetFn) => {
resetFn();
});
});
});
5 changes: 5 additions & 0 deletions apps/nextjs-pages/e2e/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
extends: 'plugin:playwright/recommended',
};
42 changes: 42 additions & 0 deletions apps/nextjs-pages/e2e/tests/auth.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { test as setup, expect } from '@playwright/test';
import { createUser } from '../../src/testing/data-generators';

const authFile = 'e2e/.auth/user.json';

setup('authenticate', async ({ page }) => {
const user = createUser();

await page.goto('/');
await page.getByRole('button', { name: 'Get started' }).click();
await page.waitForURL('/auth/login');
await page.getByRole('link', { name: 'Register' }).click();

// registration:
await page.getByLabel('First Name').click();
await page.getByLabel('First Name').fill(user.firstName);
await page.getByLabel('Last Name').click();
await page.getByLabel('Last Name').fill(user.lastName);
await page.getByLabel('Email Address').click();
await page.getByLabel('Email Address').fill(user.email);
await page.getByLabel('Password').click();
await page.getByLabel('Password').fill(user.password);
await page.getByLabel('Team Name').click();
await page.getByLabel('Team Name').fill(user.teamName);
await page.getByRole('button', { name: 'Register' }).click();
await page.waitForURL('/app');

// log out:
await page.getByRole('button', { name: 'Open user menu' }).click();
await page.getByRole('menuitem', { name: 'Sign Out' }).click();
await page.waitForURL('/auth/login?redirectTo=%2Fapp');

// log in:
await page.getByLabel('Email Address').click();
await page.getByLabel('Email Address').fill(user.email);
await page.getByLabel('Password').click();
await page.getByLabel('Password').fill(user.password);
await page.getByRole('button', { name: 'Log in' }).click();
await page.waitForURL('/app');

await page.context().storageState({ path: authFile });
});
17 changes: 17 additions & 0 deletions apps/nextjs-pages/e2e/tests/profile.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { test, expect } from '@playwright/test';

test('profile', async ({ page }) => {
// update user:
await page.goto('/app');
await page.getByRole('button', { name: 'Open user menu' }).click();
await page.getByRole('menuitem', { name: 'Your Profile' }).click();
await page.getByRole('button', { name: 'Update Profile' }).click();
await page.getByLabel('Bio').click();
await page.getByLabel('Bio').fill('My bio');
await page.getByRole('button', { name: 'Submit' }).click();
await page
.getByLabel('Profile Updated')
.getByRole('button', { name: 'Close' })
.click();
await expect(page.getByText('My bio')).toBeVisible();
});
Loading

0 comments on commit 99bc01a

Please sign in to comment.