Files
accounted/lib/onboarding/__tests__/checklist.test.ts
T
Jakob Wennberg 44cff5e5e4 feat(onboarding): activation quick wins on the Hem checklist (#1461)
* feat(onboarding): activation quick wins on the Hem checklist

First implementation slice of the approved activation concept
(artifact de543d57, dev_docs/onboarding_activation_analysis.md §9):

- New "Kvitton och underlag" checklist step, gated on the invoice-inbox
  extension like the Skatteverket step; done once the company has ever
  received an inbox item (email/WhatsApp/upload). Non-AI companies route
  to billing, matching the assistant step.
- Personalized VAT line in the Skatteverket step: the company's real next
  momsdeklaration due date from the deadlines table, with an explicit
  "välj momsperiod" prompt when vat_registered is set but moms_period is
  null (that state silently generates zero VAT deadlines).
- Truthful Att göra empty state: while the setup checklist is open and no
  journal entry is posted, the all-clear reads "Bokföringen är tom än"
  instead of a false "Allt klart!".
- Activation funnel events (onboarding_setup_step_started / _completed /
  _dismissed) via posthog-js, mirroring the existing guarded capture
  pattern; sandbox never renders the block so no extra gate is needed.

Pure helpers live in lib/onboarding/checklist.ts with tests; step
numbering now adapts to both optional extensions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: record the receipts-signal and moms-period-guard decisions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(onboarding): review triage: error-safe emptyLedger, stale-state guard, copy

- A failed posted-entries count no longer reads as an empty ledger.
- Confirming a suggested match books an entry, so the empty-ledger copy
  retires for the rest of the session (postedSinceLoad).
- 'Bokföringen är tom än så länge' reads naturally.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 15:14:34 +02:00

74 lines
2.3 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { checklistNumbers, vatDeadlineLine } from '../checklist'
describe('vatDeadlineLine', () => {
it('returns null when the company is not VAT-registered', () => {
expect(
vatDeadlineLine({ vatRegistered: false, momsPeriod: 'quarterly', nextVatDueDate: '2026-11-12' })
).toBeNull()
expect(
vatDeadlineLine({ vatRegistered: null, momsPeriod: null, nextVatDueDate: null })
).toBeNull()
})
it('flags the silent zero-deadline misconfiguration when moms_period is unset', () => {
expect(
vatDeadlineLine({ vatRegistered: true, momsPeriod: null, nextVatDueDate: null })
).toEqual({ kind: 'missing_period' })
// Even with a stray row, an unset period is still a misconfiguration to surface.
expect(
vatDeadlineLine({ vatRegistered: true, momsPeriod: undefined, nextVatDueDate: '2026-11-12' })
).toEqual({ kind: 'missing_period' })
})
it('returns the due date when registered with a period and an upcoming row', () => {
expect(
vatDeadlineLine({ vatRegistered: true, momsPeriod: 'quarterly', nextVatDueDate: '2026-11-12' })
).toEqual({ kind: 'date', dueDate: '2026-11-12' })
})
it('says nothing when a period is set but no upcoming row surfaced', () => {
expect(
vatDeadlineLine({ vatRegistered: true, momsPeriod: 'yearly', nextVatDueDate: null })
).toBeNull()
})
})
describe('checklistNumbers', () => {
it('numbers all five steps when both extensions are on', () => {
expect(checklistNumbers({ hasSkatteverket: true, hasInbox: true })).toEqual({
count: 5,
skv: 3,
receipts: 4,
assistant: 5,
})
})
it('collapses to four steps without the inbox extension', () => {
expect(checklistNumbers({ hasSkatteverket: true, hasInbox: false })).toEqual({
count: 4,
skv: 3,
receipts: 4,
assistant: 4,
})
})
it('collapses to four steps without the skatteverket extension', () => {
expect(checklistNumbers({ hasSkatteverket: false, hasInbox: true })).toEqual({
count: 4,
skv: 3,
receipts: 3,
assistant: 4,
})
})
it('collapses to three steps with neither extension', () => {
expect(checklistNumbers({ hasSkatteverket: false, hasInbox: false })).toEqual({
count: 3,
skv: 3,
receipts: 3,
assistant: 3,
})
})
})