turbo-monorepo-test/apps/backend/test/demo/person.integration.test.ts

320 lines
7.5 KiB
TypeScript

import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { getConfig } from '@/config/config.js';
import type { Server } from '@/config/types.js';
import type { Person, Pet } from '@/features/demo/demo.db-schema.js';
import { getServer } from '@/server.js';
let server: Server;
beforeAll(async () => {
const config = getConfig();
server = getServer(config);
await server.ready();
});
afterAll(async () => {
await server.close();
});
// Helper to create valid metadata
const createMetadata = () => ({
login_at: new Date().toISOString(),
ip: '192.168.1.1',
agent: 'Mozilla/5.0',
plan: 'premium' as const,
});
describe('Person CRUD', () => {
it('should create a person', async () => {
const response = await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'John',
last_name: 'Doe',
gender: 'man',
metadata: createMetadata(),
},
});
expect(response.statusCode).toBe(201);
const body = response.json();
expect(body.first_name).toBe('John');
expect(body.last_name).toBe('Doe');
expect(body.gender).toBe('man');
expect(body.id).toBeDefined();
expect(body.created_at).toBeDefined();
expect(body.metadata.plan).toBe('premium');
});
it('should get a person by ID', async () => {
// Create a person first
const createResponse = await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'Jane',
last_name: 'Smith',
gender: 'woman',
metadata: createMetadata(),
},
});
const created = createResponse.json();
// Get the person
const response = await server.inject({
method: 'GET',
url: `/demo/persons/${created.id}`,
});
expect(response.statusCode).toBe(200);
const body = response.json();
expect(body).toMatchObject({
id: created.id,
first_name: 'Jane',
last_name: 'Smith',
gender: 'woman',
});
});
it('should return 404 for non-existent person', async () => {
const response = await server.inject({
method: 'GET',
url: '/demo/persons/999999',
});
expect(response.statusCode).toBe(404);
expect(response.json()).toEqual({ message: 'Person not found' });
});
it('should list persons', async () => {
// Create multiple persons
await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'Alice',
gender: 'woman',
metadata: createMetadata(),
},
});
await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'Bob',
gender: 'man',
metadata: createMetadata(),
},
});
const response = await server.inject({
method: 'GET',
url: '/demo/persons',
});
expect(response.statusCode).toBe(200);
const body = response.json();
expect(Array.isArray(body)).toBe(true);
expect(body.length).toBeGreaterThanOrEqual(2);
});
it('should filter persons by first_name', async () => {
// Create persons
await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'Charlie',
gender: 'man',
metadata: createMetadata(),
},
});
const response = await server.inject({
method: 'GET',
url: '/demo/persons?first_name=Charlie',
});
expect(response.statusCode).toBe(200);
const body = response.json();
expect(body.every((p: Person) => p.first_name === 'Charlie')).toBe(true);
});
it('should update a person', async () => {
// Create a person
const createResponse = await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'Original',
gender: 'other',
metadata: createMetadata(),
},
});
const created = createResponse.json();
// Update the person
const updateResponse = await server.inject({
method: 'PATCH',
url: `/demo/persons/${created.id}`,
payload: {
first_name: 'Updated',
},
});
expect(updateResponse.statusCode).toBe(204);
// Verify the update
const getResponse = await server.inject({
method: 'GET',
url: `/demo/persons/${created.id}`,
});
const updated = getResponse.json();
expect(updated.first_name).toBe('Updated');
expect(updated.gender).toBe('other'); // Should remain unchanged
});
it('should return 404 when updating non-existent person', async () => {
const response = await server.inject({
method: 'PATCH',
url: '/demo/persons/999999',
payload: { first_name: 'Does Not Exist' },
});
expect(response.statusCode).toBe(404);
});
it('should delete a person', async () => {
// Create a person
const createResponse = await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'ToDelete',
gender: 'man',
metadata: createMetadata(),
},
});
const created = createResponse.json();
// Delete the person
const deleteResponse = await server.inject({
method: 'DELETE',
url: `/demo/persons/${created.id}`,
});
expect(deleteResponse.statusCode).toBe(204);
// Verify deletion
const getResponse = await server.inject({
method: 'GET',
url: `/demo/persons/${created.id}`,
});
expect(getResponse.statusCode).toBe(404);
});
it('should return 404 when deleting non-existent person', async () => {
const response = await server.inject({
method: 'DELETE',
url: '/demo/persons/999999',
});
expect(response.statusCode).toBe(404);
});
it('should create person with different plans', async () => {
const freePlan = await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'Free',
gender: 'woman',
metadata: { ...createMetadata(), plan: 'free' },
},
});
expect(freePlan.statusCode).toBe(201);
expect(freePlan.json().metadata.plan).toBe('free');
const premiumPlan = await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'Premium',
gender: 'man',
metadata: { ...createMetadata(), plan: 'premium' },
},
});
expect(premiumPlan.statusCode).toBe(201);
expect(premiumPlan.json().metadata.plan).toBe('premium');
});
});
describe('Person with Pets', () => {
it('should get person with their pets', async () => {
// Create a person
const personResponse = await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'PetOwner',
gender: 'other',
metadata: createMetadata(),
},
});
const person = personResponse.json();
// Create pets for this person
await server.inject({
method: 'POST',
url: '/demo/pets',
payload: { name: 'Fluffy', species: 'cat', owner_id: person.id },
});
await server.inject({
method: 'POST',
url: '/demo/pets',
payload: { name: 'Rex', species: 'dog', owner_id: person.id },
});
// Get person with pets
const response = await server.inject({
method: 'GET',
url: `/demo/persons/${person.id}/with-pets`,
});
expect(response.statusCode).toBe(200);
const body = response.json();
expect(body.id).toBe(person.id);
expect(body.first_name).toBe('PetOwner');
expect(Array.isArray(body.pets)).toBe(true);
expect(body.pets.length).toBe(2);
expect(body.pets.map((p: Pet) => p.name).sort()).toEqual(['Fluffy', 'Rex']);
});
it('should return person with empty pets array when they have no pets', async () => {
const personResponse = await server.inject({
method: 'POST',
url: '/demo/persons',
payload: {
first_name: 'NoPets',
gender: 'man',
metadata: createMetadata(),
},
});
const person = personResponse.json();
const response = await server.inject({
method: 'GET',
url: `/demo/persons/${person.id}/with-pets`,
});
expect(response.statusCode).toBe(200);
const body = response.json();
expect(body.pets).toEqual([]);
});
});