feat(i18n): localize admin users backbone
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
import { es } from "@/i18n/dictionaries/es"
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
revalidatePath: vi.fn(),
|
||||
getI18n: vi.fn(),
|
||||
requireRole: vi.fn(),
|
||||
createUserUseCase: vi.fn(),
|
||||
updateUserUseCase: vi.fn(),
|
||||
setUserActiveUseCase: vi.fn(),
|
||||
resetUserPasswordUseCase: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock("next/cache", () => ({
|
||||
revalidatePath: mocks.revalidatePath,
|
||||
}))
|
||||
|
||||
vi.mock("@/i18n/server", () => ({
|
||||
getI18n: mocks.getI18n,
|
||||
}))
|
||||
|
||||
vi.mock("@/services/auth.service", () => ({
|
||||
requireRole: mocks.requireRole,
|
||||
}))
|
||||
|
||||
vi.mock("@/use-cases/user.use-cases", () => ({
|
||||
createUserUseCase: mocks.createUserUseCase,
|
||||
updateUserUseCase: mocks.updateUserUseCase,
|
||||
setUserActiveUseCase: mocks.setUserActiveUseCase,
|
||||
resetUserPasswordUseCase: mocks.resetUserPasswordUseCase,
|
||||
}))
|
||||
|
||||
import {
|
||||
createUserAction,
|
||||
resetUserPasswordAction,
|
||||
setUserActiveAction,
|
||||
updateUserAction,
|
||||
} from "@/actions/user.actions"
|
||||
|
||||
describe("user actions localization", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mocks.getI18n.mockResolvedValue({ dictionary: es, locale: "es" })
|
||||
mocks.requireRole.mockResolvedValue({
|
||||
user: { id: "admin-1" },
|
||||
})
|
||||
})
|
||||
|
||||
describe("createUserAction", () => {
|
||||
it("returns localized schema validation errors for invalid create input", async () => {
|
||||
const result = await createUserAction({
|
||||
username: "",
|
||||
name: "",
|
||||
email: "bad",
|
||||
password: "short",
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
})
|
||||
|
||||
expect(mocks.getI18n).toHaveBeenCalledOnce()
|
||||
expect(mocks.createUserUseCase).not.toHaveBeenCalled()
|
||||
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],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("localizes mapped duplicate field errors for create failures", async () => {
|
||||
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",
|
||||
role: "STAFF",
|
||||
isActive: true,
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
errors: {
|
||||
username: [es.admin.users.actions.duplicateUsername],
|
||||
email: [es.admin.users.actions.duplicateEmail],
|
||||
},
|
||||
message: es.admin.users.actions.createFailure,
|
||||
})
|
||||
})
|
||||
|
||||
it("returns a localized create success message and revalidates", async () => {
|
||||
mocks.createUserUseCase.mockResolvedValue({ success: true })
|
||||
|
||||
const result = await createUserAction({
|
||||
username: "ada",
|
||||
name: "Ada",
|
||||
email: "ada@example.test",
|
||||
password: "password1",
|
||||
role: "STAFF",
|
||||
isActive: true,
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
success: true,
|
||||
message: es.admin.users.actions.createSuccess,
|
||||
})
|
||||
expect(mocks.revalidatePath).toHaveBeenCalledWith("/admin/users")
|
||||
})
|
||||
})
|
||||
|
||||
describe("updateUserAction", () => {
|
||||
it("returns localized schema validation errors for invalid update input", async () => {
|
||||
const result = await updateUserAction({
|
||||
id: "",
|
||||
username: "",
|
||||
name: "",
|
||||
email: "bad",
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
})
|
||||
|
||||
expect(mocks.getI18n).toHaveBeenCalledOnce()
|
||||
expect(mocks.updateUserUseCase).not.toHaveBeenCalled()
|
||||
expect(result).toEqual({
|
||||
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],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("localizes mapped use-case errors for update failures", async () => {
|
||||
mocks.updateUserUseCase.mockResolvedValue({
|
||||
success: false,
|
||||
errors: {
|
||||
id: [
|
||||
"Cannot remove access from the last active administrator",
|
||||
"You cannot remove your own administrator access",
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const result = await updateUserAction({
|
||||
id: "user-1",
|
||||
username: "admin",
|
||||
name: "Admin",
|
||||
email: "admin@example.test",
|
||||
role: "MANAGER",
|
||||
isActive: true,
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
errors: {
|
||||
id: [
|
||||
es.admin.users.actions.lastActiveAdmin,
|
||||
es.admin.users.actions.selfAdminAccess,
|
||||
],
|
||||
},
|
||||
message: es.admin.users.actions.updateFailure,
|
||||
})
|
||||
})
|
||||
|
||||
it("returns a localized update success message and revalidates", async () => {
|
||||
mocks.updateUserUseCase.mockResolvedValue({ success: true })
|
||||
|
||||
const result = await updateUserAction({
|
||||
id: "user-1",
|
||||
username: "admin",
|
||||
name: "Admin",
|
||||
email: "admin@example.test",
|
||||
role: "ADMIN",
|
||||
isActive: true,
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
success: true,
|
||||
message: es.admin.users.actions.updateSuccess,
|
||||
})
|
||||
expect(mocks.revalidatePath).toHaveBeenCalledWith("/admin/users")
|
||||
})
|
||||
})
|
||||
|
||||
describe("setUserActiveAction", () => {
|
||||
it("returns localized schema validation errors for invalid input", async () => {
|
||||
const result = await setUserActiveAction({
|
||||
id: "",
|
||||
isActive: false,
|
||||
})
|
||||
|
||||
expect(mocks.getI18n).toHaveBeenCalledOnce()
|
||||
expect(mocks.setUserActiveUseCase).not.toHaveBeenCalled()
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
errors: {
|
||||
id: [es.admin.users.schema.userIdRequired],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("localizes mapped use-case errors for toggle failures", async () => {
|
||||
mocks.setUserActiveUseCase.mockResolvedValue({
|
||||
success: false,
|
||||
errors: {
|
||||
id: ["You cannot deactivate your own user"],
|
||||
},
|
||||
})
|
||||
|
||||
const result = await setUserActiveAction({
|
||||
id: "user-1",
|
||||
isActive: false,
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
errors: {
|
||||
id: [es.admin.users.actions.selfDeactivate],
|
||||
},
|
||||
message: es.admin.users.actions.toggleStatusFailure,
|
||||
})
|
||||
})
|
||||
|
||||
it("returns a localized toggle status success message and revalidates", async () => {
|
||||
mocks.setUserActiveUseCase.mockResolvedValue({ success: true })
|
||||
|
||||
const result = await setUserActiveAction({
|
||||
id: "user-1",
|
||||
isActive: false,
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
success: true,
|
||||
message: es.admin.users.actions.toggleStatusSuccess,
|
||||
})
|
||||
expect(mocks.revalidatePath).toHaveBeenCalledWith("/admin/users")
|
||||
})
|
||||
})
|
||||
|
||||
describe("resetUserPasswordAction", () => {
|
||||
it("returns localized schema validation errors for invalid input", async () => {
|
||||
const result = await resetUserPasswordAction({
|
||||
id: "",
|
||||
password: "short",
|
||||
})
|
||||
|
||||
expect(mocks.getI18n).toHaveBeenCalledOnce()
|
||||
expect(mocks.resetUserPasswordUseCase).not.toHaveBeenCalled()
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
errors: {
|
||||
id: [es.admin.users.schema.userIdRequired],
|
||||
password: [es.admin.users.schema.passwordMinLength],
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it("localizes mapped use-case errors for reset failures", async () => {
|
||||
mocks.resetUserPasswordUseCase.mockResolvedValue({
|
||||
success: false,
|
||||
errors: { id: ["User not found"] },
|
||||
})
|
||||
|
||||
const result = await resetUserPasswordAction({
|
||||
id: "nonexistent",
|
||||
password: "newpassword1",
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
success: false,
|
||||
errors: {
|
||||
id: [es.admin.users.actions.notFound],
|
||||
},
|
||||
message: es.admin.users.actions.resetPasswordFailure,
|
||||
})
|
||||
})
|
||||
|
||||
it("returns a localized reset success message and revalidates", async () => {
|
||||
mocks.resetUserPasswordUseCase.mockResolvedValue({ success: true })
|
||||
|
||||
const result = await resetUserPasswordAction({
|
||||
id: "user-1",
|
||||
password: "newpassword1",
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
success: true,
|
||||
message: es.admin.users.actions.resetPasswordSuccess,
|
||||
})
|
||||
expect(mocks.revalidatePath).toHaveBeenCalledWith("/admin/users")
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user