Add seed data initialization tests

This commit is contained in:
2025-12-25 16:26:53 +00:00
parent 98e378ade8
commit 0e91d25ddf
6 changed files with 371 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'
const {
initializeUsers,
initializeComponents,
initializeScripts,
initializeWorkflows,
initializePages,
initializePackages,
} = vi.hoisted(() => ({
initializeUsers: vi.fn(),
initializeComponents: vi.fn(),
initializeScripts: vi.fn(),
initializeWorkflows: vi.fn(),
initializePages: vi.fn(),
initializePackages: vi.fn(),
}))
vi.mock('./users', () => ({ initializeUsers }))
vi.mock('./components', () => ({ initializeComponents }))
vi.mock('./scripts', () => ({ initializeScripts }))
vi.mock('./workflows', () => ({ initializeWorkflows }))
vi.mock('./pages', () => ({ initializePages }))
vi.mock('./packages', () => ({ initializePackages }))
import { initializeAllSeedData } from './index'
describe('initializeAllSeedData', () => {
beforeEach(() => {
initializeUsers.mockReset()
initializeComponents.mockReset()
initializeScripts.mockReset()
initializeWorkflows.mockReset()
initializePages.mockReset()
initializePackages.mockReset()
})
it.each([
{
name: 'run seeders in order',
errorStep: null as string | null,
expectedCalls: ['users', 'components', 'scripts', 'workflows', 'pages', 'packages'],
},
{
name: 'stop when a seeder fails',
errorStep: 'scripts',
expectedCalls: ['users', 'components', 'scripts'],
},
])('should $name', async ({ errorStep, expectedCalls }) => {
const callOrder: string[] = []
initializeUsers.mockImplementation(async () => callOrder.push('users'))
initializeComponents.mockImplementation(async () => callOrder.push('components'))
initializeScripts.mockImplementation(async () => {
callOrder.push('scripts')
if (errorStep === 'scripts') {
throw new Error('seed failed')
}
})
initializeWorkflows.mockImplementation(async () => callOrder.push('workflows'))
initializePages.mockImplementation(async () => callOrder.push('pages'))
initializePackages.mockImplementation(async () => callOrder.push('packages'))
if (errorStep) {
await expect(initializeAllSeedData()).rejects.toThrow('seed failed')
} else {
await expect(initializeAllSeedData()).resolves.toBeUndefined()
}
expect(callOrder).toEqual(expectedCalls)
})
})

View File

@@ -0,0 +1,32 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'
const { initializePackageSystem } = vi.hoisted(() => ({
initializePackageSystem: vi.fn(),
}))
vi.mock('@/lib/package-loader', () => ({
initializePackageSystem,
}))
import { initializePackages } from '@/seed-data/packages'
describe('initializePackages', () => {
beforeEach(() => {
initializePackageSystem.mockReset()
})
it.each([
{ name: 'resolve when initializer succeeds', error: null as Error | null },
{ name: 'propagate errors from initializer', error: new Error('init failed') },
])('should $name', async ({ error }) => {
if (error) {
initializePackageSystem.mockRejectedValueOnce(error)
await expect(initializePackages()).rejects.toThrow('init failed')
} else {
initializePackageSystem.mockResolvedValueOnce(undefined)
await expect(initializePackages()).resolves.toBeUndefined()
}
expect(initializePackageSystem).toHaveBeenCalledTimes(1)
})
})

View File

@@ -0,0 +1,60 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'
const { getPages } = vi.hoisted(() => ({
getPages: vi.fn(),
}))
const { initializeDefaultPages } = vi.hoisted(() => ({
initializeDefaultPages: vi.fn(),
}))
const { getPageDefinitionBuilder } = vi.hoisted(() => ({
getPageDefinitionBuilder: vi.fn(),
}))
vi.mock('@/lib/database', () => ({
Database: {
getPages,
},
}))
vi.mock('@/lib/page-definition-builder', () => ({
getPageDefinitionBuilder,
}))
import { initializePages } from '@/seed-data/pages'
describe('initializePages', () => {
beforeEach(() => {
getPages.mockReset()
getPageDefinitionBuilder.mockReset()
initializeDefaultPages.mockReset()
})
it.each([
{
name: 'skip initialization when pages exist',
existingPages: [{ id: 'page1' }],
shouldInitialize: false,
},
{
name: 'initialize defaults when no pages exist',
existingPages: [],
shouldInitialize: true,
},
])('should $name', async ({ existingPages, shouldInitialize }) => {
getPages.mockResolvedValue(existingPages)
getPageDefinitionBuilder.mockReturnValue({ initializeDefaultPages })
await initializePages()
expect(getPages).toHaveBeenCalledTimes(1)
if (shouldInitialize) {
expect(getPageDefinitionBuilder).toHaveBeenCalledTimes(1)
expect(initializeDefaultPages).toHaveBeenCalledTimes(1)
} else {
expect(getPageDefinitionBuilder).not.toHaveBeenCalled()
expect(initializeDefaultPages).not.toHaveBeenCalled()
}
})
})

View File

