refac: DELETE /v1/user/{id}?expected_role_id=N, user.remove audit event, 409 target_role_not_found, GetAll returns its error, Own-scope visibility filter moved into repos, JSON tags removed from use-case types
This commit is contained in:
1 parent
5d6f378fce
commit
b39a41be88
124 files changed
+8816
-523
No files matched your search
@@ -0,0 +1,158 @@
|
||||
import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'
|
||||
import { initializeLocale, setLocale } from '@/i18n'
|
||||
import { customAccess } from '@/test/access'
|
||||
import {
|
||||
customTypes,
|
||||
eventEntries,
|
||||
installSelectPolyfills,
|
||||
listPage,
|
||||
lookupNames,
|
||||
mountList,
|
||||
text,
|
||||
unmountAll,
|
||||
} from './contentTestKit'
|
||||
import { failWithBody, mountEditor, main as editorMain } from './entryEditorKit'
|
||||
|
||||
vi.mock('@/composables/useApi', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/composables/useApi')>()
|
||||
return { ...actual, useApi: vi.fn() }
|
||||
})
|
||||
|
||||
beforeAll(installSelectPolyfills)
|
||||
|
||||
afterEach(async () => {
|
||||
localStorage.clear()
|
||||
initializeLocale()
|
||||
await unmountAll()
|
||||
})
|
||||
|
||||
const READ_OWN = 'content.read:events=own, content.create:events=all'
|
||||
const READ_ALL = 'content.read:events=all, content.create:events=all'
|
||||
|
||||
function main() {
|
||||
return document.body.querySelector('#dashboard-content')!
|
||||
}
|
||||
|
||||
function accessWith(spec: string) {
|
||||
return customAccess(spec, 'Junior writer')
|
||||
}
|
||||
|
||||
function newEntryButtons() {
|
||||
return [...main().querySelectorAll('button')].filter(
|
||||
(candidate) => text(candidate) === 'New entry',
|
||||
)
|
||||
}
|
||||
|
||||
const three = (_key: string, query: URLSearchParams) => listPage(eventEntries.slice(0, 3), 3, query)
|
||||
const none = (_key: string, query: URLSearchParams) => listPage([], 0, query)
|
||||
|
||||
describe('Entry list: Read = Own with entries of their own', () => {
|
||||
it('reads the header, the banner and the count line from the total', async () => {
|
||||
await mountList('/content/events', {
|
||||
access: accessWith(READ_OWN),
|
||||
list: three,
|
||||
lookup: lookupNames,
|
||||
})
|
||||
|
||||
expect(text(main())).toContain('Events')
|
||||
expect(text(main())).toContain('Your role shows only entries you created.')
|
||||
expect(text(main())).toContain("Entries by others aren't shown")
|
||||
expect(text(main())).toContain(
|
||||
'Your role reads only entries you created. Ask an owner or admin if you need to see more.',
|
||||
)
|
||||
expect(text(main())).toContain('3 entries')
|
||||
expect(main().querySelector('nav[aria-label*="pagination" i]')).toBeNull()
|
||||
expect(newEntryButtons().length).toBeGreaterThan(0)
|
||||
expect(newEntryButtons().every((button) => !button.disabled)).toBe(true)
|
||||
})
|
||||
|
||||
it('shows neither the banner nor the own-scope header under Read = All', async () => {
|
||||
await mountList('/content/events', {
|
||||
access: accessWith(READ_ALL),
|
||||
list: three,
|
||||
lookup: lookupNames,
|
||||
})
|
||||
|
||||
expect(text(main())).not.toContain("Entries by others aren't shown")
|
||||
expect(text(main())).not.toContain('Your role shows only entries you created.')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Entry list: Read = Own with no entries of their own', () => {
|
||||
it('says what the person has not created, without hinting at other entries', async () => {
|
||||
await mountList('/content/events', { access: accessWith(READ_OWN), list: none })
|
||||
|
||||
expect(text(main())).toContain("You haven't created an event yet")
|
||||
expect(text(main())).toContain(
|
||||
"Your role shows only entries you created, so other people's events aren't listed here. Use New entry to add one.",
|
||||
)
|
||||
expect(text(main())).not.toContain('No entries yet')
|
||||
expect(newEntryButtons().length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('hides the action when the role cannot create', async () => {
|
||||
await mountList('/content/events', {
|
||||
access: accessWith('content.read:events=own'),
|
||||
list: none,
|
||||
})
|
||||
|
||||
expect(text(main())).toContain("You haven't created an event yet")
|
||||
expect(newEntryButtons()).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('keeps the existing empty state under Read = All', async () => {
|
||||
await mountList('/content/events', { access: accessWith(READ_ALL), list: none })
|
||||
|
||||
expect(text(main())).toContain('No entries yet')
|
||||
expect(text(main())).not.toContain("You haven't created an event yet")
|
||||
})
|
||||
|
||||
it('reads in French', async () => {
|
||||
setLocale('fr')
|
||||
await mountList('/content/events', { access: accessWith(READ_OWN), list: none })
|
||||
|
||||
expect(text(main())).toContain('Vous n’avez pas encore créé d’entrée dans Events')
|
||||
expect(text(main())).toContain('Les entrées des autres ne sont pas affichées')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Entry list: the singular noun comes from the type name', () => {
|
||||
it.each([
|
||||
[
|
||||
'Recipes',
|
||||
"You haven't created a recipe yet",
|
||||
"other people's recipes aren't listed here",
|
||||
],
|
||||
[
|
||||
'Press mentions',
|
||||
"You haven't created a press mention yet",
|
||||
"other people's press mentions aren't listed here",
|
||||
],
|
||||
[
|
||||
'Categories',
|
||||
"You haven't created a category yet",
|
||||
"other people's categories aren't listed here",
|
||||
],
|
||||
])('%s', async (name, title, fragment) => {
|
||||
await mountList('/content/events', {
|
||||
access: accessWith(READ_OWN),
|
||||
list: none,
|
||||
type: () => ({ ...customTypes[0]!, name }),
|
||||
})
|
||||
|
||||
expect(text(main())).toContain(title)
|
||||
expect(text(main())).toContain(fragment)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Entry list: a direct link to a hidden entry', () => {
|
||||
it('shows the existing Entry not found page and nothing about the entry', async () => {
|
||||
await mountEditor('/content/events/1', {
|
||||
access: accessWith(READ_OWN),
|
||||
entry: failWithBody(404, 'entry_not_found'),
|
||||
})
|
||||
|
||||
expect(text(editorMain())).toContain('Entry not found')
|
||||
expect(text(editorMain())).not.toContain('created by')
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user