Files
homebox/frontend/lib/api/__test__/user/templates.test.ts
2025-12-28 23:10:09 +00:00

298 lines
12 KiB
TypeScript

import { describe, expect, test } from "vitest";
import type { ItemTemplateOut } from "../../types/data-contracts";
import type { UserClient } from "../../user";
import { factories } from "../factories";
import { sharedUserClient } from "../test-utils";
describe("templates lifecycle (create, update, delete)", () => {
/**
* useTemplate sets up a template resource for testing, and returns a function
* that can be used to delete the template from the backend server.
*/
async function useTemplate(api: UserClient): Promise<[ItemTemplateOut, () => Promise<void>]> {
const { response, data } = await api.templates.create(factories.template());
expect(response.status).toBe(201);
const cleanup = async () => {
const { response } = await api.templates.delete(data.id);
expect(response.status).toBe(204);
};
return [data, cleanup];
}
test("user should be able to create a template", async () => {
const api = await sharedUserClient();
const templateData = factories.template();
const { response, data } = await api.templates.create(templateData);
expect(response.status).toBe(201);
expect(data.id).toBeTruthy();
// Ensure we can get the template
const { response: getResponse, data: getData } = await api.templates.get(data.id);
expect(getResponse.status).toBe(200);
expect(getData.id).toBe(data.id);
expect(getData.name).toBe(templateData.name);
expect(getData.description).toBe(templateData.description);
expect(getData.defaultQuantity).toBe(templateData.defaultQuantity);
expect(getData.defaultInsured).toBe(templateData.defaultInsured);
expect(getData.defaultName).toBe(templateData.defaultName);
expect(getData.defaultDescription).toBe(templateData.defaultDescription);
expect(getData.defaultManufacturer).toBe(templateData.defaultManufacturer);
expect(getData.defaultModelNumber).toBe(templateData.defaultModelNumber);
// Cleanup
const { response: deleteResponse } = await api.templates.delete(data.id);
expect(deleteResponse.status).toBe(204);
});
test("user should be able to get all templates", async () => {
const api = await sharedUserClient();
const [_, cleanup] = await useTemplate(api);
const { response, data } = await api.templates.getAll();
expect(response.status).toBe(200);
expect(Array.isArray(data)).toBe(true);
expect(data.length).toBeGreaterThanOrEqual(1);
await cleanup();
});
test("user should be able to update a template", async () => {
const api = await sharedUserClient();
const [template, cleanup] = await useTemplate(api);
const updateData = {
id: template.id,
name: "updated-template-name",
description: "updated-description",
notes: "updated-notes",
defaultQuantity: 5,
defaultInsured: true,
defaultName: "Updated Default Name",
defaultDescription: "Updated Default Description",
defaultManufacturer: "Updated Manufacturer",
defaultModelNumber: "MODEL-999",
defaultLifetimeWarranty: true,
defaultWarrantyDetails: "Lifetime coverage",
defaultLocationId: null,
defaultTagIds: null,
includeWarrantyFields: true,
includePurchaseFields: true,
includeSoldFields: false,
fields: [],
};
const { response, data } = await api.templates.update(template.id, updateData);
expect(response.status).toBe(200);
expect(data.id).toBe(template.id);
// Ensure the template was updated
const { response: getResponse, data: getData } = await api.templates.get(template.id);
expect(getResponse.status).toBe(200);
expect(getData.name).toBe(updateData.name);
expect(getData.description).toBe(updateData.description);
expect(getData.notes).toBe(updateData.notes);
expect(getData.defaultQuantity).toBe(updateData.defaultQuantity);
expect(getData.defaultInsured).toBe(updateData.defaultInsured);
expect(getData.defaultName).toBe(updateData.defaultName);
expect(getData.defaultDescription).toBe(updateData.defaultDescription);
expect(getData.defaultManufacturer).toBe(updateData.defaultManufacturer);
expect(getData.defaultModelNumber).toBe(updateData.defaultModelNumber);
expect(getData.defaultLifetimeWarranty).toBe(updateData.defaultLifetimeWarranty);
expect(getData.includeWarrantyFields).toBe(updateData.includeWarrantyFields);
expect(getData.includePurchaseFields).toBe(updateData.includePurchaseFields);
await cleanup();
});
test("user should be able to delete a template", async () => {
const api = await sharedUserClient();
const [template, _] = await useTemplate(api);
const { response } = await api.templates.delete(template.id);
expect(response.status).toBe(204);
// Ensure we can't get the template
const { response: getResponse } = await api.templates.get(template.id);
expect(getResponse.status).toBe(404);
});
test("user should be able to create a template with custom fields", async () => {
const api = await sharedUserClient();
const NIL_UUID = "00000000-0000-0000-0000-000000000000";
const templateData = factories.template();
templateData.fields = [
{ id: NIL_UUID, name: "Custom Field 1", type: "text", textValue: "Value 1" },
{ id: NIL_UUID, name: "Custom Field 2", type: "text", textValue: "Value 2" },
];
const { response, data } = await api.templates.create(templateData);
expect(response.status).toBe(201);
expect(data.fields).toHaveLength(2);
expect(data.fields![0]!.name).toBe("Custom Field 1");
expect(data.fields![0]!.textValue).toBe("Value 1");
expect(data.fields![1]!.name).toBe("Custom Field 2");
expect(data.fields![1]!.textValue).toBe("Value 2");
// Cleanup
const { response: deleteResponse } = await api.templates.delete(data.id);
expect(deleteResponse.status).toBe(204);
});
test("user should be able to update template custom fields", async () => {
const api = await sharedUserClient();
const NIL_UUID = "00000000-0000-0000-0000-000000000000";
// Create template with a field
const templateData = factories.template();
templateData.fields = [{ id: NIL_UUID, name: "Original Field", type: "text", textValue: "Original Value" }];
const { response: createResponse, data: createdTemplate } = await api.templates.create(templateData);
expect(createResponse.status).toBe(201);
expect(createdTemplate.fields).toHaveLength(1);
// Update with modified and new fields
const updateData = {
id: createdTemplate.id,
name: createdTemplate.name,
description: createdTemplate.description,
notes: createdTemplate.notes,
defaultQuantity: createdTemplate.defaultQuantity,
defaultInsured: createdTemplate.defaultInsured,
defaultName: createdTemplate.defaultName,
defaultDescription: createdTemplate.defaultDescription,
defaultManufacturer: createdTemplate.defaultManufacturer,
defaultModelNumber: createdTemplate.defaultModelNumber,
defaultLifetimeWarranty: createdTemplate.defaultLifetimeWarranty,
defaultWarrantyDetails: createdTemplate.defaultWarrantyDetails,
defaultLocationId: null,
defaultTagIds: null,
includeWarrantyFields: createdTemplate.includeWarrantyFields,
includePurchaseFields: createdTemplate.includePurchaseFields,
includeSoldFields: createdTemplate.includeSoldFields,
fields: [
{ id: createdTemplate.fields![0]!.id, name: "Updated Field", type: "text", textValue: "Updated Value" },
{ id: NIL_UUID, name: "New Field", type: "text", textValue: "New Value" },
],
};
const { response: updateResponse, data: updatedTemplate } = await api.templates.update(
createdTemplate.id,
updateData
);
expect(updateResponse.status).toBe(200);
expect(updatedTemplate.fields).toHaveLength(2);
// Cleanup
const { response: deleteResponse } = await api.templates.delete(createdTemplate.id);
expect(deleteResponse.status).toBe(204);
});
});
describe("templates with location and tags", () => {
test("user should be able to create a template with a default location", async () => {
const api = await sharedUserClient();
// First create a location
const locationData = factories.location();
const { response: locResponse, data: location } = await api.locations.create(locationData);
expect(locResponse.status).toBe(201);
// Create template with the location
const templateData = factories.template();
templateData.defaultLocationId = location.id;
const { response, data } = await api.templates.create(templateData);
expect(response.status).toBe(201);
expect(data.defaultLocation).toBeTruthy();
expect(data.defaultLocation?.id).toBe(location.id);
expect(data.defaultLocation?.name).toBe(location.name);
// Cleanup
await api.templates.delete(data.id);
await api.locations.delete(location.id);
});
test("user should be able to create a template with default tags", async () => {
const api = await sharedUserClient();
// First create some tags
const { response: tag1Response, data: tag1 } = await api.tags.create(factories.tag());
expect(tag1Response.status).toBe(201);
const { response: tag2Response, data: tag2 } = await api.tags.create(factories.tag());
expect(tag2Response.status).toBe(201);
// Create template with tags
const templateData = factories.template();
templateData.defaultTagIds = [tag1.id, tag2.id];
const { response, data } = await api.templates.create(templateData);
expect(response.status).toBe(201);
expect(data.defaultTags).toHaveLength(2);
expect(data.defaultTags.map(l => l.id)).toContain(tag1.id);
expect(data.defaultTags.map(l => l.id)).toContain(tag2.id);
// Cleanup
await api.templates.delete(data.id);
await api.tags.delete(tag1.id);
await api.tags.delete(tag2.id);
});
test("user should be able to update template to remove location", async () => {
const api = await sharedUserClient();
// Create a location
const { response: locResponse, data: location } = await api.locations.create(factories.location());
expect(locResponse.status).toBe(201);
// Create template with location
const templateData = factories.template();
templateData.defaultLocationId = location.id;
const { response: createResponse, data: template } = await api.templates.create(templateData);
expect(createResponse.status).toBe(201);
expect(template.defaultLocation).toBeTruthy();
// Update to remove location
const updateData = {
id: template.id,
name: template.name,
description: template.description,
notes: template.notes,
defaultQuantity: template.defaultQuantity,
defaultInsured: template.defaultInsured,
defaultName: template.defaultName,
defaultDescription: template.defaultDescription,
defaultManufacturer: template.defaultManufacturer,
defaultModelNumber: template.defaultModelNumber,
defaultLifetimeWarranty: template.defaultLifetimeWarranty,
defaultWarrantyDetails: template.defaultWarrantyDetails,
defaultLocationId: null,
defaultTagIds: null,
includeWarrantyFields: template.includeWarrantyFields,
includePurchaseFields: template.includePurchaseFields,
includeSoldFields: template.includeSoldFields,
fields: [],
};
const { response: updateResponse, data: updated } = await api.templates.update(template.id, updateData);
expect(updateResponse.status).toBe(200);
expect(updated.defaultLocation).toBeNull();
// Cleanup
await api.templates.delete(template.id);
await api.locations.delete(location.id);
});
});