db management fix
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.mock('../../lib/prisma', () => ({
|
||||
prisma: {
|
||||
adminUser: {
|
||||
findFirst: vi.fn(),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
import { prisma } from '../../lib/prisma'
|
||||
import { findAdminByEmail } from './admin.repo'
|
||||
|
||||
describe('admin.repo', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('looks up admin email case-insensitively', async () => {
|
||||
await findAdminByEmail('Admin@Example.com')
|
||||
|
||||
expect(prisma.adminUser.findFirst).toHaveBeenCalledWith({
|
||||
where: {
|
||||
email: {
|
||||
equals: 'Admin@Example.com',
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -31,7 +31,14 @@ function parseOptionalDate(value?: string | null) {
|
||||
}
|
||||
|
||||
export function findAdminByEmail(email: string) {
|
||||
return prisma.adminUser.findUnique({ where: { email } })
|
||||
return prisma.adminUser.findFirst({
|
||||
where: {
|
||||
email: {
|
||||
equals: email,
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function findAdminByIdOrThrow(id: string) {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.mock('./admin.repo', () => ({
|
||||
findAdminByEmail: vi.fn(),
|
||||
setAdminPasswordReset: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('../../services/notificationService', () => ({
|
||||
sendTransactionalEmail: vi.fn().mockResolvedValue(undefined),
|
||||
}))
|
||||
|
||||
import * as repo from './admin.repo'
|
||||
import { sendTransactionalEmail } from '../../services/notificationService'
|
||||
import { forgotPassword } from './admin.service'
|
||||
|
||||
describe('admin.service forgotPassword', () => {
|
||||
const originalAdminUrl = process.env.ADMIN_URL
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
process.env.ADMIN_URL = 'http://localhost:3002'
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
process.env.ADMIN_URL = originalAdminUrl
|
||||
})
|
||||
|
||||
it('sends the reset email to the canonical stored admin address', async () => {
|
||||
vi.mocked(repo.findAdminByEmail).mockResolvedValue({
|
||||
id: 'admin_1',
|
||||
email: 'admin@rentaldrivego.com',
|
||||
firstName: 'Samir',
|
||||
isActive: true,
|
||||
} as any)
|
||||
|
||||
await forgotPassword('Admin@RentalDriveGo.com')
|
||||
|
||||
expect(repo.setAdminPasswordReset).toHaveBeenCalledWith(
|
||||
'admin_1',
|
||||
expect.any(String),
|
||||
expect.any(Date),
|
||||
)
|
||||
expect(sendTransactionalEmail).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
to: 'admin@rentaldrivego.com',
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -93,7 +93,7 @@ export async function forgotPassword(email: string) {
|
||||
const resetUrl = `${adminUrl}/reset-password?token=${rawToken}`
|
||||
|
||||
await sendTransactionalEmail({
|
||||
to: email,
|
||||
to: admin.email,
|
||||
subject: 'Reset your RentalDriveGo admin password',
|
||||
html: `<p>Hi ${admin.firstName},</p><p><a href="${resetUrl}">Reset password</a></p><p>Expires in ${ADMIN_RESET_TTL_MINUTES} minutes.</p>`,
|
||||
text: `Hi ${admin.firstName},\n\nReset here: ${resetUrl}\n\nExpires in ${ADMIN_RESET_TTL_MINUTES} minutes.`,
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.mock('../../lib/prisma', () => ({
|
||||
prisma: {
|
||||
employee: {
|
||||
findFirst: vi.fn(),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
import { prisma } from '../../lib/prisma'
|
||||
import { findActiveEmployeeByEmail, findEmployeeWithCompanyByEmail } from './auth.employee.repo'
|
||||
|
||||
describe('auth.employee.repo', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('looks up employee login email case-insensitively', async () => {
|
||||
await findEmployeeWithCompanyByEmail('Owner@Example.com')
|
||||
|
||||
expect(prisma.employee.findFirst).toHaveBeenCalledWith({
|
||||
where: {
|
||||
email: {
|
||||
equals: 'Owner@Example.com',
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
include: { company: true },
|
||||
})
|
||||
})
|
||||
|
||||
it('looks up active employee reset email case-insensitively', async () => {
|
||||
await findActiveEmployeeByEmail('Owner@Example.com')
|
||||
|
||||
expect(prisma.employee.findFirst).toHaveBeenCalledWith({
|
||||
where: {
|
||||
email: {
|
||||
equals: 'Owner@Example.com',
|
||||
mode: 'insensitive',
|
||||
},
|
||||
isActive: true,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -9,14 +9,25 @@ export function findEmployeeWithCompanyById(id: string) {
|
||||
|
||||
export function findEmployeeWithCompanyByEmail(email: string) {
|
||||
return prisma.employee.findFirst({
|
||||
where: { email },
|
||||
where: {
|
||||
email: {
|
||||
equals: email,
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
include: { company: true },
|
||||
})
|
||||
}
|
||||
|
||||
export function findActiveEmployeeByEmail(email: string) {
|
||||
return prisma.employee.findFirst({
|
||||
where: { email, isActive: true },
|
||||
where: {
|
||||
email: {
|
||||
equals: email,
|
||||
mode: 'insensitive',
|
||||
},
|
||||
isActive: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.mock('./auth.employee.repo', () => ({
|
||||
findActiveEmployeeByEmail: vi.fn(),
|
||||
setPasswordResetToken: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('../../services/notificationService', () => ({
|
||||
sendTransactionalEmail: vi.fn().mockResolvedValue(undefined),
|
||||
}))
|
||||
|
||||
import * as repo from './auth.employee.repo'
|
||||
import { sendTransactionalEmail } from '../../services/notificationService'
|
||||
import { forgotPassword } from './auth.employee.service'
|
||||
|
||||
describe('auth.employee.service forgotPassword', () => {
|
||||
const originalDashboardUrl = process.env.DASHBOARD_URL
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
process.env.DASHBOARD_URL = 'http://localhost:3001'
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
process.env.DASHBOARD_URL = originalDashboardUrl
|
||||
})
|
||||
|
||||
it('sends the reset email to the canonical stored address', async () => {
|
||||
vi.mocked(repo.findActiveEmployeeByEmail).mockResolvedValue({
|
||||
id: 'emp_1',
|
||||
email: 'owner@company.com',
|
||||
firstName: 'Aya',
|
||||
preferredLanguage: 'en',
|
||||
} as any)
|
||||
|
||||
await forgotPassword('Owner@Company.com')
|
||||
|
||||
expect(repo.setPasswordResetToken).toHaveBeenCalledWith(
|
||||
'emp_1',
|
||||
expect.any(String),
|
||||
expect.any(Date),
|
||||
)
|
||||
expect(sendTransactionalEmail).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
to: 'owner@company.com',
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -78,7 +78,7 @@ export async function forgotPassword(email: string) {
|
||||
const lang = (employee.preferredLanguage as Lang) ?? 'fr'
|
||||
|
||||
await sendTransactionalEmail({
|
||||
to: email,
|
||||
to: employee.email,
|
||||
subject: resetPasswordEmail.subject(lang),
|
||||
html: resetPasswordEmail.html(resetUrl, employee.firstName, RESET_TOKEN_TTL_MINUTES, lang),
|
||||
text: resetPasswordEmail.text(resetUrl, employee.firstName, RESET_TOKEN_TTL_MINUTES, lang),
|
||||
|
||||
Reference in New Issue
Block a user