320 lines
7.5 KiB
TypeScript
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([]);
|
|
});
|
|
});
|