diff --git a/prisma/migrations/20260418204430_altera_task_limita_title_e_description/migration.sql b/prisma/migrations/20260418204430_altera_task_limita_title_e_description/migration.sql new file mode 100644 index 0000000..72f90b9 --- /dev/null +++ b/prisma/migrations/20260418204430_altera_task_limita_title_e_description/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - You are about to alter the column `title` on the `Task` table. The data in that column could be lost. The data in that column will be cast from `Text` to `VarChar(200)`. + - You are about to alter the column `description` on the `Task` table. The data in that column could be lost. The data in that column will be cast from `Text` to `VarChar(500)`. + +*/ +-- AlterTable +ALTER TABLE "Task" ALTER COLUMN "title" SET DATA TYPE VARCHAR(200), +ALTER COLUMN "description" SET DATA TYPE VARCHAR(500); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 40c71c7..ebb23e0 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -37,8 +37,8 @@ enum TaskStatus { model Task { id String @id @default(uuid()) - title String - description String + title String @db.VarChar(200) + description String @db.VarChar(500) status TaskStatus @default(pending) user_id String created_at DateTime @default(now()) diff --git a/src/zod/taskSchema.ts b/src/zod/taskSchema.ts index 2f74a87..178aa8b 100644 --- a/src/zod/taskSchema.ts +++ b/src/zod/taskSchema.ts @@ -3,8 +3,14 @@ import { pt } from "zod/locales"; z.config(pt()); export const taskSchema = z.object({ - title: z.string("Coluna 'title' é obrigatório!"), - description: z.string("Coluna 'description' é obrigatória!"), + title: z + .string("Coluna 'title' é obrigatório!") + .min(5, "O título deve conter no mínimo 5 caracteres.") + .max(200, "O título deve conter no máximo 200 caracteres."), + description: z + .string("Coluna 'description' é obrigatória!") + .min(10, "A descrição deve conter no mínimo 10 caracteres.") + .max(500, "A descrição deve conter no máximo 500 caracteres."), status: z.enum(["pending", "in_progress", "done"]).optional(), }); diff --git a/tests/controller/task/patch.test.ts b/tests/controller/task/patch.test.ts index dc7f0f3..9c10537 100644 --- a/tests/controller/task/patch.test.ts +++ b/tests/controller/task/patch.test.ts @@ -1,3 +1,4 @@ +import { randomUUID } from "node:crypto"; import { API, createSession, @@ -6,177 +7,274 @@ import { waitForAllServices, } from "$/orchestrator.js"; import { AuthenticatedUser, UserSession } from "~/models/session.js"; +import { Task } from "@/generated/client.js"; beforeAll(async () => { await waitForAllServices(); }); describe("PATCH `/tasks/:id`", () => { - test("Sem usuário logado", async () => { - const fakeTaskId = crypto.randomUUID(); - - const taskForUpdate = { - title: "Atualização da task sem usuário", - description: "O sistema deve bloquear essa ação!", - }; - - const response = await fetch(`${API.task}/${fakeTaskId}`, { - method: "PATCH", - body: JSON.stringify(taskForUpdate), - headers: { - "Content-Type": "application/json", - }, - }); + describe("Usuário anônimo", () => { + test("Tentando alterar tarefa", async () => { + const fakeTaskId = randomUUID(); + + const taskForUpdate = { + title: "Atualização da task sem usuário", + description: "O sistema deve bloquear essa ação!", + }; - expect(response.ok).toBe(false); - expect(response.status).toBe(401); + const response = await fetch(`${API.task}/${fakeTaskId}`, { + method: "PATCH", + body: JSON.stringify(taskForUpdate), + headers: { + "Content-Type": "application/json", + }, + }); - const responseBody = await response.json(); - expect(responseBody).toEqual({ - message: "Não autorizado.", - action: "Faça o login.", + expect(response.ok).toBe(false); + expect(response.status).toBe(401); + + const responseBody = await response.json(); + expect(responseBody).toEqual({ + message: "Não autorizado.", + action: "Faça o login.", + }); }); }); - let defaultUser: AuthenticatedUser; - let defaultSession: UserSession; - test("Com usuário logado porém `task` com `ID` inválido", async () => { - defaultUser = await createUser(); - defaultSession = await createSession(defaultUser); - const invalidId = "id-no-formato-invalido"; - - const taskForUpdate = { - title: "Atualização com ID inválido", - description: "O sistema deve bloquear essa ação!", - }; - - const response = await fetch(`${API.task}/${invalidId}`, { - method: "PATCH", - body: JSON.stringify(taskForUpdate), - headers: { - "Content-Type": "application/json", - Cookie: `session=${defaultSession.id}`, - }, + describe("Usuário padrão", () => { + let defaultUser: AuthenticatedUser; + let defaultSession: UserSession; + let taskForUpdate: Task; + test("`task` com `ID` inválido", async () => { + defaultUser = await createUser(); + defaultSession = await createSession(defaultUser); + const invalidId = "id-no-formato-invalido"; + + const taskForUpdate = { + title: "Atualização com ID inválido", + description: "O sistema deve bloquear essa ação!", + }; + + const response = await fetch(`${API.task}/${invalidId}`, { + method: "PATCH", + body: JSON.stringify(taskForUpdate), + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + }); + + expect(response.ok).toBe(false); + expect(response.status).toBe(400); + + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: "Id da task deve ser do tipo UUID.", + }); }); - expect(response.ok).toBe(false); - expect(response.status).toBe(400); + test("`task` com `ID` inexistente no banco", async () => { + const fakeTaskId = crypto.randomUUID(); + + const taskForUpdate = { + title: "Atualização da task sem usuário", + description: "O sistema deve bloquear essa ação!", + }; - const responseBody = await response.json(); - expect(responseBody).toEqual({ - error: "Id da task deve ser do tipo UUID.", + const response = await fetch(`${API.task}/${fakeTaskId}`, { + method: "PATCH", + body: JSON.stringify(taskForUpdate), + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + }); + + expect(response.ok).toBe(true); + expect(response.status).toBe(204); }); - }); - test("Com usuário logado porém `task` com `ID` inexistente no banco", async () => { - const fakeTaskId = crypto.randomUUID(); - - const taskForUpdate = { - title: "Atualização da task sem usuário", - description: "O sistema deve bloquear essa ação!", - }; - - const response = await fetch(`${API.task}/${fakeTaskId}`, { - method: "PATCH", - body: JSON.stringify(taskForUpdate), - headers: { - "Content-Type": "application/json", - Cookie: `session=${defaultSession.id}`, - }, + test("`task` com `ID` existente no banco", async () => { + const task = { + title: "Atualização da task", + description: "O sistema deve aceitar essa ação!", + }; + taskForUpdate = await createTask(task, defaultUser); + + const response = await fetch(`${API.task}/${taskForUpdate.id}`, { + method: "PATCH", + body: JSON.stringify({ + title: "Task atualizada!", + description: "O sistema aceitou a atualização!", + status: "done", + }), + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + }); + + expect(response.ok).toBe(true); + expect(response.status).toBe(201); + + const responseBody = await response.json(); + expect(responseBody.data.title).not.toBe(task.title); + expect(responseBody.data.description).not.toBe(task.description); + expect(new Date(responseBody.data.updated_at).getTime()).toBeGreaterThan( + new Date(responseBody.data.created_at).getTime(), + ); }); - expect(response.ok).toBe(true); - expect(response.status).toBe(204); - }); + test("`task` com `status` inexistente", async () => { + const task = { + title: "Atualização da task", + description: "O sistema deve aceitar essa ação!", + }; + + const taskForUpdate = await createTask(task, defaultUser); + + const response = await fetch(`${API.task}/${taskForUpdate.id}`, { + method: "PATCH", + body: JSON.stringify({ + status: "este_status_nao_existe", + }), + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + }); - test("Com usuário logado e `task` com `ID` existente no banco", async () => { - const task = { - title: "Atualização da task", - description: "O sistema deve aceitar essa ação!", - }; - const taskForUpdate = await createTask(task, defaultUser); - - const response = await fetch(`${API.task}/${taskForUpdate.id}`, { - method: "PATCH", - body: JSON.stringify({ - title: "Task atualizada!", - description: "O sistema aceitou a atualização!", - status: "done", - }), - headers: { - "Content-Type": "application/json", - Cookie: `session=${defaultSession.id}`, - }, + expect(response.ok).toBe(false); + expect(response.status).toBe(400); + + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: + 'Opção inválida: esperada uma das "pending"|"in_progress"|"done"', + }); }); - expect(response.ok).toBe(true); - expect(response.status).toBe(201); + test("Com um usuário tentando alterar `task` de outro usuário", async () => { + const task = { + title: "Criação da task", + description: "O sistema deve aceitar essa ação!", + }; - const responseBody = await response.json(); - expect(responseBody.data.title).not.toBe(task.title); - expect(responseBody.data.description).not.toBe(task.description); - expect(new Date(responseBody.data.updated_at).getTime()).toBeGreaterThan( - new Date(responseBody.data.created_at).getTime(), - ); - }); + const taskForUpdate = await createTask(task, defaultUser); + + const otherUser = await createUser(); + const otherSession = await createSession(otherUser); + + const response = await fetch(`${API.task}/${taskForUpdate.id}`, { + method: "PATCH", + body: JSON.stringify({ + title: "Alterado por outro usuário?", + description: "O sistema não pode aceitar esta ação!", + }), + headers: { + "Content-Type": "application/json", + Cookie: `session=${otherSession.id}`, + }, + }); - test("Com usuário logado e `task` com `status` inexistente", async () => { - const task = { - title: "Atualização da task", - description: "O sistema deve aceitar essa ação!", - }; - - const taskForUpdate = await createTask(task, defaultUser); - - const response = await fetch(`${API.task}/${taskForUpdate.id}`, { - method: "PATCH", - body: JSON.stringify({ - status: "este_status_nao_existe", - }), - headers: { - "Content-Type": "application/json", - Cookie: `session=${defaultSession.id}`, - }, + expect(response.ok).toBe(false); + expect(response.status).toBe(403); + + const responseBody = await response.json(); + expect(responseBody).toEqual({ + message: "Voce não tem permissão executar essa ação.", + }); }); - expect(response.ok).toBe(false); - expect(response.status).toBe(400); + test("Com `title` menor que 5 caracteres", async () => { + const response = await fetch(`${API.task}/${taskForUpdate.id}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + body: JSON.stringify({ + title: "Pequ", + }), + }); + + expect(response.ok).toBe(false); + expect(response.status).toBe(400); - const responseBody = await response.json(); - expect(responseBody).toEqual({ - error: 'Opção inválida: esperada uma das "pending"|"in_progress"|"done"', + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: "O título deve conter no mínimo 5 caracteres.", + }); }); - }); - test("Com um usuário tentando alterar `task` de outro usuário", async () => { - const task = { - title: "Criação da task", - description: "O sistema deve aceitar essa ação!", - }; - - const taskForUpdate = await createTask(task, defaultUser); - - const otherUser = await createUser(); - const otherSession = await createSession(otherUser); - - const response = await fetch(`${API.task}/${taskForUpdate.id}`, { - method: "PATCH", - body: JSON.stringify({ - title: "Alterado por outro usuário?", - description: "O sistema não pode aceitar esta ação!", - }), - headers: { - "Content-Type": "application/json", - Cookie: `session=${otherSession.id}`, - }, + test("Com `title` maior que 200 caracteres", async () => { + const title = + "Exploração Avançada de Parâmetros de Validação para Títulos e Descrições em Arquiteturas de Microserviços Modernas que Utilizam TypeScript e Node.js para Garantir a Integridade Total dos Dados na Nuvem."; + + const response = await fetch(`${API.task}/${taskForUpdate.id}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + body: JSON.stringify({ + title, + }), + }); + + expect(response.ok).toBe(false); + expect(response.status).toBe(400); + + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: "O título deve conter no máximo 200 caracteres.", + }); + }); + + test("Com `description` menor que 10 caracteres", async () => { + const response = await fetch(`${API.task}/${taskForUpdate.id}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + body: JSON.stringify({ + description: "Pequena", + }), + }); + + expect(response.ok).toBe(false); + expect(response.status).toBe(400); + + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: "A descrição deve conter no mínimo 10 caracteres.", + }); }); - expect(response.ok).toBe(false); - expect(response.status).toBe(403); + test("Com `description` maior que 500 caracteres", async () => { + const description = + "A implementação de limites rigorosos de caracteres em campos de texto é uma prática indispensável para o desenvolvimento de APIs resilientes e escaláveis. Ao definir um teto para a descrição, o desenvolvedor previne abusos de armazenamento e garante que a transferência de dados via JSON permaneça leve, otimizando o tempo de resposta do servidor. Além disso, essa restrição facilita a padronização estética na interface do usuário, evitando que componentes de cartão ou listas sofram deformações visuais inesperadas. No contexto de SEO, manter a descrição concisa auxilia os motores de busca a indexarem corretamente o resumo do conteúdo, refletindo diretamente na relevância do projeto."; + + const response = await fetch(`${API.task}/${taskForUpdate.id}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + body: JSON.stringify({ + description, + }), + }); + + expect(response.ok).toBe(false); + expect(response.status).toBe(400); - const responseBody = await response.json(); - expect(responseBody).toEqual({ - message: "Voce não tem permissão executar essa ação.", + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: "A descrição deve conter no máximo 500 caracteres.", + }); }); }); }); diff --git a/tests/controller/task/post.test.ts b/tests/controller/task/post.test.ts index 7b3f49b..71d5fca 100644 --- a/tests/controller/task/post.test.ts +++ b/tests/controller/task/post.test.ts @@ -11,153 +11,252 @@ beforeAll(async () => { }); describe("POST `/tasks`", () => { - test("Sem usuário logado", async () => { - const response = await fetch(API.task, { - method: "POST", - body: JSON.stringify({ - title: "Usuário sem sessão", - description: "O sistema deve bloquear esta ação!", - }), - }); + describe("Usuário anônimo", () => { + test("Tentando criar tarefa", async () => { + const response = await fetch(API.task, { + method: "POST", + body: JSON.stringify({ + title: "Usuário sem sessão", + description: "O sistema deve bloquear esta ação!", + }), + }); - expect(response.ok).toBe(false); - expect(response.status).toBe(401); + expect(response.ok).toBe(false); + expect(response.status).toBe(401); - const responseBody = await response.json(); - expect(responseBody).toEqual({ - message: "Não autorizado.", - action: "Faça o login.", + const responseBody = await response.json(); + expect(responseBody).toEqual({ + message: "Não autorizado.", + action: "Faça o login.", + }); }); }); - let defaultUser: AuthenticatedUser; - let defaultSession: UserSession; - test("Com usuário logado e todos os dados corretos", async () => { - const newTask = { - title: "Task com usuário logado", - description: "O sistema deve aceitar esta ação!", - status: "in_progress", - }; - - defaultUser = await createUser(); - defaultSession = await createSession(defaultUser); - - const response = await fetch(API.task, { - method: "POST", - body: JSON.stringify(newTask), - headers: { - "Content-Type": "application/json", - Cookie: `session=${defaultSession.id}`, - }, + describe("Usuário padrão", () => { + let defaultUser: AuthenticatedUser; + let defaultSession: UserSession; + test("Todos os dados corretos", async () => { + const newTask = { + title: "Task com usuário logado", + description: "O sistema deve aceitar esta ação!", + status: "in_progress", + }; + + defaultUser = await createUser(); + defaultSession = await createSession(defaultUser); + + const response = await fetch(API.task, { + method: "POST", + body: JSON.stringify(newTask), + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + }); + + expect(response.ok).toBe(true); + expect(response.status).toBe(201); + + const responseBody = await response.json(); + expect(responseBody).toHaveProperty("message"); + expect(responseBody.data).toHaveProperty( + "description", + newTask.description, + ); + expect(responseBody.data).toHaveProperty("title", newTask.title); + expect(responseBody.data).toHaveProperty("id"); + expect(responseBody.data).toHaveProperty("created_at"); + expect(responseBody.data).toHaveProperty("updated_at"); + expect(responseBody.data).toHaveProperty("status"); + expect(responseBody.data.user_id).toBe(defaultUser.id); }); - expect(response.ok).toBe(true); - expect(response.status).toBe(201); - - const responseBody = await response.json(); - expect(responseBody).toHaveProperty("message"); - expect(responseBody.data).toHaveProperty( - "description", - newTask.description, - ); - expect(responseBody.data).toHaveProperty("title", newTask.title); - expect(responseBody.data).toHaveProperty("id"); - expect(responseBody.data).toHaveProperty("created_at"); - expect(responseBody.data).toHaveProperty("updated_at"); - expect(responseBody.data).toHaveProperty("status"); - expect(responseBody.data.user_id).toBe(defaultUser.id); - }); + test("Sem a propriedade `title`", async () => { + const newTaskWithNoTitle = { + description: "O sistema deve negar esta ação!", + }; + + const response = await fetch(API.task, { + method: "POST", + body: JSON.stringify(newTaskWithNoTitle), + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + }); - test("Com usuário logado e sem a propriedade `title`", async () => { - const newTaskWithNoTitle = { - description: "O sistema deve negar esta ação!", - }; - - const response = await fetch(API.task, { - method: "POST", - body: JSON.stringify(newTaskWithNoTitle), - headers: { - "Content-Type": "application/json", - Cookie: `session=${defaultSession.id}`, - }, + expect(response.ok).toBe(false); + expect(response.status).toBe(400); + + const responseBody = await response.json(); + expect(responseBody).toHaveProperty("error"); + + expect(responseBody.error).toBe("Coluna 'title' é obrigatório!"); }); - expect(response.ok).toBe(false); - expect(response.status).toBe(400); + test("Sem a propriedade `description`", async () => { + const newTaskWithNoDescription = { + title: "Bad request!", + }; - const responseBody = await response.json(); - expect(responseBody).toHaveProperty("error"); + const response = await fetch(API.task, { + method: "POST", + body: JSON.stringify(newTaskWithNoDescription), + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + }); - expect(responseBody.error).toBe("Coluna 'title' é obrigatório!"); - }); + expect(response.ok).toBe(false); + expect(response.status).toBe(400); + + const responseBody = await response.json(); + expect(responseBody).toHaveProperty("error"); - test("Com usuário logado e sem a propriedade `description`", async () => { - const newTaskWithNoDescription = { - title: "Bad request!", - }; - - const response = await fetch(API.task, { - method: "POST", - body: JSON.stringify(newTaskWithNoDescription), - headers: { - "Content-Type": "application/json", - Cookie: `session=${defaultSession.id}`, - }, + expect(responseBody.error).toBe("Coluna 'description' é obrigatória!"); }); - expect(response.ok).toBe(false); - expect(response.status).toBe(400); + test("Sem as propriedades `title` e `description`", async () => { + const emptyObject = {}; - const responseBody = await response.json(); - expect(responseBody).toHaveProperty("error"); + const response = await fetch(API.task, { + method: "POST", + body: JSON.stringify(emptyObject), + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + }); - expect(responseBody.error).toBe("Coluna 'description' é obrigatória!"); - }); + expect(response.ok).toBe(false); + expect(response.status).toBe(400); - test("Com usuário logado e sem as propriedades `title` e `description`", async () => { - const emptyObject = {}; + const responseBody = await response.json(); + expect(responseBody).toHaveProperty("error"); - const response = await fetch(API.task, { - method: "POST", - body: JSON.stringify(emptyObject), - headers: { - "Content-Type": "application/json", - Cookie: `session=${defaultSession.id}`, - }, + expect(responseBody.error).toBe( + "Coluna 'title' é obrigatório! | Coluna 'description' é obrigatória!", + ); }); - expect(response.ok).toBe(false); - expect(response.status).toBe(400); + test("Com `status` inválido", async () => { + const newTaskWithInvalidStatus = { + title: "Tarefa com status invalido", + description: "O sistema deve obrigatóriamente bloquear esta ação.", + status: "status_inválido", + }; + const response = await fetch(API.task, { + method: "POST", + body: JSON.stringify(newTaskWithInvalidStatus), + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + }); - const responseBody = await response.json(); - expect(responseBody).toHaveProperty("error"); + expect(response.ok).toBe(false); + expect(response.status).toBe(400); - expect(responseBody.error).toBe( - "Coluna 'title' é obrigatório! | Coluna 'description' é obrigatória!", - ); - }); + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: + 'Opção inválida: esperada uma das "pending"|"in_progress"|"done"', + }); + }); - test("Com usuário logado e com `status` inválido", async () => { - const newTaskWithInvalidStatus = { - title: "Tarefa com status invalido", - description: "O sistema deve obrigatóriamente bloquear esta ação.", - status: "status_inválido", - }; - const response = await fetch(API.task, { - method: "POST", - body: JSON.stringify(newTaskWithInvalidStatus), - headers: { - "Content-Type": "application/json", - Cookie: `session=${defaultSession.id}`, - }, + test("Com `title` menor que 5 caracteres", async () => { + const response = await fetch(API.task, { + method: "POST", + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + body: JSON.stringify({ + title: "Pequ", + description: "Titulo muito pequeno, sistema deve bloquear!", + }), + }); + + expect(response.ok).toBe(false); + expect(response.status).toBe(400); + + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: "O título deve conter no mínimo 5 caracteres.", + }); + }); + + test("Com `title` maior que 200 caracteres", async () => { + const title = + "Exploração Avançada de Parâmetros de Validação para Títulos e Descrições em Arquiteturas de Microserviços Modernas que Utilizam TypeScript e Node.js para Garantir a Integridade Total dos Dados na Nuvem."; + + const response = await fetch(API.task, { + method: "POST", + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + body: JSON.stringify({ + title, + description: "Titulo muito grande, sistema deve bloquear!", + }), + }); + + expect(response.ok).toBe(false); + expect(response.status).toBe(400); + + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: "O título deve conter no máximo 200 caracteres.", + }); }); - expect(response.ok).toBe(false); - expect(response.status).toBe(400); + test("Com `description` menor que 10 caracteres", async () => { + const response = await fetch(API.task, { + method: "POST", + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + body: JSON.stringify({ + title: "Descrição pequena!", + description: "Pequena", + }), + }); + + expect(response.ok).toBe(false); + expect(response.status).toBe(400); + + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: "A descrição deve conter no mínimo 10 caracteres.", + }); + }); + + test("Com `description` maior que 500 caracteres", async () => { + const description = + "A implementação de limites rigorosos de caracteres em campos de texto é uma prática indispensável para o desenvolvimento de APIs resilientes e escaláveis. Ao definir um teto para a descrição, o desenvolvedor previne abusos de armazenamento e garante que a transferência de dados via JSON permaneça leve, otimizando o tempo de resposta do servidor. Além disso, essa restrição facilita a padronização estética na interface do usuário, evitando que componentes de cartão ou listas sofram deformações visuais inesperadas. No contexto de SEO, manter a descrição concisa auxilia os motores de busca a indexarem corretamente o resumo do conteúdo, refletindo diretamente na relevância do projeto."; + + const response = await fetch(API.task, { + method: "POST", + headers: { + "Content-Type": "application/json", + Cookie: `session=${defaultSession.id}`, + }, + body: JSON.stringify({ + title: "Descrição muito grande!", + description, + }), + }); + + expect(response.ok).toBe(false); + expect(response.status).toBe(400); - const responseBody = await response.json(); - expect(responseBody).toEqual({ - error: 'Opção inválida: esperada uma das "pending"|"in_progress"|"done"', + const responseBody = await response.json(); + expect(responseBody).toEqual({ + error: "A descrição deve conter no máximo 500 caracteres.", + }); }); }); });