refactor: remove username from User model, login by email only
This commit is contained in:
@@ -50,7 +50,6 @@ describe("user actions localization", () => {
|
||||
describe("createUserAction", () => {
|
||||
it("returns localized schema validation errors for invalid create input", async () => {
|
||||
const result = await createUserAction({
|
||||
username: "",
|
||||
name: "",
|
||||
email: "bad",
|
||||
password: "short",
|
||||
@@ -63,7 +62,6 @@ describe("user actions localization", () => {
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
errors: {
|
||||
username: [es.admin.users.schema.usernameRequired],
|
||||
name: [es.admin.users.schema.nameRequired],
|
||||
email: [es.admin.users.schema.emailInvalid],
|
||||
password: [es.admin.users.schema.passwordMinLength],
|
||||
@@ -75,13 +73,11 @@ describe("user actions localization", () => {
|
||||
mocks.createUserUseCase.mockResolvedValue({
|
||||
success: false,
|
||||
errors: {
|
||||
username: ["Username already exists"],
|
||||
email: ["Email already exists"],
|
||||
},
|
||||
})
|
||||
|
||||
const result = await createUserAction({
|
||||
username: "ada",
|
||||
name: "Ada",
|
||||
email: "ada@example.test",
|
||||
password: "password1",
|
||||
@@ -92,7 +88,6 @@ describe("user actions localization", () => {
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
errors: {
|
||||
username: [es.admin.users.actions.duplicateUsername],
|
||||
email: [es.admin.users.actions.duplicateEmail],
|
||||
},
|
||||
message: es.admin.users.actions.createFailure,
|
||||
@@ -103,7 +98,6 @@ describe("user actions localization", () => {
|
||||
mocks.createUserUseCase.mockResolvedValue({ success: true })
|
||||
|
||||
const result = await createUserAction({
|
||||
username: "ada",
|
||||
name: "Ada",
|
||||
email: "ada@example.test",
|
||||
password: "password1",
|
||||
@@ -123,7 +117,6 @@ describe("user actions localization", () => {
|
||||
it("returns localized schema validation errors for invalid update input", async () => {
|
||||
const result = await updateUserAction({
|
||||
id: "",
|
||||
username: "",
|
||||
name: "",
|
||||
email: "bad",
|
||||
role: "ADMIN",
|
||||
@@ -136,7 +129,6 @@ describe("user actions localization", () => {
|
||||
success: false,
|
||||
errors: {
|
||||
id: [es.admin.users.schema.userIdRequired],
|
||||
username: [es.admin.users.schema.usernameRequired],
|
||||
name: [es.admin.users.schema.nameRequired],
|
||||
email: [es.admin.users.schema.emailInvalid],
|
||||
},
|
||||
@@ -156,7 +148,6 @@ describe("user actions localization", () => {
|
||||
|
||||
const result = await updateUserAction({
|
||||
id: "user-1",
|
||||
username: "admin",
|
||||
name: "Admin",
|
||||
email: "admin@example.test",
|
||||
role: "MANAGER",
|
||||
@@ -180,7 +171,6 @@ describe("user actions localization", () => {
|
||||
|
||||
const result = await updateUserAction({
|
||||
id: "user-1",
|
||||
username: "admin",
|
||||
name: "Admin",
|
||||
email: "admin@example.test",
|
||||
role: "ADMIN",
|
||||
|
||||
@@ -6,11 +6,10 @@ import { es } from "@/i18n/dictionaries/es"
|
||||
const actionCopy = es.admin.users.actions
|
||||
|
||||
describe("user action message localization", () => {
|
||||
it("localizes all 6 known use-case error strings to dictionary keys", () => {
|
||||
it("localizes all 5 known use-case error strings to dictionary keys", () => {
|
||||
expect(
|
||||
localizeUserFieldErrors(
|
||||
{
|
||||
username: ["Username already exists"],
|
||||
email: ["Email already exists"],
|
||||
id: [
|
||||
"User not found",
|
||||
@@ -22,7 +21,6 @@ describe("user action message localization", () => {
|
||||
actionCopy,
|
||||
),
|
||||
).toEqual({
|
||||
username: [actionCopy.duplicateUsername],
|
||||
email: [actionCopy.duplicateEmail],
|
||||
id: [
|
||||
actionCopy.notFound,
|
||||
|
||||
@@ -74,7 +74,6 @@ describe("new user form localization", () => {
|
||||
|
||||
// Form labels from dictionary
|
||||
expect(html).toContain("Nombre")
|
||||
expect(html).toContain("Usuario")
|
||||
expect(html).toContain("Correo electrónico")
|
||||
expect(html).toContain("Contraseña")
|
||||
expect(html).toContain("Rol")
|
||||
@@ -104,7 +103,6 @@ describe("new user form localization", () => {
|
||||
|
||||
expect(html).toContain("New User")
|
||||
expect(html).toContain("Full name")
|
||||
expect(html).toContain("Username")
|
||||
expect(html).toContain("Password")
|
||||
expect(html).toContain("Minimum 8 characters")
|
||||
expect(html).toContain("Create User")
|
||||
@@ -136,7 +134,6 @@ describe("edit user form localization", () => {
|
||||
mocks.getUserProfileById.mockResolvedValue({
|
||||
id: "user-1",
|
||||
name: "Ada Lovelace",
|
||||
username: "ada",
|
||||
email: "ada@example.test",
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
|
||||
@@ -51,7 +51,6 @@ describe("user pages localization", () => {
|
||||
{
|
||||
id: "user-1",
|
||||
name: "Ada Lovelace",
|
||||
username: "ada",
|
||||
email: "ada@example.test",
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
@@ -59,7 +58,6 @@ describe("user pages localization", () => {
|
||||
{
|
||||
id: "user-2",
|
||||
name: "Grace Hopper",
|
||||
username: "grace",
|
||||
email: "grace@example.test",
|
||||
role: "STAFF",
|
||||
isActive: false,
|
||||
@@ -78,7 +76,6 @@ describe("user pages localization", () => {
|
||||
|
||||
// Table headers from dictionary
|
||||
expect(html).toContain("Nombre")
|
||||
expect(html).toContain("Usuario")
|
||||
expect(html).toContain("Correo electrónico")
|
||||
expect(html).toContain("Rol")
|
||||
expect(html).toContain("Estado")
|
||||
@@ -94,10 +91,8 @@ describe("user pages localization", () => {
|
||||
|
||||
// User data is never translated
|
||||
expect(html).toContain("Ada Lovelace")
|
||||
expect(html).toContain("ada")
|
||||
expect(html).toContain("ada@example.test")
|
||||
expect(html).toContain("Grace Hopper")
|
||||
expect(html).toContain("grace")
|
||||
expect(html).toContain("grace@example.test")
|
||||
|
||||
// Canonical role values must NOT appear as display text
|
||||
@@ -133,7 +128,6 @@ describe("user pages localization", () => {
|
||||
{
|
||||
id: "user-1",
|
||||
name: "Ada Lovelace",
|
||||
username: "ada",
|
||||
email: "ada@example.test",
|
||||
role: "MANAGER",
|
||||
isActive: true,
|
||||
@@ -150,7 +144,6 @@ describe("user pages localization", () => {
|
||||
expect(html).toContain("Users")
|
||||
expect(html).toContain("Add User")
|
||||
expect(html).toContain("Name")
|
||||
expect(html).toContain("Username")
|
||||
expect(html).toContain("Email")
|
||||
expect(html).toContain("Role")
|
||||
expect(html).toContain("Status")
|
||||
@@ -172,7 +165,6 @@ describe("user pages localization", () => {
|
||||
{
|
||||
id: "user-1",
|
||||
name: "Test User",
|
||||
username: "testuser",
|
||||
email: "test@example.test",
|
||||
role: "UNKNOWN_ROLE",
|
||||
isActive: true,
|
||||
|
||||
@@ -12,7 +12,6 @@ describe("admin users dictionary", () => {
|
||||
empty: "No users found.",
|
||||
columns: {
|
||||
name: "Name",
|
||||
username: "Username",
|
||||
email: "Email",
|
||||
role: "Role",
|
||||
status: "Status",
|
||||
@@ -29,8 +28,6 @@ describe("admin users dictionary", () => {
|
||||
expect(users.form).toEqual({
|
||||
nameLabel: "Name",
|
||||
namePlaceholder: "Full name",
|
||||
usernameLabel: "Username",
|
||||
usernamePlaceholder: "Username",
|
||||
emailLabel: "Email",
|
||||
emailPlaceholder: "user@example.com",
|
||||
passwordLabel: "Password",
|
||||
@@ -69,7 +66,6 @@ describe("admin users dictionary", () => {
|
||||
toggleStatusFailure: "Failed to update user status",
|
||||
resetPasswordSuccess: "Password reset successfully",
|
||||
resetPasswordFailure: "Failed to reset password",
|
||||
duplicateUsername: "Username already exists",
|
||||
duplicateEmail: "Email already exists",
|
||||
notFound: "User not found",
|
||||
lastActiveAdmin:
|
||||
@@ -79,7 +75,6 @@ describe("admin users dictionary", () => {
|
||||
})
|
||||
|
||||
expect(users.schema).toEqual({
|
||||
usernameRequired: "Username is required",
|
||||
nameRequired: "Name is required",
|
||||
emailInvalid: "Invalid email",
|
||||
passwordMinLength: "Password must be at least 8 characters",
|
||||
@@ -100,7 +95,6 @@ describe("admin users dictionary", () => {
|
||||
empty: "No se encontraron usuarios.",
|
||||
columns: {
|
||||
name: "Nombre",
|
||||
username: "Usuario",
|
||||
email: "Correo electrónico",
|
||||
role: "Rol",
|
||||
status: "Estado",
|
||||
@@ -117,8 +111,6 @@ describe("admin users dictionary", () => {
|
||||
expect(users.form).toEqual({
|
||||
nameLabel: "Nombre",
|
||||
namePlaceholder: "Nombre completo",
|
||||
usernameLabel: "Usuario",
|
||||
usernamePlaceholder: "Usuario",
|
||||
emailLabel: "Correo electrónico",
|
||||
emailPlaceholder: "usuario@ejemplo.com",
|
||||
passwordLabel: "Contraseña",
|
||||
@@ -157,7 +149,6 @@ describe("admin users dictionary", () => {
|
||||
toggleStatusFailure: "Error al actualizar el estado del usuario",
|
||||
resetPasswordSuccess: "Contraseña restablecida correctamente",
|
||||
resetPasswordFailure: "Error al restablecer la contraseña",
|
||||
duplicateUsername: "El nombre de usuario ya existe",
|
||||
duplicateEmail: "El correo electrónico ya existe",
|
||||
notFound: "Usuario no encontrado",
|
||||
lastActiveAdmin:
|
||||
@@ -167,7 +158,6 @@ describe("admin users dictionary", () => {
|
||||
})
|
||||
|
||||
expect(users.schema).toEqual({
|
||||
usernameRequired: "El usuario es obligatorio",
|
||||
nameRequired: "El nombre es obligatorio",
|
||||
emailInvalid: "Correo electrónico no válido",
|
||||
passwordMinLength: "La contraseña debe tener al menos 8 caracteres",
|
||||
|
||||
@@ -13,14 +13,14 @@ describe("i18n dictionaries", () => {
|
||||
it("returns localized login copy for English and Spanish", () => {
|
||||
expect(getDictionary("en").login).toEqual({
|
||||
title: "Sign In",
|
||||
usernameLabel: "Username",
|
||||
emailLabel: "Email",
|
||||
passwordLabel: "Password",
|
||||
submitLabel: "Sign In",
|
||||
})
|
||||
|
||||
expect(getDictionary("es").login).toEqual({
|
||||
title: "Iniciar sesión",
|
||||
usernameLabel: "Usuario",
|
||||
emailLabel: "Correo electrónico",
|
||||
passwordLabel: "Contraseña",
|
||||
submitLabel: "Iniciar sesión",
|
||||
})
|
||||
|
||||
@@ -83,7 +83,6 @@ describe("core schemas", () => {
|
||||
expect(
|
||||
updateUserSchema.safeParse({
|
||||
id: "user-id",
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
role: "ADMIN",
|
||||
@@ -94,7 +93,6 @@ describe("core schemas", () => {
|
||||
expect(
|
||||
updateUserSchema.safeParse({
|
||||
id: "",
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
role: "ADMIN",
|
||||
@@ -110,13 +108,13 @@ describe("core schemas", () => {
|
||||
)
|
||||
|
||||
expect(
|
||||
signInSchema.safeParse({ username: "admin", password: "abc" }).success,
|
||||
signInSchema.safeParse({ email: "admin@test.com", password: "abc" }).success,
|
||||
).toBe(true)
|
||||
expect(
|
||||
signInSchema.safeParse({ username: "", password: "abc" }).success,
|
||||
signInSchema.safeParse({ email: "", password: "abc" }).success,
|
||||
).toBe(false)
|
||||
expect(
|
||||
signInSchema.safeParse({ username: "admin", password: "ab" }).success,
|
||||
signInSchema.safeParse({ email: "admin@test.com", password: "ab" }).success,
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
@@ -152,7 +150,6 @@ describe("core schemas", () => {
|
||||
it("validates user password, email, and role", () => {
|
||||
expect(
|
||||
createUserSchema.safeParse({
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
password: "password1",
|
||||
@@ -163,7 +160,6 @@ describe("core schemas", () => {
|
||||
|
||||
expect(
|
||||
createUserSchema.safeParse({
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "bad-email",
|
||||
password: "password1",
|
||||
@@ -174,7 +170,6 @@ describe("core schemas", () => {
|
||||
|
||||
expect(
|
||||
createUserSchema.safeParse({
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
password: "short",
|
||||
@@ -185,7 +180,6 @@ describe("core schemas", () => {
|
||||
|
||||
expect(
|
||||
createUserSchema.safeParse({
|
||||
username: "user",
|
||||
name: "User",
|
||||
email: "user@example.test",
|
||||
password: "password1",
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
} from "@/schemas/user.schema"
|
||||
|
||||
const esCopy: UserSchemaCopy = {
|
||||
usernameRequired: "El usuario es obligatorio",
|
||||
nameRequired: "El nombre es obligatorio",
|
||||
emailInvalid: "Correo electrónico no válido",
|
||||
passwordMinLength: "La contraseña debe tener al menos 8 caracteres",
|
||||
@@ -20,7 +19,6 @@ const esCopy: UserSchemaCopy = {
|
||||
}
|
||||
|
||||
const validCreateData = {
|
||||
username: "admin",
|
||||
name: "Admin User",
|
||||
email: "admin@example.test",
|
||||
password: "password1",
|
||||
@@ -30,7 +28,6 @@ const validCreateData = {
|
||||
|
||||
const validUpdateData = {
|
||||
id: "user-id",
|
||||
username: "admin",
|
||||
name: "Admin User",
|
||||
email: "admin@example.test",
|
||||
role: "ADMIN" as const,
|
||||
@@ -40,7 +37,6 @@ const validUpdateData = {
|
||||
describe("user schema localization", () => {
|
||||
it("buildCreateUserSchema with default copy produces same validation as createUserSchema", () => {
|
||||
const result = buildCreateUserSchema(defaultUserSchemaCopy).safeParse({
|
||||
username: "",
|
||||
name: "",
|
||||
email: "bad",
|
||||
password: "short",
|
||||
@@ -51,7 +47,6 @@ describe("user schema localization", () => {
|
||||
expect(result.success).toBe(false)
|
||||
if (!result.success) {
|
||||
const errors = result.error.flatten().fieldErrors
|
||||
expect(errors.username).toContain("Username is required")
|
||||
expect(errors.name).toContain("Name is required")
|
||||
expect(errors.email).toContain("Invalid email")
|
||||
expect(errors.password).toContain(
|
||||
@@ -64,7 +59,6 @@ describe("user schema localization", () => {
|
||||
|
||||
it("buildCreateUserSchema with Spanish copy produces Spanish error messages", () => {
|
||||
const result = buildCreateUserSchema(esCopy).safeParse({
|
||||
username: "",
|
||||
name: "",
|
||||
email: "bad",
|
||||
password: "short",
|
||||
@@ -75,7 +69,6 @@ describe("user schema localization", () => {
|
||||
expect(result.success).toBe(false)
|
||||
if (!result.success) {
|
||||
const errors = result.error.flatten().fieldErrors
|
||||
expect(errors.username).toContain(esCopy.usernameRequired)
|
||||
expect(errors.name).toContain(esCopy.nameRequired)
|
||||
expect(errors.email).toContain(esCopy.emailInvalid)
|
||||
expect(errors.password).toContain(esCopy.passwordMinLength)
|
||||
@@ -85,7 +78,6 @@ describe("user schema localization", () => {
|
||||
it("buildUpdateUserSchema with default copy produces same validation as updateUserSchema", () => {
|
||||
const result = buildUpdateUserSchema(defaultUserSchemaCopy).safeParse({
|
||||
id: "",
|
||||
username: "",
|
||||
name: "",
|
||||
email: "bad",
|
||||
role: "INVALID",
|
||||
@@ -96,7 +88,6 @@ describe("user schema localization", () => {
|
||||
if (!result.success) {
|
||||
const errors = result.error.flatten().fieldErrors
|
||||
expect(errors.id).toContain("User id is required")
|
||||
expect(errors.username).toContain("Username is required")
|
||||
expect(errors.name).toContain("Name is required")
|
||||
expect(errors.email).toContain("Invalid email")
|
||||
}
|
||||
@@ -105,7 +96,6 @@ describe("user schema localization", () => {
|
||||
it("buildUpdateUserSchema with Spanish copy produces Spanish error messages", () => {
|
||||
const result = buildUpdateUserSchema(esCopy).safeParse({
|
||||
id: "",
|
||||
username: "",
|
||||
name: "",
|
||||
email: "bad",
|
||||
role: "INVALID",
|
||||
@@ -116,7 +106,6 @@ describe("user schema localization", () => {
|
||||
if (!result.success) {
|
||||
const errors = result.error.flatten().fieldErrors
|
||||
expect(errors.id).toContain(esCopy.userIdRequired)
|
||||
expect(errors.username).toContain(esCopy.usernameRequired)
|
||||
expect(errors.name).toContain(esCopy.nameRequired)
|
||||
expect(errors.email).toContain(esCopy.emailInvalid)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user