Add base tests

This commit is contained in:
MartinBraquet
2025-08-04 10:26:19 +02:00
parent c284983b4b
commit ed515fa3fc
11 changed files with 4041 additions and 20 deletions

View File

@@ -1,4 +1,4 @@
name: Check Next.js
name: CI
on:
push:
@@ -9,8 +9,8 @@ on:
- main
jobs:
build:
name: Build
ci:
name: All
runs-on: ubuntu-latest
steps:
@@ -25,7 +25,23 @@ jobs:
- name: Install dependencies
run: npm ci
- name: Build the app
- name: Type check
run: npx tsc --noEmit
- name: Lint
run: npm run lint
- name: Run tests
run: npm run test
- name: Build app
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: npm run build
# Optional: Playwright E2E tests
- name: Install Playwright deps
run: npx playwright install --with-deps
- name: Run E2E tests
run: npx playwright test

View File

@@ -80,13 +80,16 @@ npx prisma migrate dev --name init
```
Note that your local database will be made of synthetic data, not real users. This is fine for development and testing.
Start the development server:
Make sure the tests pass:
```bash
npm run test
```
Start the development server:
```bash
npm run dev
```
Once the server is running, visit http://localhost:3000 to start using the app. Now you can start contributing by
making changes and submitting pull requests!
Once the server is running, visit http://localhost:3000 to start using the app. Now you can start contributing by making changes and submitting pull requests!
See [development.md](docs/development.md) for additional instructions, such as adding new profile features.

2
__mocks__/fileMock.js Normal file
View File

@@ -0,0 +1,2 @@
// Mock for file imports (images, etc.)
module.exports = 'test-file-stub';

2
__mocks__/styleMock.js Normal file
View File

@@ -0,0 +1,2 @@
// Mock for CSS imports
module.exports = {};

47
jest.config.js Normal file
View File

@@ -0,0 +1,47 @@
const nextJest = require('next/jest');
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
});
// Add any custom config to be passed to Jest
const customJestConfig = {
// Add more setup options before each test is run
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
moduleNameMapper: {
// Handle module aliases (this will be automatically configured for you soon)
'^@/components/(.*)$': '<rootDir>/components/$1',
'^@/app/(.*)$': '<rootDir>/app/$1',
'^@/lib/(.*)$': '<rootDir>/lib/$1',
'^@/types/(.*)$': '<rootDir>/types/$1',
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
'^.+\\.(jpg|jpeg|png|gif|webp|avif|svg)$': '<rootDir>/__mocks__/fileMock.js',
},
// Don't ignore node_modules by default
transformIgnorePatterns: [
'/node_modules/(?!(@upstash|@radix-ui|@hookform|@auth|@aws-sdk|@emotion|@mui|@prisma|@radix-ui|@react-email|@supabase|@types|@upstash|next-auth|react-markdown|rehype-raw|remark-gfm|uuid|react-syntax-highlighter)/)',
],
// Add more configuration options as needed
// transform: {
// // Use babel-jest to transpile tests with the next/babel preset
// // https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
// '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
// },
// testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
// testEnvironment: 'jsdom',
// transform: {
// // Use babel-jest to transpile tests with the next/babel preset
// // https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
// '^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
// },
// transformIgnorePatterns: [
// '/node_modules/(?!(react-syntax-highlighter|@heroicons|@aws-sdk|@radix-ui|@emotion|@mui|@prisma|@radix-ui|@react-email|@supabase|@types|@upstash|next-auth|react-markdown|rehype-raw|remark-gfm|uuid)/)',
// ],
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);

14
jest.setup.d.ts vendored Normal file
View File

@@ -0,0 +1,14 @@
// This file extends the global Jest namespace with custom matchers from @testing-library/jest-dom
import '@testing-library/jest-dom';
declare global {
namespace jest {
interface Matchers<R> {
toBeInTheDocument(): R;
toHaveClass(...classes: string[]): R;
// Add other custom matchers you use from @testing-library/jest-dom
}
}
}
export {};

55
jest.setup.js Normal file
View File

@@ -0,0 +1,55 @@
// Learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
// Mock next/navigation
jest.mock('next/navigation', () => ({
useRouter() {
return {
prefetch: () => null,
push: jest.fn(),
};
},
useSearchParams() {
return {
get: jest.fn(),
};
},
usePathname() {
return '';
},
}));
// Mock next-auth
jest.mock('next-auth/react', () => ({
useSession: jest.fn(() => ({
data: null,
status: 'unauthenticated',
})),
signIn: jest.fn(),
signOut: jest.fn(),
getSession: jest.fn(),
}));
// Mock next/head
jest.mock('next/head', () => {
return {
__esModule: true,
default: ({
children,
} /*: {
children: Array<React.ReactElement>;
}*/) => <>{children}</>,
};
});
// Mock next-themes
jest.mock('next-themes', () => ({
useTheme: () => ({
setTheme: jest.fn(),
theme: 'light',
systemTheme: 'light',
}),
ThemeProvider: ({ children }) => (
<div>{children}</div>
),
}));

View File

@@ -4,8 +4,14 @@ import React from "react";
export default function LoadingSpinner() {
return (
<div className="flex items-center justify-center min-h-screen ">
<div className="w-12 h-12 border-4 border-gray-300 border-t-gray-800 rounded-full animate-spin" />
<div
data-testid="spinner-container"
className="flex items-center justify-center min-h-screen"
>
<div
data-testid="spinner"
className="w-12 h-12 border-4 border-gray-300 border-t-gray-800 rounded-full animate-spin"
/>
</div>
);
}

View File

@@ -0,0 +1,17 @@
import { render, screen } from '@testing-library/react';
import LoadingSpinner from '../LoadingSpinner';
describe('LoadingSpinner', () => {
it('renders a loading spinner', () => {
render(<LoadingSpinner />);
// Check if the spinner container is rendered with the correct classes
const spinnerContainer = screen.getByTestId('spinner-container');
expect(spinnerContainer).toBeInTheDocument();
expect(spinnerContainer).toHaveClass('flex', 'items-center', 'justify-center', 'min-h-screen');
// Check if the spinner has the correct classes
const spinner = screen.getByTestId('spinner');
expect(spinner).toHaveClass('w-12', 'h-12', 'border-4', 'border-gray-300', 'border-t-gray-800', 'rounded-full', 'animate-spin');
});
});

3868
package-lock.json generated
View File

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,11 @@
"postinstall": "npx prisma generate --no-engine",
"build": "npx prisma migrate deploy && next build",
"start": "next start",
"lint": "next lint"
"lint": "next lint",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"test:update": "jest --updateSnapshot"
},
"dependencies": {
"@auth/prisma-adapter": "^2.10.0",
@@ -48,11 +52,18 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@testing-library/jest-dom": "^6.6.4",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"@types/jest": "^30.0.0",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/testing-library__jest-dom": "^6.0.0",
"eslint": "^9",
"eslint-config-next": "15.1.7",
"jest": "^30.0.5",
"jest-environment-jsdom": "^30.0.5",
"postcss": "^8",
"prisma": "^6.13.0",
"tailwindcss": "^3.4.1",