test(frontend): add jest setup and integration tests for API client

This commit is contained in:
Tiago Yamamoto 2025-12-15 10:26:12 -03:00
parent c9747d3596
commit d3d6ae2991
4 changed files with 137 additions and 1 deletions

18
frontend/jest.config.js Normal file
View file

@ -0,0 +1,18 @@
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 = {
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testEnvironment: 'jest-environment-jsdom',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
}
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig)

4
frontend/jest.setup.js Normal file
View file

@ -0,0 +1,4 @@
import '@testing-library/jest-dom'
// Mock fetch globally
global.fetch = jest.fn()

View file

@ -6,7 +6,8 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "next lint",
"test": "jest"
},
"dependencies": {
"@hookform/resolvers": "^3.10.0",
@ -63,12 +64,18 @@
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.9",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
"@types/jest": "^30.0.0",
"@types/node": "^22",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^9.39.1",
"jest": "^30.2.0",
"jest-environment-jsdom": "^30.2.0",
"postcss": "^8.5",
"tailwindcss": "^4.1.9",
"ts-node": "^10.9.2",
"tw-animate-css": "1.3.3",
"typescript": "^5"
}

View file

@ -0,0 +1,107 @@
let jobsApi: any
let companiesApi: any
let usersApi: any
// Mock environment variable
const ORIGINAL_ENV = process.env
beforeEach(() => {
jest.resetModules()
process.env = { ...process.env, NEXT_PUBLIC_API_URL: 'http://test-api.com/api/v1' }
// Re-require modules to pick up new env vars
const api = require('../api')
jobsApi = api.jobsApi
companiesApi = api.companiesApi
usersApi = api.usersApi
global.fetch = jest.fn()
})
afterEach(() => {
jest.clearAllMocks()
})
afterAll(() => {
process.env = ORIGINAL_ENV
})
describe('API Client', () => {
describe('jobsApi', () => {
it('should fetch jobs with correct parameters', async () => {
const mockJobs = {
data: [{ id: 1, title: 'Dev Job' }],
pagination: { total: 1 }
}
; (global.fetch as jest.Mock).mockResolvedValueOnce({
ok: true,
json: async () => mockJobs,
})
const response = await jobsApi.list({ page: 1, limit: 10, companyId: 5 })
expect(global.fetch).toHaveBeenCalledWith(
'http://test-api.com/api/v1/jobs?page=1&limit=10&companyId=5',
expect.objectContaining({
headers: expect.objectContaining({
'Content-Type': 'application/json'
})
})
)
expect(response).toEqual(mockJobs)
})
it('should handle API errors correctly', async () => {
; (global.fetch as jest.Mock).mockResolvedValueOnce({
ok: false,
status: 404,
text: async () => 'Not Found',
})
await expect(jobsApi.list()).rejects.toThrow('Not Found')
})
})
describe('companiesApi', () => {
it('should create company correctly', async () => {
const mockCompany = { id: '123', name: 'Test Corp' }
; (global.fetch as jest.Mock).mockResolvedValueOnce({
ok: true,
json: async () => mockCompany,
})
const newCompany = { name: 'Test Corp', slug: 'test-corp' }
await companiesApi.create(newCompany)
expect(global.fetch).toHaveBeenCalledWith(
'http://test-api.com/api/v1/companies',
expect.objectContaining({
method: 'POST',
body: JSON.stringify(newCompany)
})
)
})
})
describe('URL Construction', () => {
it('should handle double /api/v1 correctly', async () => {
; (global.fetch as jest.Mock).mockResolvedValueOnce({
ok: true,
json: async () => ([]),
})
// We need to import the raw apiRequest function to test this properly,
// but since it's not exported, we simulate via an exported function
await usersApi.list()
// The apiRequest logic handles URL cleaning.
// Expected: base http://test-api.com/api/v1 + endpoint /api/v1/users -> http://test-api.com/api/v1/users
// NOT http://test-api.com/api/v1/api/v1/users
expect(global.fetch).toHaveBeenCalledWith(
'http://test-api.com/api/v1/users',
expect.any(Object)
)
})
})
})