473 lines
21 KiB
JavaScript
473 lines
21 KiB
JavaScript
const { test } = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
const fs = require('node:fs')
|
|
const vm = require('node:vm')
|
|
const vue = require('vue')
|
|
const ts = require('../../backend/node_modules/typescript')
|
|
|
|
const deferred = () => {
|
|
let resolve
|
|
const promise = new Promise(done => { resolve = done })
|
|
return { promise, resolve }
|
|
}
|
|
const settle = () => new Promise(setImmediate)
|
|
|
|
function setup(api, apiBase = 'https://fedeo.example/backend') {
|
|
const auth = vue.reactive({ activeTenant: '1', user: { is_admin: true } })
|
|
const timers = new Map()
|
|
let timerId = 0
|
|
let mount
|
|
let unmount
|
|
let countRefreshes = 0
|
|
const context = vm.createContext({
|
|
require, exports: {}, URL, AbortController,
|
|
ref: vue.ref, computed: vue.computed, watch: vue.watch,
|
|
useAuthStore: () => auth,
|
|
useDocumentInboxCount: () => ({ refresh: async () => { countRefreshes++ } }),
|
|
useRuntimeConfig: () => ({ public: { apiBase } }),
|
|
useFiles: () => ({}), useToast: () => ({ add() {} }),
|
|
useNuxtApp: () => ({ $api: (url, options) => /\/assignments$/.test(url) ? Promise.resolve([]) : api(url, options) }),
|
|
window: { location: { origin: 'https://fedeo.example' } },
|
|
onMounted: handler => { mount = handler },
|
|
onBeforeUnmount: handler => { unmount = handler },
|
|
setTimeout: handler => { timers.set(++timerId, handler); return timerId },
|
|
clearTimeout: id => timers.delete(id),
|
|
})
|
|
const source = fs.readFileSync(`${__dirname}/../pages/organisation/dokumentenablage.vue`, 'utf8').match(/<script setup lang="ts">([\s\S]*?)<\/script>/)[1]
|
|
vm.runInContext(ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022, esModuleInterop: true } }).outputText, context)
|
|
return { auth, timers, mount, countRefreshes: () => countRefreshes, close: () => unmount(), run: code => vm.runInContext(code, context) }
|
|
}
|
|
|
|
test('scanner setup preserves absolute and relative backend prefixes', async t => {
|
|
for (const base of ['https://fedeo.example/backend/', '/backend']) {
|
|
const ui = setup(async () => ({ documents: [], total: 0 }), base)
|
|
t.after(ui.close)
|
|
ui.mount()
|
|
await settle()
|
|
assert.equal(ui.run('scannerUrl.value'), 'https://fedeo.example/backend/scanner-inbox/')
|
|
}
|
|
})
|
|
|
|
test('a slow response from the previous tenant cannot expose its documents', async t => {
|
|
const previous = deferred()
|
|
let calls = 0
|
|
const ui = setup(() => ++calls === 1 ? previous.promise : Promise.resolve({ documents: [{ id: 'tenant-2' }], total: 1 }))
|
|
t.after(ui.close)
|
|
ui.mount()
|
|
ui.auth.activeTenant = '2'
|
|
await settle()
|
|
previous.resolve({ documents: [{ id: 'tenant-1-secret' }], total: 1 })
|
|
await settle()
|
|
assert.equal(ui.run('documents.value[0].id'), 'tenant-2')
|
|
})
|
|
|
|
test('credential responses are discarded on tenant switches and passwords clear on closing', async t => {
|
|
const pending = deferred()
|
|
const ui = setup(url => url.endsWith('/credentials') ? pending.promise : Promise.resolve({ documents: [], total: 0, connection: null, path: '/scanner-inbox/' }))
|
|
t.after(ui.close)
|
|
ui.mount()
|
|
await ui.run('openSetup()')
|
|
const creation = ui.run('createCredentials()')
|
|
ui.auth.activeTenant = '2'
|
|
await settle()
|
|
pending.resolve({ connection: { username: 'previous-tenant', password: 'never-display', active: true }, path: '/scanner-inbox/' })
|
|
await creation
|
|
assert.equal(ui.run('password.value'), '')
|
|
assert.equal(ui.run('connection.value'), null)
|
|
assert.equal(ui.run('setupOpen.value'), false)
|
|
ui.run('setupOpen.value = true')
|
|
await settle()
|
|
ui.run('password.value = "shown-once"; setupOpen.value = false')
|
|
await settle()
|
|
assert.equal(ui.run('password.value'), '')
|
|
})
|
|
|
|
test('unmounting cancels polling and ignores in-flight responses', async () => {
|
|
const pending = deferred()
|
|
const ui = setup(() => pending.promise)
|
|
ui.mount()
|
|
ui.close()
|
|
pending.resolve({ documents: [{ id: 'late' }], total: 1 })
|
|
await settle()
|
|
assert.equal(ui.run('documents.value.length'), 0)
|
|
assert.equal(ui.timers.size, 0)
|
|
})
|
|
|
|
const filingOptions = {
|
|
folders: [
|
|
{ id: 'parent', name: 'Buchhaltung', parent: null, standardFiletype: null, standardFiletypeIsOptional: true },
|
|
{ id: 'folder', name: 'Rechnungen', parent: 'parent', standardFiletype: 'invoice', standardFiletypeIsOptional: false },
|
|
],
|
|
types: [{ id: 'invoice', name: 'Rechnung' }, { id: 'other', name: 'Sonstiges' }],
|
|
}
|
|
|
|
test('filing shows folder paths, requires a type and honours mandatory folder defaults', async t => {
|
|
const ui = setup(async () => filingOptions)
|
|
t.after(ui.close)
|
|
await ui.run('openFiling({ id: "scan", name: "scan.pdf" })')
|
|
assert.equal(ui.run('canFile.value'), false)
|
|
assert.equal(ui.run('folderOptions.value.find(folder => folder.id === "folder").name'), 'Buchhaltung / Rechnungen')
|
|
ui.run('filingFolder.value = "folder"')
|
|
await settle()
|
|
assert.equal(ui.run('filingType.value'), 'invoice')
|
|
assert.equal(ui.run('fixedType.value'), true)
|
|
assert.equal(ui.run('canFile.value'), true)
|
|
ui.run('filingType.value = "other"')
|
|
assert.equal(ui.run('canFile.value'), false)
|
|
ui.run('filingFolder.value = "root"')
|
|
await settle()
|
|
assert.equal(ui.run('fixedType.value'), false)
|
|
assert.equal(ui.run('canFile.value'), true)
|
|
})
|
|
|
|
test('successful filing sends folder and type, removes the entry and returns from an empty last page', async t => {
|
|
const pendingSave = deferred()
|
|
const requests = []
|
|
const ui = setup((url, options) => {
|
|
requests.push({ url, options })
|
|
if (url.endsWith('/filing-options')) return Promise.resolve(filingOptions)
|
|
if (url.endsWith('/file')) return pendingSave.promise
|
|
return Promise.resolve({ documents: [{ id: 'remaining' }], total: 50 })
|
|
})
|
|
t.after(ui.close)
|
|
ui.run('documents.value = [{ id: "scan", name: "scan.pdf" }]; total.value = 51; page.value = 2')
|
|
await ui.run('openFiling(documents.value[0])')
|
|
ui.run('filingType.value = "invoice"')
|
|
const saving = ui.run('fileDocument()')
|
|
await ui.run('fileDocument()')
|
|
assert.equal(requests.filter(item => item.url.endsWith('/file')).length, 1)
|
|
assert.equal(ui.run('documents.value.length'), 1, 'keeps the original until saving succeeds')
|
|
pendingSave.resolve({ id: 'scan' })
|
|
await saving
|
|
const post = requests.find(item => item.url.endsWith('/file'))
|
|
assert.equal(post.url, '/api/document-inbox/scan/file')
|
|
assert.equal(post.options.body.folder, null)
|
|
assert.equal(post.options.body.type, 'invoice')
|
|
assert.equal(ui.run('previewOpen.value'), false)
|
|
assert.equal(ui.run('page.value'), 1)
|
|
assert.equal(requests.at(-1).options.query.offset, 0)
|
|
assert.equal(ui.run('documents.value[0].id'), 'remaining')
|
|
})
|
|
|
|
test('filing failure preserves the document and selected values for retry', async t => {
|
|
const ui = setup(async url => {
|
|
if (url.endsWith('/file')) throw { data: { message: 'Ordner nicht verfügbar' } }
|
|
return filingOptions
|
|
})
|
|
t.after(ui.close)
|
|
ui.run('documents.value = [{ id: "scan", name: "scan.pdf" }]; total.value = 1')
|
|
await ui.run('openFiling(documents.value[0])')
|
|
ui.run('filingFolder.value = "folder"')
|
|
await settle()
|
|
await ui.run('fileDocument()')
|
|
assert.equal(ui.run('filingError.value'), 'Ordner nicht verfügbar')
|
|
assert.equal(ui.run('previewOpen.value'), true)
|
|
assert.equal(ui.run('filingType.value'), 'invoice')
|
|
assert.equal(ui.run('documents.value[0].id'), 'scan')
|
|
assert.equal(ui.run('canFile.value'), true)
|
|
})
|
|
|
|
test('archiving needs no classification, waits for confirmation and updates the list, preview and badge', async t => {
|
|
const pending = deferred()
|
|
const staleList = deferred()
|
|
const requests = []
|
|
let listings = 0
|
|
const ui = setup((url, options) => {
|
|
requests.push({ url, options })
|
|
if (url.endsWith('/archive')) return pending.promise
|
|
if (url.endsWith('/filing-options')) return Promise.resolve({ folders: [], types: [] })
|
|
if (url.endsWith('/suggestion')) return Promise.resolve({ status: 'pending', suggestion: null })
|
|
if (++listings === 1) return staleList.promise
|
|
return Promise.resolve({ documents: [{ id: 'remaining' }], total: 50 })
|
|
})
|
|
t.after(ui.close)
|
|
ui.run('documents.value = [{ id: "scan", name: "scan.pdf" }]; total.value = 51; page.value = 2')
|
|
await ui.run('openPreview(documents.value[0])')
|
|
await settle()
|
|
assert.equal(ui.run('canFile.value'), false)
|
|
ui.run('openArchive(documents.value[0])')
|
|
assert.equal(requests.some(request => request.url.endsWith('/archive')), false)
|
|
const listing = ui.run('load(true)')
|
|
const saving = ui.run('archiveDocument()')
|
|
await ui.run('archiveDocument()')
|
|
await ui.run('fileDocument()')
|
|
assert.equal(requests.filter(request => request.url.endsWith('/archive')).length, 1)
|
|
assert.equal(requests.some(request => request.url.endsWith('/file')), false)
|
|
assert.equal(ui.run('documents.value.length'), 1)
|
|
pending.resolve({ id: 'scan', archived: true })
|
|
await saving
|
|
staleList.resolve({ documents: [{ id: 'scan' }], total: 51 })
|
|
await listing
|
|
assert.equal(requests.find(request => request.url.endsWith('/archive')).options.method, 'POST')
|
|
assert.equal(ui.run('archiveOpen.value'), false)
|
|
assert.equal(ui.run('previewOpen.value'), false)
|
|
assert.equal(ui.run('documents.value[0].id'), 'remaining')
|
|
assert.equal(ui.run('total.value'), 50)
|
|
assert.equal(ui.run('page.value'), 1)
|
|
assert.equal(ui.countRefreshes(), 1)
|
|
})
|
|
|
|
test('archive cancellation and failure preserve the document and allow a retry from the list', async t => {
|
|
let calls = 0
|
|
const ui = setup(async () => { calls++; throw { data: { message: 'Archivieren fehlgeschlagen' } } })
|
|
t.after(ui.close)
|
|
ui.run('documents.value = [{ id: "scan", name: "scan.pdf" }]; total.value = 1; openArchive(documents.value[0])')
|
|
await settle()
|
|
ui.run('archiveOpen.value = false')
|
|
await settle()
|
|
assert.equal(ui.run('archiveTarget.value'), null)
|
|
assert.equal(calls, 0)
|
|
ui.run('openArchive(documents.value[0])')
|
|
await ui.run('archiveDocument()')
|
|
assert.equal(ui.run('archiveError.value'), 'Archivieren fehlgeschlagen')
|
|
assert.equal(ui.run('archiveOpen.value'), true)
|
|
assert.equal(ui.run('archiveSaving.value'), false)
|
|
assert.equal(ui.run('documents.value[0].id'), 'scan')
|
|
assert.equal(ui.run('total.value'), 1)
|
|
assert.equal(ui.countRefreshes(), 0)
|
|
})
|
|
|
|
test('archive responses from a previous tenant or unmounted page cannot update the current view', async t => {
|
|
for (const action of ['tenant', 'unmount']) {
|
|
const pending = deferred()
|
|
const ui = setup(url => url.endsWith('/archive') ? pending.promise : Promise.resolve({ documents: [{ id: 'tenant-2' }], total: 1 }))
|
|
t.after(ui.close)
|
|
ui.run('documents.value = [{ id: "scan", name: "scan.pdf" }]; total.value = 1; openArchive(documents.value[0])')
|
|
const saving = ui.run('archiveDocument()')
|
|
if (action === 'tenant') ui.auth.activeTenant = '2'
|
|
else ui.close()
|
|
await settle()
|
|
pending.resolve({ id: 'scan', archived: true })
|
|
await saving
|
|
assert.equal(ui.run('documents.value[0].id'), action === 'tenant' ? 'tenant-2' : 'scan')
|
|
assert.equal(ui.countRefreshes(), 0)
|
|
if (action === 'tenant') assert.equal(ui.run('archiveOpen.value'), false)
|
|
}
|
|
})
|
|
|
|
test('tenant switching discards pending folder options and filing responses', async t => {
|
|
for (const stage of ['options', 'save']) {
|
|
const pending = deferred()
|
|
const ui = setup(url => {
|
|
if (url.endsWith('/filing-options')) return stage === 'options' ? pending.promise : Promise.resolve(filingOptions)
|
|
if (url.endsWith('/file')) return pending.promise
|
|
return Promise.resolve({ documents: [{ id: 'tenant-2' }], total: 1 })
|
|
})
|
|
t.after(ui.close)
|
|
let operation = ui.run('openFiling({ id: "scan", name: "scan.pdf" })')
|
|
if (stage === 'save') {
|
|
await operation
|
|
ui.run('filingType.value = "invoice"')
|
|
operation = ui.run('fileDocument()')
|
|
}
|
|
ui.auth.activeTenant = '2'
|
|
await settle()
|
|
pending.resolve(stage === 'options' ? filingOptions : { id: 'scan' })
|
|
await operation
|
|
assert.equal(ui.run('previewOpen.value'), false)
|
|
assert.equal(ui.run('filingFolders.value.length'), 0)
|
|
assert.equal(ui.run('filingTypes.value.length'), 0)
|
|
assert.equal(ui.run('documents.value[0].id'), 'tenant-2')
|
|
}
|
|
})
|
|
|
|
const aiSuggestion = { folderId: 'folder', typeId: 'invoice', confidence: 'high', reason: 'Rechnung erkannt.' }
|
|
|
|
test('AI preselection only files the document after confirmation and reads the prepared result without triggering AI', async t => {
|
|
const requests = []
|
|
const ui = setup(async (url, options) => {
|
|
requests.push({ url, options })
|
|
if (url.endsWith('/filing-options')) return filingOptions
|
|
if (url.endsWith('/suggestion')) return { status: 'ready', suggestion: aiSuggestion }
|
|
if (url.endsWith('/file')) return { id: 'scan' }
|
|
return { documents: [], total: 0 }
|
|
})
|
|
t.after(ui.close)
|
|
await ui.run('openPreview({ id: "scan", name: "scan.pdf" })')
|
|
await settle()
|
|
assert.equal(ui.run('filingFolder.value'), 'folder')
|
|
assert.equal(ui.run('filingType.value'), 'invoice')
|
|
assert.equal(ui.run('canFile.value'), true)
|
|
assert.equal(requests.some(request => request.url.endsWith('/file')), false)
|
|
ui.run('previewOpen.value = false')
|
|
await settle()
|
|
await ui.run('openPreview({ id: "scan", name: "scan.pdf" })')
|
|
await settle()
|
|
assert.equal(requests.filter(request => request.url.endsWith('/suggestion')).length, 2)
|
|
assert.ok(requests.filter(request => request.url.endsWith('/suggestion')).every(request => request.options.method === 'GET'))
|
|
await ui.run('fileDocument()')
|
|
const save = requests.find(request => request.url.endsWith('/file'))
|
|
assert.equal(save.options.body.folder, 'folder')
|
|
assert.equal(save.options.body.type, 'invoice')
|
|
assert.equal(ui.run('previewOpen.value'), false)
|
|
assert.equal(ui.countRefreshes(), 1)
|
|
})
|
|
|
|
test('late AI results preserve manual choices, and can still be explicitly applied', async t => {
|
|
const pending = deferred()
|
|
const ui = setup(url => url.endsWith('/suggestion') ? pending.promise : Promise.resolve(filingOptions))
|
|
t.after(ui.close)
|
|
await ui.run('openPreview({ id: "scan", name: "scan.pdf" })')
|
|
ui.run('filingType.value = "other"; selectionTouched.value = true')
|
|
pending.resolve({ status: 'ready', suggestion: aiSuggestion })
|
|
await settle()
|
|
assert.equal(ui.run('filingFolder.value'), 'root')
|
|
assert.equal(ui.run('filingType.value'), 'other')
|
|
assert.equal(ui.run('suggestion.value.typeId'), 'invoice')
|
|
ui.run('applySuggestion()')
|
|
assert.equal(ui.run('filingFolder.value'), 'folder')
|
|
assert.equal(ui.run('filingType.value'), 'invoice')
|
|
})
|
|
|
|
test('closing, changing documents or switching tenant cancels and discards pending AI responses', async t => {
|
|
for (const action of ['close', 'document', 'tenant', 'unmount']) {
|
|
const pending = deferred()
|
|
const signals = []
|
|
const ui = setup((url, options) => {
|
|
if (url.endsWith('/suggestion')) { signals.push(options.signal); return pending.promise }
|
|
if (url.endsWith('/filing-options')) return Promise.resolve(filingOptions)
|
|
return Promise.resolve({ documents: [], total: 0 })
|
|
})
|
|
t.after(ui.close)
|
|
await ui.run('openPreview({ id: "scan", name: "scan.pdf" })')
|
|
if (action === 'close') ui.run('previewOpen.value = false')
|
|
if (action === 'tenant') ui.auth.activeTenant = '2'
|
|
if (action === 'document') await ui.run('openPreview({ id: "next", name: "next.pdf" })')
|
|
if (action === 'unmount') ui.close()
|
|
await settle()
|
|
assert.equal(signals[0].aborted, true)
|
|
// Keep the replacement document's request separate from the stale first result.
|
|
if (action === 'document') ui.run('previewOpen.value = false')
|
|
await settle()
|
|
pending.resolve({ status: 'ready', suggestion: aiSuggestion })
|
|
await settle()
|
|
assert.equal(ui.run('suggestion.value'), null)
|
|
}
|
|
})
|
|
|
|
test('AI failures leave manual filing available and optional folder defaults do not overwrite the AI type', async t => {
|
|
const ui = setup(async url => {
|
|
if (url.endsWith('/suggestion')) throw { data: { message: 'KI nicht verfügbar' } }
|
|
return filingOptions
|
|
})
|
|
t.after(ui.close)
|
|
await ui.run('openPreview({ id: "scan", name: "scan.pdf" })')
|
|
await settle()
|
|
assert.equal(ui.run('suggestionError.value'), 'KI nicht verfügbar')
|
|
ui.run('filingType.value = "other"')
|
|
assert.equal(ui.run('canFile.value'), true)
|
|
ui.run('filingFolders.value[1].standardFiletypeIsOptional = true; suggestion.value = { folderId: "folder", typeId: "other" }; applySuggestion()')
|
|
await settle()
|
|
assert.equal(ui.run('filingType.value'), 'other')
|
|
})
|
|
|
|
test('pending preparation is polled, preserves manual choices and only explicit refresh queues work', async t => {
|
|
const requests = []
|
|
let state = 'pending'
|
|
const ui = setup(async (url, options) => {
|
|
if (url.endsWith('/filing-options')) return filingOptions
|
|
requests.push(options.method)
|
|
return { status: state, suggestion: state === 'ready' ? aiSuggestion : null }
|
|
})
|
|
t.after(ui.close)
|
|
await ui.run('openPreview({ id: "scan", name: "scan.pdf" })')
|
|
await settle()
|
|
assert.equal(ui.run('suggestionStatus.value'), 'pending')
|
|
assert.equal(ui.run('suggestion.value'), null)
|
|
assert.equal(ui.timers.size, 1)
|
|
ui.run('filingType.value = "other"; selectionTouched.value = true')
|
|
state = 'ready'
|
|
await ui.run('loadFilingSuggestion()')
|
|
assert.equal(ui.run('filingType.value'), 'other')
|
|
assert.equal(ui.run('suggestion.value.typeId'), 'invoice')
|
|
assert.equal(ui.timers.size, 0)
|
|
await ui.run('loadFilingSuggestion(true)')
|
|
assert.deepEqual(requests, ['GET', 'GET', 'POST'])
|
|
})
|
|
|
|
test('preparation polling resumes when a concurrent manual filing attempt fails', async t => {
|
|
const save = deferred()
|
|
let state = 'processing'
|
|
const ui = setup(async url => {
|
|
if (url.endsWith('/filing-options')) return filingOptions
|
|
if (url.endsWith('/suggestion')) return { status: state, suggestion: state === 'ready' ? aiSuggestion : null }
|
|
if (url.endsWith('/file')) { await save.promise; throw { data: { error: 'Bitte erneut versuchen' } } }
|
|
})
|
|
t.after(ui.close)
|
|
const tick = async () => {
|
|
assert.equal(ui.timers.size, 1)
|
|
const [id, callback] = [...ui.timers][0]
|
|
ui.timers.delete(id)
|
|
await callback()
|
|
}
|
|
await ui.run('openPreview({ id: "scan", name: "scan.pdf" })')
|
|
await settle()
|
|
ui.run('filingType.value = "other"; selectionTouched.value = true')
|
|
const filing = ui.run('fileDocument()')
|
|
await tick()
|
|
assert.equal(ui.timers.size, 1, 'polling remains scheduled while filing is in progress')
|
|
save.resolve()
|
|
await filing
|
|
assert.equal(ui.run('previewOpen.value'), true)
|
|
state = 'ready'
|
|
await tick()
|
|
assert.equal(ui.run('suggestion.value.typeId'), 'invoice')
|
|
assert.equal(ui.run('filingType.value'), 'other')
|
|
assert.equal(ui.timers.size, 0)
|
|
})
|
|
|
|
test('entity assignments are submitted together with filing and search reset preserves a selected item', async t => {
|
|
const requests = []
|
|
const ui = setup(async (url, options) => {
|
|
requests.push({ url, options })
|
|
if (url.endsWith('/filing-options')) return { ...filingOptions, assignmentKinds: [{ value: 'project', label: 'Projekt' }, { value: 'customer', label: 'Kunde' }] }
|
|
if (url.endsWith('/assignment-options')) return [{ id: '11', name: 'Umbau' }]
|
|
if (url.endsWith('/suggestion')) return { status: 'ready', suggestion: aiSuggestion }
|
|
if (url.endsWith('/file')) return { id: 'scan' }
|
|
return { documents: [], total: 0 }
|
|
})
|
|
t.after(ui.close)
|
|
await ui.run('openPreview({ id: "scan", name: "scan.pdf" })')
|
|
await settle()
|
|
ui.run('assignmentSearch.value = "Umbau"')
|
|
await settle()
|
|
await ui.run('loadAssignmentOptions()')
|
|
ui.run('assignmentId.value = "11"; assignmentSearch.value = ""')
|
|
await settle()
|
|
assert.equal(ui.run('assignmentId.value'), '11')
|
|
ui.run('addAssignment()')
|
|
assert.equal(ui.run('assignments.value[0].name'), 'Umbau')
|
|
assert.equal(requests.some(request => request.url.endsWith('/file')), false)
|
|
ui.run('assignmentKind.value = "customer"')
|
|
await settle()
|
|
ui.run('assignmentOptions.value = [{ id: "21", name: "Kunde" }]; assignmentId.value = "21"; assignmentLoading.value = false; addAssignment(); removeAssignment("project")')
|
|
await ui.run('fileDocument()')
|
|
const saved = requests.find(request => request.url.endsWith('/file'))
|
|
assert.equal(saved.options.body.assignments.project, null)
|
|
assert.equal(saved.options.body.assignments.customer, '21')
|
|
assert.equal(saved.options.body.folder, 'folder')
|
|
assert.equal(saved.options.body.type, 'invoice')
|
|
assert.equal(ui.countRefreshes(), 1)
|
|
})
|
|
|
|
test('old entity search responses are discarded on category and tenant changes', async t => {
|
|
const pending = deferred()
|
|
const ui = setup(url => {
|
|
if (url.endsWith('/filing-options')) return Promise.resolve({ ...filingOptions, assignmentKinds: [{ value: 'project', label: 'Projekt' }, { value: 'customer', label: 'Kunde' }] })
|
|
if (url.endsWith('/assignment-options')) return pending.promise
|
|
if (url.endsWith('/suggestion')) return Promise.resolve({ status: 'ready', suggestion: null })
|
|
return Promise.resolve({ documents: [], total: 0 })
|
|
})
|
|
t.after(ui.close)
|
|
await ui.run('openPreview({ id: "scan", name: "scan.pdf" })')
|
|
ui.run('assignmentKind.value = "customer"')
|
|
await settle()
|
|
ui.auth.activeTenant = '2'
|
|
await settle()
|
|
pending.resolve([{ id: 'foreign', name: 'Previous tenant project' }])
|
|
await settle()
|
|
assert.equal(ui.run('assignmentOptions.value.length'), 0)
|
|
assert.equal(ui.run('assignments.value.length'), 0)
|
|
assert.equal(ui.timers.size, 1, 'only the inbox list polling remains')
|
|
})
|