Files
Webklar-Kundenbereich/test/teamAdminRoutes.test.js
T

103 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, after } from 'node:test'
import assert from 'node:assert/strict'
import os from 'node:os'
import path from 'node:path'
import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs'
import { startAppwriteMock } from './support/appwriteMock.js'
import { startFakeStripe } from './support/fakeStripe.js'
import { useTestEnv } from './support/testEnv.js'
import { schemaKeys } from './support/schema.js'
import { mailSink } from './support/mailSink.js'
// Etappe 3: Gutschriften, Abo-Angebote, E-Mail-Speicher und Funktionen ueber den Team-Eingang (/api/team, JWT)
process.env.TAKEOVER_UPLOAD_DIR = mkdtempSync(path.join(os.tmpdir(), 'team-takeover-'))
const aw = await startAppwriteMock({
schema: {
subscriptions: schemaKeys('subscriptions'),
contractEvents: schemaKeys('contractEvents'),
takeoverCredits: schemaKeys('takeoverCredits'),
aboOffers: schemaKeys('aboOffers'),
portalFeatures: schemaKeys('portalFeatures'),
},
})
const st = await startFakeStripe()
useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url })
const { startTestApp, rawGet, post } = await import('./support/testApp.js')
const { seedFixtures, consent } = await import('./support/fixtures.js')
const { setMailTransportForTests } = await import('../server/services/mailer.js')
const { recordContractEvent } = await import('../server/services/contractEvents.js')
const { default: teamRoutes } = await import('../server/routes/team/index.js')
const app = await startTestApp({ '/api/team': teamRoutes })
setMailTransportForTests(mailSink())
after(() => {
setMailTransportForTests(null)
return Promise.all([app.close(), aw.close(), st.close()])
})
seedFixtures(aw)
aw.seed('employees', { $id: 'e_staff2', userId: 'u_staff2', displayName: 'Andrej', email: 'andrej@webklar.com' })
const credit = (id, customerId, status) =>
aw.seed('takeoverCredits', {
$id: id, customerId, email: 'k@example.invalid', services: JSON.stringify(['hosting']), provider: 'IONOS', domain: 'kunde.de',
invoiceAmountCents: 12000, billingMonths: 12, paidUntil: '2026-12-31T00:00:00.000Z', message: 'Bitte verrechnen',
files: '[]', status, history: '[]', takeoverFrom: '2026-10-01T00:00:00.000Z',
})
credit('tc1', 'c1', 'offen')
credit('tc2', 'c1', 'abgelehnt')
credit('tc3', 'c2', 'offen')
await recordContractEvent({
id: 'speicher-c2', customerId: 'c2', subscriptionId: 'sub_h2', type: 'speicher', productKey: 'hosting',
details: { kind: 'einrichten', fromUnits: 0, toUnits: 2, effectiveAt: new Date().toISOString(), totalGb: 15, monthlyCents: 200 },
consent, status: 'offen', dueAt: new Date().toISOString(),
})
aw.seed('websiteProjects', { $id: 'pa1', customerId: 'c1', projectName: 'Team-Test' })
const staff = { headers: { authorization: 'Bearer jwt-staff' } }
test('alle vier Bereiche mit jwt-staff erreichbar (kein Admin-Label noetig)', async () => {
for (const p of ['/api/team/takeover-credits', '/api/team/offers', '/api/team/storage-tasks', '/api/team/funktionen/c1']) {
assert.equal((await rawGet(p, staff)).status, 200, p)
}
})
test('Kundenfilter: Gutschriften nur des Kunden, openCount weiter ueber alle', async () => {
const all = (await rawGet('/api/team/takeover-credits?status=all&customerId=c1', staff)).body
assert.deepEqual(all.requests.map((r) => r.id).sort(), ['tc1', 'tc2'])
assert.equal(all.openCount, 2)
const open = (await rawGet('/api/team/takeover-credits?customerId=c2', staff)).body
assert.deepEqual(open.requests.map((r) => r.id), ['tc3'])
})
test('Angebot anlegen als Mitarbeiter, Kundenfilter der Angebotsliste', async () => {
const res = await post('/api/team/offers', { customerId: 'c2', productKey: 'wartung', monthlyPriceCents: 2500, months: 2, notifyCustomer: false }, staff)
assert.equal(res.status, 201, JSON.stringify(res.body))
assert.equal(res.body.offer.createdBy, 'Andrej <andrej@webklar.com>')
assert.deepEqual((await rawGet('/api/team/offers?customerId=c2', staff)).body.offers.map((o) => o.customerId), ['c2'])
assert.deepEqual((await rawGet('/api/team/offers?customerId=c1', staff)).body.offers, [])
})
test('E-Mail-Speicher open-count ohne Stripe-Abgleich', async () => {
const before = st.calls.length
assert.deepEqual((await rawGet('/api/team/storage-tasks/open-count', staff)).body, { open: 1 })
assert.equal(st.calls.length, before)
})
test('Mitarbeiter aus dem JWT: Rueckfrage, Erledigt und Funktionen-Notiz tragen Andrej', async () => {
const q = await post('/api/team/takeover-credits/tc3/decision', { action: 'question', note: 'Bitte Rechnung schicken' }, staff)
assert.equal(q.status, 200, JSON.stringify(q.body))
const detail = (await rawGet('/api/team/takeover-credits/tc3', staff)).body
assert.equal(detail.request.history.at(-1).by, 'Andrej <andrej@webklar.com>')
const done = await post('/api/team/storage-tasks/speicher-c2/done', {}, staff)
assert.equal(done.status, 200, JSON.stringify(done.body))
assert.equal(done.body.task.doneBy, 'andrej@webklar.com')
const news = await post('/api/team/funktionen/c1/news', { projectId: 'pa1', action: 'activate', note: 'Pilot' }, staff)
assert.equal(news.status, 200)
assert.match(news.body.projects[0].features.news.adminNote, /Andrej: activate – Pilot$/)
})
test('ohne JWT 401 fuer alle neuen Pfade', async () => {
for (const p of ['/api/team/takeover-credits', '/api/team/takeover-credits/open-count', '/api/team/offers', '/api/team/storage-tasks', '/api/team/storage-tasks/open-count', '/api/team/funktionen/c1']) {
assert.equal((await rawGet(p)).status, 401, p)
}
})