- git rm AdminView.vue, AdminUsersTab.vue, AdminQuotasTab.vue, AdminAiConfigTab.vue, AuditLogTab.vue - Migrate tab tests to import from views/admin/Admin*View.vue - Update router.guard.test.js: replace AdminView mock with AdminLayout + 5 admin view mocks - Add D-09 redirect test (admin on / → /admin) - Fix stale api/admin.js JSDoc consumer list - Fix SettingsView.vue stale AdminView comment reference
148 lines
4.5 KiB
JavaScript
148 lines
4.5 KiB
JavaScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { mount, flushPromises } from '@vue/test-utils'
|
|
|
|
// Mock api/client.js
|
|
vi.mock('../../../api/client.js', () => ({
|
|
adminListUsers: vi.fn(),
|
|
adminGetUserQuota: vi.fn(),
|
|
adminUpdateQuota: vi.fn(),
|
|
}))
|
|
|
|
import AdminQuotasTab from '../../../views/admin/AdminQuotasView.vue'
|
|
import * as api from '../../../api/client.js'
|
|
|
|
const MB = 1048576
|
|
|
|
function makeUser(id, email) {
|
|
return { id, email, handle: email.split('@')[0], role: 'user', is_active: true }
|
|
}
|
|
|
|
function makeQuota(userId, usedMB, limitMB) {
|
|
return {
|
|
user_id: userId,
|
|
used_bytes: usedMB * MB,
|
|
limit_bytes: limitMB * MB,
|
|
}
|
|
}
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
// ── onMounted: loads users + quotas ──────────────────────────────────────────
|
|
|
|
describe('AdminQuotasTab — onMounted', () => {
|
|
it('calls adminListUsers() on mount', async () => {
|
|
api.adminListUsers.mockResolvedValue({ items: [] })
|
|
mount(AdminQuotasTab)
|
|
await flushPromises()
|
|
expect(api.adminListUsers).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('shows "No users yet" empty state when API returns empty list', async () => {
|
|
api.adminListUsers.mockResolvedValue({ items: [] })
|
|
const w = mount(AdminQuotasTab)
|
|
await flushPromises()
|
|
expect(w.text()).toContain('No users yet')
|
|
})
|
|
|
|
it('calls adminGetUserQuota for each user', async () => {
|
|
api.adminListUsers.mockResolvedValue({
|
|
items: [makeUser('u1', 'alice@example.com'), makeUser('u2', 'bob@example.com')],
|
|
})
|
|
api.adminGetUserQuota
|
|
.mockResolvedValueOnce(makeQuota('u1', 10, 100))
|
|
.mockResolvedValueOnce(makeQuota('u2', 50, 200))
|
|
|
|
mount(AdminQuotasTab)
|
|
await flushPromises()
|
|
|
|
expect(api.adminGetUserQuota).toHaveBeenCalledWith('u1')
|
|
expect(api.adminGetUserQuota).toHaveBeenCalledWith('u2')
|
|
})
|
|
|
|
it('displays quota data in the table', async () => {
|
|
api.adminListUsers.mockResolvedValue({
|
|
items: [makeUser('u1', 'alice@example.com')],
|
|
})
|
|
api.adminGetUserQuota.mockResolvedValue(makeQuota('u1', 10, 100))
|
|
|
|
const w = mount(AdminQuotasTab)
|
|
await flushPromises()
|
|
|
|
expect(w.text()).toContain('alice@example.com')
|
|
// 10 MB used, 100 MB limit
|
|
expect(w.text()).toContain('10 MB')
|
|
expect(w.text()).toContain('100 MB')
|
|
})
|
|
})
|
|
|
|
// ── saveQuota: calls adminUpdateQuota(id, bytes) ──────────────────────────────
|
|
|
|
describe('AdminQuotasTab — saveQuota', () => {
|
|
it('calls adminUpdateQuota with user id and new limit in bytes on save', async () => {
|
|
api.adminListUsers.mockResolvedValue({
|
|
items: [makeUser('u1', 'alice@example.com')],
|
|
})
|
|
api.adminGetUserQuota.mockResolvedValue(makeQuota('u1', 10, 100))
|
|
api.adminUpdateQuota.mockResolvedValue({
|
|
user_id: 'u1',
|
|
used_bytes: 10 * MB,
|
|
limit_bytes: 200 * MB,
|
|
warning: false,
|
|
})
|
|
|
|
const w = mount(AdminQuotasTab)
|
|
await flushPromises()
|
|
|
|
// Click "Edit" button
|
|
const editBtn = w.find('button')
|
|
expect(editBtn.text()).toContain('Edit')
|
|
await editBtn.trigger('click')
|
|
await w.vm.$nextTick()
|
|
|
|
// Change the limit input to 200 MB
|
|
const input = w.find('input[type="number"]')
|
|
await input.setValue(200)
|
|
|
|
// Click "Save"
|
|
const saveBtn = w.findAll('button').find(b => b.text().includes('Save'))
|
|
await saveBtn.trigger('click')
|
|
await flushPromises()
|
|
|
|
expect(api.adminUpdateQuota).toHaveBeenCalledWith('u1', 200 * MB)
|
|
})
|
|
|
|
it('shows warning text when API response has warning: true', async () => {
|
|
api.adminListUsers.mockResolvedValue({
|
|
items: [makeUser('u1', 'alice@example.com')],
|
|
})
|
|
api.adminGetUserQuota.mockResolvedValue(makeQuota('u1', 90, 100))
|
|
api.adminUpdateQuota.mockResolvedValue({
|
|
user_id: 'u1',
|
|
used_bytes: 90 * MB,
|
|
limit_bytes: 50 * MB, // below current usage
|
|
warning: true,
|
|
})
|
|
|
|
const w = mount(AdminQuotasTab)
|
|
await flushPromises()
|
|
|
|
// Enter edit mode
|
|
await w.find('button').trigger('click')
|
|
await w.vm.$nextTick()
|
|
|
|
// Set limit below current usage
|
|
const input = w.find('input[type="number"]')
|
|
await input.setValue(50)
|
|
|
|
// Save
|
|
const saveBtn = w.findAll('button').find(b => b.text().includes('Save'))
|
|
await saveBtn.trigger('click')
|
|
await flushPromises()
|
|
|
|
// Warning text must appear
|
|
expect(w.text()).toMatch(/below current usage|uploads will be blocked/i)
|
|
})
|
|
})
|