From 81af2faa71dcf428f5c31e15ad6b8dc5be7c56f9 Mon Sep 17 00:00:00 2001 From: jvgasparoni Date: Tue, 28 Oct 2025 17:31:37 -0300 Subject: [PATCH 1/2] build: install `@faker-js/faker` --- package-lock.json | 18 ++++++++++++++++++ package.json | 1 + 2 files changed, 19 insertions(+) diff --git a/package-lock.json b/package-lock.json index dd1479a..18cab8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "devDependencies": { "@commitlint/cli": "19.4.0", "@commitlint/config-conventional": "19.2.2", + "@faker-js/faker": "9.7.0", "commitizen": "4.3.0", "concurrently": "8.2.2", "cz-conventional-changelog": "3.3.0", @@ -941,6 +942,23 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@faker-js/faker": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.7.0.tgz", + "integrity": "sha512-aozo5vqjCmDoXLNUJarFZx2IN/GgGaogY4TMJ6so/WLZOWpSV7fvj2dmrV6sEAnUm1O7aCrhTibjpzeDFgNqbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0.0", + "npm": ">=9.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", diff --git a/package.json b/package.json index bfea1c9..bab881c 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "devDependencies": { "@commitlint/cli": "19.4.0", "@commitlint/config-conventional": "19.2.2", + "@faker-js/faker": "9.7.0", "commitizen": "4.3.0", "concurrently": "8.2.2", "cz-conventional-changelog": "3.3.0", From 8a9ac5a0d3b0ae1306b50c708385fe0d746e17f7 Mon Sep 17 00:00:00 2001 From: jvgasparoni Date: Tue, 28 Oct 2025 17:32:17 -0300 Subject: [PATCH 2/2] feat: create and use `orchestrator.createUser()` --- .../api/v1/users/[username]/get.test.js | 82 +++++------- .../api/v1/users/[username]/patch.test.js | 125 ++++-------------- tests/orchestrator.js | 13 ++ 3 files changed, 70 insertions(+), 150 deletions(-) diff --git a/tests/integration/api/v1/users/[username]/get.test.js b/tests/integration/api/v1/users/[username]/get.test.js index 5b68c73..e903743 100644 --- a/tests/integration/api/v1/users/[username]/get.test.js +++ b/tests/integration/api/v1/users/[username]/get.test.js @@ -9,81 +9,61 @@ beforeAll(async () => { describe("GET /api/v1/users/[username]", () => { describe("Anonymous user", () => { - test("With exact case match'", async () => { - const response1 = await fetch("http://localhost:3000/api/v1/users", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - username: "MesmoCase", - email: "mesmo.case@example.com", - password: "password123", - }), + test("With exact case match", async () => { + const createdUser = await orchestrator.createUser({ + username: "MesmoCase", }); - expect(response1.status).toBe(201); - - const response2 = await fetch( + const response = await fetch( "http://localhost:3000/api/v1/users/MesmoCase", ); - expect(response2.status).toBe(200); + expect(response.status).toBe(200); - const response2Body = await response2.json(); + const responseBody = await response.json(); - expect(response2Body).toEqual({ - id: response2Body.id, + expect(responseBody).toEqual({ + id: responseBody.id, username: "MesmoCase", - email: "mesmo.case@example.com", - password: response2Body.password, - created_at: response2Body.created_at, - updated_at: response2Body.updated_at, + email: createdUser.email, + password: responseBody.password, + created_at: responseBody.created_at, + updated_at: responseBody.updated_at, }); - expect(uuidVersion(response2Body.id)).toBe(4); - expect(Date.parse(response2Body.created_at)).not.toBeNaN(); - expect(Date.parse(response2Body.updated_at)).not.toBeNaN(); + expect(uuidVersion(responseBody.id)).toBe(4); + expect(Date.parse(responseBody.created_at)).not.toBeNaN(); + expect(Date.parse(responseBody.updated_at)).not.toBeNaN(); }); - test("With case mismatch'", async () => { - const response1 = await fetch("http://localhost:3000/api/v1/users", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - username: "CaseDiferente", - email: "case.diferente@example.com", - password: "password123", - }), + test("With case mismatch", async () => { + const createdUser = await orchestrator.createUser({ + username: "CaseDiferente", }); - expect(response1.status).toBe(201); - - const response2 = await fetch( + const response = await fetch( "http://localhost:3000/api/v1/users/casediferente", ); - expect(response2.status).toBe(200); + expect(response.status).toBe(200); - const response2Body = await response2.json(); + const responseBody = await response.json(); - expect(response2Body).toEqual({ - id: response2Body.id, + expect(responseBody).toEqual({ + id: responseBody.id, username: "CaseDiferente", - email: "case.diferente@example.com", - password: response2Body.password, - created_at: response2Body.created_at, - updated_at: response2Body.updated_at, + email: createdUser.email, + password: responseBody.password, + created_at: responseBody.created_at, + updated_at: responseBody.updated_at, }); - expect(uuidVersion(response2Body.id)).toBe(4); - expect(Date.parse(response2Body.created_at)).not.toBeNaN(); - expect(Date.parse(response2Body.updated_at)).not.toBeNaN(); + expect(uuidVersion(responseBody.id)).toBe(4); + expect(Date.parse(responseBody.created_at)).not.toBeNaN(); + expect(Date.parse(responseBody.updated_at)).not.toBeNaN(); }); - test("With nonexistent username'", async () => { + test("With nonexistent username", async () => { const response = await fetch( "http://localhost:3000/api/v1/users/UsuarioInexistente", ); diff --git a/tests/integration/api/v1/users/[username]/patch.test.js b/tests/integration/api/v1/users/[username]/patch.test.js index c093c99..ba42df6 100644 --- a/tests/integration/api/v1/users/[username]/patch.test.js +++ b/tests/integration/api/v1/users/[username]/patch.test.js @@ -11,7 +11,7 @@ beforeAll(async () => { describe("PATCH /api/v1/users/[username]", () => { describe("Anonymous user", () => { - test("With nonexistent 'username''", async () => { + test("With nonexistent 'username'", async () => { const response = await fetch( "http://localhost:3000/api/v1/users/UsuarioInexistente", { @@ -32,34 +32,14 @@ describe("PATCH /api/v1/users/[username]", () => { }); test("With duplicated 'username'", async () => { - const user1Response = await fetch("http://localhost:3000/api/v1/users", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - username: "user1", - email: "user1@example.com", - password: "password123", - }), + await orchestrator.createUser({ + username: "user1", }); - expect(user1Response.status).toBe(201); - - const user2Response = await fetch("http://localhost:3000/api/v1/users", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - username: "user2", - email: "user2@example.com", - password: "password123", - }), + await orchestrator.createUser({ + username: "user2", }); - expect(user2Response.status).toBe(201); - const response = await fetch("http://localhost:3000/api/v1/users/user2", { method: "PATCH", headers: { @@ -83,43 +63,23 @@ describe("PATCH /api/v1/users/[username]", () => { }); test("With duplicated 'email'", async () => { - const user1Response = await fetch("http://localhost:3000/api/v1/users", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - username: "email1", - email: "email1@example.com", - password: "password123", - }), + await orchestrator.createUser({ + email: "email1@curso.dev", }); - expect(user1Response.status).toBe(201); - - const user2Response = await fetch("http://localhost:3000/api/v1/users", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - username: "email2", - email: "email2@example.com", - password: "password123", - }), + const createdUser2 = await orchestrator.createUser({ + email: "email2@curso.dev", }); - expect(user2Response.status).toBe(201); - const response = await fetch( - "http://localhost:3000/api/v1/users/email2", + `http://localhost:3000/api/v1/users/${createdUser2.username}`, { method: "PATCH", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ - email: "email1@example.com", + email: "email1@curso.dev", }), }, ); @@ -137,22 +97,10 @@ describe("PATCH /api/v1/users/[username]", () => { }); test("With unique 'username'", async () => { - const user1Response = await fetch("http://localhost:3000/api/v1/users", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - username: "uniqueUser1", - email: "uniqueUser1@example.com", - password: "password123", - }), - }); - - expect(user1Response.status).toBe(201); + const createdUser = await orchestrator.createUser(); const response = await fetch( - "http://localhost:3000/api/v1/users/uniqueUser1", + `http://localhost:3000/api/v1/users/${createdUser.username}`, { method: "PATCH", headers: { @@ -171,7 +119,7 @@ describe("PATCH /api/v1/users/[username]", () => { expect(responseBody).toEqual({ id: responseBody.id, username: "uniqueUser2", - email: "uniqueUser1@example.com", + email: createdUser.email, password: responseBody.password, created_at: responseBody.created_at, updated_at: responseBody.updated_at, @@ -185,29 +133,18 @@ describe("PATCH /api/v1/users/[username]", () => { }); test("With unique 'email'", async () => { - const user1Response = await fetch("http://localhost:3000/api/v1/users", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - username: "uniqueEmail1", - email: "uniqueEmail1@example.com", - password: "password123", - }), - }); - - expect(user1Response.status).toBe(201); + const createdUser = await orchestrator.createUser(); const response = await fetch( - "http://localhost:3000/api/v1/users/uniqueEmail1", + `http://localhost:3000/api/v1/users/${createdUser.username}`, + { method: "PATCH", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ - email: "uniqueEmail2@example.com", + email: "uniqueEmail2@curso.dev", }), }, ); @@ -218,8 +155,8 @@ describe("PATCH /api/v1/users/[username]", () => { expect(responseBody).toEqual({ id: responseBody.id, - username: "uniqueEmail1", - email: "uniqueEmail2@example.com", + username: createdUser.username, + email: "uniqueEmail2@curso.dev", password: responseBody.password, created_at: responseBody.created_at, updated_at: responseBody.updated_at, @@ -233,22 +170,12 @@ describe("PATCH /api/v1/users/[username]", () => { }); test("With new 'password'", async () => { - const user1Response = await fetch("http://localhost:3000/api/v1/users", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - username: "newPassword1", - email: "newPassword1@example.com", - password: "password123", - }), + const createdUser = await orchestrator.createUser({ + password: "newPassword1", }); - expect(user1Response.status).toBe(201); - const response = await fetch( - "http://localhost:3000/api/v1/users/newPassword1", + `http://localhost:3000/api/v1/users/${createdUser.username}`, { method: "PATCH", headers: { @@ -266,8 +193,8 @@ describe("PATCH /api/v1/users/[username]", () => { expect(responseBody).toEqual({ id: responseBody.id, - username: "newPassword1", - email: "newPassword1@example.com", + username: createdUser.username, + email: createdUser.email, password: responseBody.password, created_at: responseBody.created_at, updated_at: responseBody.updated_at, @@ -279,7 +206,7 @@ describe("PATCH /api/v1/users/[username]", () => { expect(responseBody.updated_at > responseBody.created_at).toBe(true); - const userInDatabase = await user.findOneByUsername("newPassword1"); + const userInDatabase = await user.findOneByUsername(createdUser.username); const correctPasswordMatch = await password.compare( "newPassword2", userInDatabase.password, diff --git a/tests/orchestrator.js b/tests/orchestrator.js index d9806f7..30f5039 100644 --- a/tests/orchestrator.js +++ b/tests/orchestrator.js @@ -1,6 +1,9 @@ +import { faker } from "@faker-js/faker"; import retry from "async-retry"; + import database from "infra/database.js"; import migrator from "models/migrator.js"; +import user from "models/user.js"; async function waitForAllServices() { await waitForWebServer(); @@ -29,10 +32,20 @@ async function runPendingMigrations() { await migrator.runPendingMigrations(); } +async function createUser(userObject) { + return await user.create({ + username: + userObject?.username || faker.internet.username().replace(/[_.-]/g, ""), + email: userObject?.email || faker.internet.email(), + password: userObject?.password || "validpassword", + }); +} + const orchestrator = { waitForAllServices, clearDatabase, runPendingMigrations, + createUser, }; export default orchestrator;