-
Notifications
You must be signed in to change notification settings - Fork 0
Libraries
configuration
__mocks__/fileMock.js
module.exports = 'test-file-stub'__mocks__/styleMock.js
module.exports = {}jest.config.cjs
You can modify collectCoverageFrom and coverageThreshold for coverage configuration.
You can modify moduleNameMapper for absolute path.
module.exports = {
testEnvironment: 'jsdom',
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/App.tsx',
'!src/env.ts',
'!src/{stories,store,mocks,utils,hooks}/**',
'!src/**/*.{types,type,stories,constants,test,spec}.{ts,tsx}',
'!**/*.d.ts',
'!**/*.config.*',
'!**/node_modules/**',
'!**/.yarn/**'
],
testMatch: [
'<rootDir>/__tests__/**/*.(spec|test).ts?(x)',
'<rootDir>/src/**/*.(spec|test).ts?(x)',
],
moduleNameMapper: {
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
'^.+\\.(jpg|jpeg|png|gif|webp|svg)$': '<rootDir>/__mocks__/fileMock.js',
'^src/(.*)$': '<rootDir>/src/$1',
'^@/(.*)$': '<rootDir>/src/$1',
},
setupFilesAfterEnv: [
'<rootDir>/jest.setup.ts',
'jest-plugin-context/setup',
],
testPathIgnorePatterns: [
'<rootDir>/node_modules/',
'<rootDir>/.yarn/'
],
transform: {
'^.+\\.(js|jsx|ts|tsx)$': [
'@swc/jest',
{
sourceMaps: true,
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
decorators: false,
dynamicImport: false,
},
transform: {
react: {
runtime: 'automatic',
},
},
},
},
],
},
coveragePathIgnorePatterns: [
'/node_modules/',
'^.+\\.module\\.(css|sass|scss)$',
'coverage',
'src/main.ts',
'.yarn',
'src/config.ts',
],
coverageThreshold: {
global: {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
},
};jest.setup.ts
Configuration for jest & MSW.
import '@testing-library/jest-dom';
import {server} from "./src/mocks/server";
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());configuration
.eslintrc.json
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:react/recommended",
"standard-with-typescript",
"plugin:prettier/recommended",
"plugin:jest-dom/recommended",
"plugin:storybook/recommended"
],
"overrides": [
{
"files": ["*.jsx", "*.tsx"],
"rules": {
"@typescript-eslint/explicit-function-return-type": ["off"]
}
},
{
"files": ["**/stories/**.jsx", "**/stories/**.tsx"],
"rules": {
"@typescript-eslint/consistent-type-assertions": ["off"]
}
}
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module",
"project": "./tsconfig.json"
},
"plugins": [
"react"
],
"rules": {
"react/react-in-jsx-scope": "off",
"prettier/prettier": ["error", { "endOfLine": "auto" }]
},
"ignorePatterns": [
"vite-env.d.ts",
"jest.config.cjs",
"jest.setup.ts",
"vite.config.ts",
"__mocks__/**"
]
}.vscode/settings.json
Forcing the ESLint auto fix in case of not configuring themselves.
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.format.enable": true,
"editor.formatOnSave": false,
}configuration
.prettierrc
You can modify by your preferences.
{
"trailingComma": "all",
"singleQuote": true,
"semi": true,
"useTabs": false,
"tabWidth": 2,
"printWidth": 80,
"arrowParens": "always"
}
configuration
.husky/pre-commit
Checking lint error before commit.
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
.husky/pre-push
Checking all test files before push.
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn run jest --watchAll=false
pacakge.json
"scripts": {
"lint": "eslint --fix",
},
"lint-staged": {
"src/**/*.{ts,js,tsx}": [
"yarn lint"
]
}configuration
There is no configuration.
configuration
.storybook
src/stories
There is no configuration.
Only default configuration is added.
configuration
This project is using react-query with axios.
src/main.tsx
import { QueryClientProvider, QueryClient } from "react-query";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<QueryClientProvider client={new QueryClient()}>
<RecoilRoot>
<Router>
<App />
</Router>
</RecoilRoot>
</QueryClientProvider>
</React.StrictMode>
);src/utils/axios.ts
import axios, { AxiosInstance } from 'axios';
export const useAxios = async (): Promise<AxiosInstance> => {
const instance = await axios.create({
baseURL: import.meta.env.VITE_API_URL,
headers: {
'Content-Type': 'application/json',
},
});
return instance;
};src/hooks/useGetUsers.ts
import { useQuery, UseQueryResult } from 'react-query';
import { useAxios } from '@/utils/axios';
interface userGetResType {
id: number;
name: string;
username: string;
email: string;
}
const getUser = async (id: number): Promise<userGetResType> => {
try {
const { data } = await (await useAxios()).get(`/users/${id}`);
return data;
} catch (err: any) {
throw new Error(err.response.status, { cause: err.response.data });
}
};
export const useGetUser = (id: number): UseQueryResult<userGetResType, any> => {
return useQuery<userGetResType, any>('user', async () => await getUser(id));
};src/pages/User.tsx
import { useEffect, useState } from 'react';
import { useGetUser } from '@/hooks/useGetUsers';
import userState from '@/store/user';
import { useSetRecoilState } from 'recoil';
export default function User() {
const { isLoading, isError, error, data } = useGetUser(1);
const [warning, setWarning] = useState<string>('');
const setUser = useSetRecoilState(userState);
useEffect(() => {
if (data != null) {
setUser(data);
}
if (isError) {
error?.message === '404' && setWarning('404: Cannot request');
}
}, [isError, data]);
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div className="App">
<p>{warning !== '' && warning}</p>
<p>{data?.name}</p>
</div>
);
}
configuration
src/mocks/handlers.ts
import { rest } from 'msw';
import { VITE_API_URL } from '../env';
const url: string = VITE_API_URL;
export const handlers = [
rest.get(`${url}/users/1`, (req, res, ctx) => {
return res(
ctx.json({
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere@april.biz',
address: {
street: 'Kulas Light',
suite: 'Apt. 556',
city: 'Gwenborough',
zipcode: '92998-3874',
geo: { lat: '-37.3159', lng: '81.1496' },
},
phone: '1-770-736-8031 x56442',
website: 'hildegard.org',
company: {
name: 'Romaguera-Crona',
catchPhrase: 'Multi-layered client-server neural-net',
bs: 'harness real-time e-markets',
},
}),
);
}),
];src/mocks/server.ts
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);jest.setup.ts
import { server } from './mocks/server.js'
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());configuration
src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
import { QueryClientProvider, QueryClient } from 'react-query';
import { RecoilRoot } from 'recoil';
import { BrowserRouter as Router } from 'react-router-dom';
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<QueryClientProvider client={new QueryClient()}>
<RecoilRoot>
<Router>
<App />
</Router>
</RecoilRoot>
</QueryClientProvider>
</React.StrictMode>,
);
src/store/user.ts
import { atom } from 'recoil';
interface UserType {
id: number;
name: string;
username: string;
email: string;
}
const userState = atom<UserType>({
key: 'todos',
default: {
id: 0,
name: '',
username: '',
email: '',
},
});
export default userState;src/pages/User.tsx
import { useEffect, useState } from 'react';
import { useGetUser } from '@/hooks/useGetUsers';
import userState from '@/store/user';
import { useSetRecoilState } from 'recoil';
export default function User() {
const { isLoading, isError, error, data } = useGetUser(1);
const [warning, setWarning] = useState<string>('');
const setUser = useSetRecoilState(userState);
useEffect(() => {
if (data != null) {
setUser(data);
}
if (isError) {
error?.message === '404' && setWarning('404: Cannot request');
}
}, [isError, data]);
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div className="App">
<p>{warning !== '' && warning}</p>
<p>{data?.name}</p>
</div>
);
}
configuration
each page is included in src/pages
src/App.tsx
import { RouteObject, useRoutes } from 'react-router-dom';
import Layout from '@/components/common/Layout';
import User from '@/pages/User';
import Home from '@/pages/Home';
import NotFound from '@/pages/NotFound';
const routes: RouteObject[] = [
{
path: '/',
element: <Layout />,
children: [
{ index: true, element: <Home></Home> },
{ path: '/user', element: <User></User> },
{ path: '*', element: <NotFound></NotFound> },
],
},
];
function App() {
const element = useRoutes(routes);
return element;
}
export default App;