This commit is contained in:
Luiz Silva 2026-10-10 12:15:08 -03:00
parent 32df6cab5f
commit 742d4e10db
8 changed files with 414 additions and 1562 deletions

236
tests/respostas.test.ts Normal file
View file

@ -0,0 +1,236 @@
import { describe, expect, it } from "bun:test"
import z from "zod"
import {
codigosResposta,
respostaComuns,
zCodigosRespostaErro,
zResposta,
zRespostaErro,
zRespostaSucesso,
zRespostas,
type tipoZResposta,
} from "../src/respostas"
describe("zRespostas - Sucesso", () => {
it("deve validar resposta de sucesso com schema específico (string)", () => {
const schema = zRespostas(z.string())
const res = respostaComuns.valor("Operação realizada com sucesso")
const parsed = schema.parse(res)
expect(parsed.cod).toBe(codigosResposta.sucesso)
expect(parsed.eCerto).toBe(true)
expect(parsed.eErro).toBe(false)
if (parsed.eCerto) {
expect(parsed.valor).toBe("Operação realizada com sucesso")
}
})
it("deve validar resposta de sucesso com schema de objeto complexo", () => {
const zUsuario = z.object({
id: z.number(),
nome: z.string(),
ativo: z.boolean(),
})
const schema = zRespostas(zUsuario)
const res = respostaComuns.valor({ id: 10, nome: "Maria", ativo: true }, [
"detalhe 1",
])
const parsed = schema.parse(res)
expect(parsed.eCerto).toBe(true)
if (parsed.eCerto) {
expect(parsed.valor.id).toBe(10)
expect(parsed.valor.nome).toBe("Maria")
expect(parsed.valor.ativo).toBe(true)
expect(parsed.detalhes).toEqual(["detalhe 1"])
}
})
it("deve aceitar qualquer valor quando invocado sem parâmetros (default z.any())", () => {
const schema = zRespostas()
const resString = respostaComuns.valor("qualquer texto")
const resNumero = respostaComuns.valor(12345)
const resBool = respostaComuns.valorTrue()
expect(schema.parse(resString).eCerto).toBe(true)
expect(schema.parse(resNumero).eCerto).toBe(true)
expect(schema.parse(resBool).eCerto).toBe(true)
})
it("deve funcionar com zRespostaSucesso isoladamente", () => {
const schema = zRespostaSucesso(z.number())
const res = respostaComuns.valor(99)
const parsed = schema.parse(res)
expect(parsed.cod).toBe(200)
expect(parsed.valor).toBe(99)
})
it("deve rejeitar sucesso quando o tipo de valor for incompatível", () => {
const schema = zRespostas(z.string())
const resInvalido = {
cod: codigosResposta.sucesso,
eCerto: true,
eErro: false,
valor: 12345, // número em vez de string
}
expect(() => schema.parse(resInvalido)).toThrow()
})
it("deve aceitar detalhes nullish (null, undefined ou ausente)", () => {
const schema = zRespostas(z.string())
const resComNull = {
cod: codigosResposta.sucesso,
eCerto: true,
eErro: false,
valor: "ok",
detalhes: null,
}
const resSemDetalhes = {
cod: codigosResposta.sucesso,
eCerto: true,
eErro: false,
valor: "ok",
}
expect(schema.parse(resComNull).detalhes).toBeNull()
expect(schema.parse(resSemDetalhes).detalhes).toBeUndefined()
})
})
describe("zRespostas - Erro", () => {
const schema = zRespostas(z.string())
it("deve validar erroConhecido (400)", () => {
const res = respostaComuns.erro("Dados inválidos", ["campo X obrigatório"])
const parsed = schema.parse(res)
expect(parsed.cod).toBe(codigosResposta.erroConhecido)
expect(parsed.eCerto).toBe(false)
expect(parsed.eErro).toBe(true)
if (parsed.eErro) {
expect(parsed.mensagem).toBe("Dados inválidos")
expect(parsed.detalhes).toEqual(["campo X obrigatório"])
}
})
it("deve validar erroPermissao (401)", () => {
const res = respostaComuns.erroPermissao("Acesso negado")
const parsed = schema.parse(res)
expect(parsed.cod).toBe(codigosResposta.erroPermissao)
expect(parsed.eErro).toBe(true)
if (parsed.eErro) {
expect(parsed.mensagem).toBe("Acesso negado")
}
})
it("deve validar erroNaoEncontrado (404)", () => {
const res = respostaComuns.naoEncontrado("Usuário não encontrado")
const parsed = schema.parse(res)
expect(parsed.cod).toBe(codigosResposta.erroNaoEncontrado)
expect(parsed.eErro).toBe(true)
if (parsed.eErro) {
expect(parsed.mensagem).toBe("Usuário não encontrado")
}
})
it("deve validar erroDesconhecido (500)", () => {
const res = respostaComuns.erroInterno({
erro: new Error("Falha no banco"),
local: "usuario.service",
mensagem: "Erro inesperado",
})
const parsed = schema.parse(res)
expect(parsed.cod).toBe(codigosResposta.erroDesconhecido)
expect(parsed.eErro).toBe(true)
if (parsed.eErro) {
expect(parsed.mensagem).toBe("Erro inesperado")
}
})
it("deve validar tempoEsgotado (504)", () => {
const res = respostaComuns.tempoEsgotado("Gateway Timeout")
const parsed = schema.parse(res)
expect(parsed.cod).toBe(codigosResposta.tempoEsgotado)
expect(parsed.eErro).toBe(true)
if (parsed.eErro) {
expect(parsed.mensagem).toBe("Gateway Timeout")
}
})
it("deve funcionar com zRespostaErro isoladamente", () => {
const res = respostaComuns.erro("Falha simples")
const parsed = zRespostaErro.parse(res)
expect(parsed.cod).toBe(400)
expect(parsed.mensagem).toBe("Falha simples")
})
it("deve rejeitar códigos de erro não pertencentes a codigosResposta", () => {
const resInvalido = {
cod: 403, // 403 não é código do enum codigosResposta (p-respostas usa 401)
eCerto: false,
eErro: true,
mensagem: "Proibido",
}
expect(() => schema.parse(resInvalido)).toThrow()
})
it("deve rejeitar erro sem mensagem", () => {
const resSemMsg = {
cod: codigosResposta.erroConhecido,
eCerto: false,
eErro: true,
}
expect(() => schema.parse(resSemMsg)).toThrow()
})
})
describe("zRespostas - Consistência e Aliases", () => {
it("zResposta deve ser idêntico a zRespostas", () => {
expect(zResposta).toBe(zRespostas)
})
it("zCodigosRespostaErro deve aceitar apenas os 5 códigos de erro", () => {
expect(zCodigosRespostaErro.parse(400)).toBe(400)
expect(zCodigosRespostaErro.parse(401)).toBe(401)
expect(zCodigosRespostaErro.parse(404)).toBe(404)
expect(zCodigosRespostaErro.parse(500)).toBe(500)
expect(zCodigosRespostaErro.parse(504)).toBe(504)
expect(() => zCodigosRespostaErro.parse(200)).toThrow()
expect(() => zCodigosRespostaErro.parse(403)).toThrow()
expect(() => zCodigosRespostaErro.parse(502)).toThrow()
})
it("deve permitir narrowing estático em TypeScript", () => {
const schema = zRespostas(z.string())
const res: tipoZResposta<z.ZodString> = schema.parse(
respostaComuns.valor("dados"),
)
if (res.eCerto) {
const v: string = res.valor
expect(v).toBe("dados")
} else {
const m: string = res.mensagem
expect(m).toBeDefined()
}
if (res.cod === codigosResposta.sucesso) {
const v: string = res.valor
expect(v).toBe("dados")
} else {
const m: string = res.mensagem
expect(m).toBeDefined()
}
})
})