feat(i18n): localize asset validation messages
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
import { localizeAssetFieldErrors } from "@/actions/asset.messages"
|
||||
|
||||
const actionCopy = {
|
||||
createSuccess: "Activo creado correctamente",
|
||||
createFailure: "Error al crear el activo",
|
||||
updateSuccess: "Activo actualizado correctamente",
|
||||
updateFailure: "Error al actualizar el activo",
|
||||
duplicateSerialNumber: "El número de serie ya existe",
|
||||
notFound: "Activo no encontrado",
|
||||
itemNotFound: "Artículo no encontrado",
|
||||
assignmentAlreadyReturned: "La asignación ya fue devuelta",
|
||||
previousItemNotFound: "Artículo anterior no encontrado",
|
||||
insufficientStock: "El artículo no tiene stock suficiente",
|
||||
recipientRequired: "El destinatario es obligatorio",
|
||||
invalidStatus: "Estado inválido",
|
||||
genericFailure: "Error al procesar el activo",
|
||||
}
|
||||
|
||||
describe("asset action message localization", () => {
|
||||
it("localizes known asset field errors", () => {
|
||||
expect(
|
||||
localizeAssetFieldErrors(
|
||||
{
|
||||
itemId: ["Item not found"],
|
||||
id: ["Asset not found", "Assignment already returned"],
|
||||
serialNumber: ["This serial number already exists"],
|
||||
stock: ["Item does not have enough stock"],
|
||||
previousItem: ["Previous item not found for available asset"],
|
||||
},
|
||||
actionCopy,
|
||||
),
|
||||
).toEqual({
|
||||
itemId: [actionCopy.itemNotFound],
|
||||
id: [actionCopy.notFound, actionCopy.assignmentAlreadyReturned],
|
||||
serialNumber: [actionCopy.duplicateSerialNumber],
|
||||
stock: [actionCopy.insufficientStock],
|
||||
previousItem: [actionCopy.previousItemNotFound],
|
||||
})
|
||||
})
|
||||
|
||||
it("keeps unknown messages unchanged", () => {
|
||||
expect(
|
||||
localizeAssetFieldErrors(
|
||||
{ serialNumber: ["Unexpected asset issue"] },
|
||||
actionCopy,
|
||||
),
|
||||
).toEqual({ serialNumber: ["Unexpected asset issue"] })
|
||||
})
|
||||
})
|
||||
@@ -458,6 +458,29 @@ describe("i18n dictionaries", () => {
|
||||
fallback: {
|
||||
unknownStatus: "Unknown status",
|
||||
},
|
||||
actions: {
|
||||
createSuccess: "Asset created successfully",
|
||||
createFailure: "Error creating asset",
|
||||
updateSuccess: "Asset updated successfully",
|
||||
updateFailure: "Error updating asset",
|
||||
duplicateSerialNumber: "This serial number already exists",
|
||||
notFound: "Asset not found",
|
||||
itemNotFound: "Item not found",
|
||||
assignmentAlreadyReturned: "Assignment already returned",
|
||||
previousItemNotFound: "Previous item not found for available asset",
|
||||
insufficientStock: "Item does not have enough stock",
|
||||
recipientRequired: "Recipient is required",
|
||||
invalidStatus: "Invalid status",
|
||||
genericFailure: "Error processing asset",
|
||||
},
|
||||
schema: {
|
||||
itemRequired: "Item is required",
|
||||
serialNumberRequired: "Serial number is required",
|
||||
idRequired: "ID is required",
|
||||
statusRequired: "Status is required",
|
||||
invalidCreateStatus: "Status must be Available or Assigned",
|
||||
invalidUpdateStatus: "Invalid status",
|
||||
},
|
||||
})
|
||||
|
||||
expect(getDictionary("es").inventory.assets).toEqual({
|
||||
@@ -509,6 +532,30 @@ describe("i18n dictionaries", () => {
|
||||
fallback: {
|
||||
unknownStatus: "Estado desconocido",
|
||||
},
|
||||
actions: {
|
||||
createSuccess: "Activo creado correctamente",
|
||||
createFailure: "Error al crear el activo",
|
||||
updateSuccess: "Activo actualizado correctamente",
|
||||
updateFailure: "Error al actualizar el activo",
|
||||
duplicateSerialNumber: "El número de serie ya existe",
|
||||
notFound: "Activo no encontrado",
|
||||
itemNotFound: "Artículo no encontrado",
|
||||
assignmentAlreadyReturned: "La asignación ya fue devuelta",
|
||||
previousItemNotFound:
|
||||
"Artículo anterior no encontrado para el activo disponible",
|
||||
insufficientStock: "El artículo no tiene stock suficiente",
|
||||
recipientRequired: "El destinatario es obligatorio",
|
||||
invalidStatus: "Estado inválido",
|
||||
genericFailure: "Error al procesar el activo",
|
||||
},
|
||||
schema: {
|
||||
itemRequired: "El artículo es obligatorio",
|
||||
serialNumberRequired: "El número de serie es obligatorio",
|
||||
idRequired: "El activo es obligatorio",
|
||||
statusRequired: "El estado es obligatorio",
|
||||
invalidCreateStatus: "El estado inicial debe ser Disponible o Asignado",
|
||||
invalidUpdateStatus: "Estado inválido",
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
import {
|
||||
buildCreateAssetSchema,
|
||||
buildUpdateAssetSchema,
|
||||
} from "@/schemas/asset.schema"
|
||||
|
||||
const schemaCopy = {
|
||||
itemRequired: "El artículo es obligatorio",
|
||||
serialNumberRequired: "El número de serie es obligatorio",
|
||||
idRequired: "El activo es obligatorio",
|
||||
statusRequired: "El estado es obligatorio",
|
||||
invalidCreateStatus: "El estado inicial no es válido",
|
||||
invalidUpdateStatus: "El estado no es válido",
|
||||
}
|
||||
|
||||
describe("asset schema localization", () => {
|
||||
it("uses localized create validation messages", () => {
|
||||
const result = buildCreateAssetSchema(schemaCopy).safeParse({
|
||||
itemId: "",
|
||||
serialNumber: "",
|
||||
status: "BROKEN",
|
||||
})
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
if (!result.success) {
|
||||
const errors = result.error.flatten().fieldErrors
|
||||
|
||||
expect(errors.itemId).toContain(schemaCopy.itemRequired)
|
||||
expect(errors.serialNumber).toContain(schemaCopy.serialNumberRequired)
|
||||
expect(errors.status).toContain(schemaCopy.invalidCreateStatus)
|
||||
}
|
||||
})
|
||||
|
||||
it("uses localized update identifier and status validation messages", () => {
|
||||
const result = buildUpdateAssetSchema(schemaCopy).safeParse({
|
||||
id: "",
|
||||
itemId: "item-1",
|
||||
serialNumber: "SERIAL-1",
|
||||
status: "UNSUPPORTED",
|
||||
})
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
if (!result.success) {
|
||||
const errors = result.error.flatten().fieldErrors
|
||||
|
||||
expect(errors.id).toContain(schemaCopy.idRequired)
|
||||
expect(errors.status).toContain(schemaCopy.invalidUpdateStatus)
|
||||
}
|
||||
})
|
||||
|
||||
it("preserves raw status values for accepted create and update payloads", () => {
|
||||
const createResult = buildCreateAssetSchema(schemaCopy).safeParse({
|
||||
itemId: "item-1",
|
||||
serialNumber: "SERIAL-1",
|
||||
status: "ASSIGNED",
|
||||
recipientId: "recipient-1",
|
||||
})
|
||||
|
||||
expect(createResult.success).toBe(true)
|
||||
if (createResult.success) {
|
||||
expect(createResult.data.status).toBe("ASSIGNED")
|
||||
}
|
||||
|
||||
const updateResult = buildUpdateAssetSchema(schemaCopy).safeParse({
|
||||
id: "asset-1",
|
||||
itemId: "item-1",
|
||||
serialNumber: "SERIAL-1",
|
||||
status: "DISPOSED",
|
||||
})
|
||||
|
||||
expect(updateResult.success).toBe(true)
|
||||
if (updateResult.success) {
|
||||
expect(updateResult.data.status).toBe("DISPOSED")
|
||||
}
|
||||
})
|
||||
|
||||
it("keeps optional asset fields optional", () => {
|
||||
const result = buildCreateAssetSchema(schemaCopy).safeParse({
|
||||
itemId: "item-1",
|
||||
serialNumber: "SERIAL-1",
|
||||
status: "AVAILABLE",
|
||||
})
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user