@@ -0,0 +1,56 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'
const { getLuaScripts, addLuaScript } = vi.hoisted(() => ({
getLuaScripts: vi.fn(),
addLuaScript: vi.fn(),
}))
vi.mock('@/lib/database', () => ({
Database: {
getLuaScripts,
addLuaScript,
},
}))
import { initializeScripts } from '@/seed-data/scripts'
const expectedScriptIds = [
'script_welcome_message',
'script_format_date',
'script_validate_email',
'script_permission_check',
'script_page_load_analytics',
]
describe('initializeScripts', () => {
beforeEach(() => {
getLuaScripts.mockReset()
addLuaScript.mockReset()
})
it.each([
{
name: 'skip seeding when scripts exist',
existingScripts: [{ id: 'existing' }],
expectedAdds: 0,
},
{
name: 'seed default scripts when none exist',
existingScripts: [],
expectedAdds: expectedScriptIds.length,
},
])('should $name', async ({ existingScripts, expectedAdds }) => {
getLuaScripts.mockResolvedValue(existingScripts)
await initializeScripts()
expect(getLuaScripts).toHaveBeenCalledTimes(1)
expect(addLuaScript).toHaveBeenCalledTimes(expectedAdds)
if (expectedAdds > 0) {
expectedScriptIds.forEach(id => {
expect(addLuaScript).toHaveBeenCalledWith(expect.objectContaining({ id }))
})
}
})
})

View File

@@ -0,0 +1,98 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'
const {
getUsers,
setCredential,
setFirstLoginFlag,
addUser,
setGodCredentialsExpiry,
hashPassword,
} = vi.hoisted(() => ({
getUsers: vi.fn(),
setCredential: vi.fn(),
setFirstLoginFlag: vi.fn(),
addUser: vi.fn(),
setGodCredentialsExpiry: vi.fn(),
hashPassword: vi.fn(),
}))
const { getScrambledPassword } = vi.hoisted(() => ({
getScrambledPassword: vi.fn(),
}))
vi.mock('@/lib/database', () => ({
Database: {
getUsers,
setCredential,
setFirstLoginFlag,
addUser,
setGodCredentialsExpiry,
},
hashPassword,
}))
vi.mock('@/lib/auth', () => ({
getScrambledPassword,
}))
import { initializeUsers } from '@/seed-data/users'
const expectedUsernames = ['supergod', 'god', 'admin', 'alice', 'bob']
describe('initializeUsers', () => {
beforeEach(() => {
getUsers.mockReset()
setCredential.mockReset()
setFirstLoginFlag.mockReset()
addUser.mockReset()
setGodCredentialsExpiry.mockReset()
hashPassword.mockReset()
getScrambledPassword.mockReset()
})
it.each([
{
name: 'skip seeding when users exist',
existingUsers: [{ id: 'existing' }],
expectedAdds: 0,
},
{
name: 'seed users when none exist',
existingUsers: [],
expectedAdds: expectedUsernames.length,
},
])('should $name', async ({ existingUsers, expectedAdds }) => {
const nowSpy = vi.spyOn(Date, 'now').mockReturnValue(1000)
getUsers.mockResolvedValue(existingUsers)
getScrambledPassword.mockImplementation((username: string) => `scrambled-${username}`)
hashPassword.mockImplementation(async (value: string) => `hash-${value}`)
if (expectedAdds === 0) {
await initializeUsers()
} else {
await expect(initializeUsers()).resolves.toBeUndefined()
}
expect(getUsers).toHaveBeenCalledTimes(1)
expect(addUser).toHaveBeenCalledTimes(expectedAdds)
expect(setCredential).toHaveBeenCalledTimes(expectedAdds)
expect(setFirstLoginFlag).toHaveBeenCalledTimes(expectedAdds)
if (expectedAdds === 0) {
expect(getScrambledPassword).not.toHaveBeenCalled()
expect(hashPassword).not.toHaveBeenCalled()
expect(setGodCredentialsExpiry).not.toHaveBeenCalled()
} else {
expectedUsernames.forEach(username => {
expect(getScrambledPassword).toHaveBeenCalledWith(username)
expect(hashPassword).toHaveBeenCalledWith(`scrambled-${username}`)
expect(setCredential).toHaveBeenCalledWith(username, `hash-scrambled-${username}`)
expect(setFirstLoginFlag).toHaveBeenCalledWith(username, true)
expect(addUser).toHaveBeenCalledWith(expect.objectContaining({ username }))
})
expect(setGodCredentialsExpiry).toHaveBeenCalledWith(1000 + 60 * 60 * 1000)
}
nowSpy.mockRestore()
})
})

View File

@@ -0,0 +1,54 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'
const { getWorkflows, addWorkflow } = vi.hoisted(() => ({
getWorkflows: vi.fn(),
addWorkflow: vi.fn(),
}))
vi.mock('@/lib/database', () => ({
Database: {
getWorkflows,
addWorkflow,
},
}))
import { initializeWorkflows } from '@/seed-data/workflows'
const expectedWorkflowIds = [
'workflow_user_registration',
'workflow_page_access',
'workflow_comment_submission',
]
describe('initializeWorkflows', () => {
beforeEach(() => {
getWorkflows.mockReset()
addWorkflow.mockReset()
})
it.each([
{
name: 'skip seeding when workflows exist',
existingWorkflows: [{ id: 'existing' }],
expectedAdds: 0,
},
{
name: 'seed default workflows when none exist',
existingWorkflows: [],
expectedAdds: expectedWorkflowIds.length,
},
])('should $name', async ({ existingWorkflows, expectedAdds }) => {
getWorkflows.mockResolvedValue(existingWorkflows)
await initializeWorkflows()
expect(getWorkflows).toHaveBeenCalledTimes(1)
expect(addWorkflow).toHaveBeenCalledTimes(expectedAdds)
if (expectedAdds > 0) {
expectedWorkflowIds.forEach(id => {
expect(addWorkflow).toHaveBeenCalledWith(expect.objectContaining({ id }))
})
}
})
})