Ugrás a tartalomra
kassza

Tesztelés

Automata tesztben ne hívd a Számlázz.hu-t. A tesztfiók 10 percenként legfeljebb 500 számlát enged, a hálózat lassú és kiszámíthatatlan, és egy elrontott teszt éles fiókon valódi számlát állít ki. Erre való a createMockKassza(): ugyanazt a Kassza felületet adja, mint a createKassza(), de nem hív hálózatot, és nem kell hozzá Agent kulcs.

import { createMockKassza } from 'kassza/testing'

const kassza = createMockKassza()

const szamla = await kassza.invoices.create({
  orderNumber: 'REND-1001',
  buyer: { name: 'Vevő Kft.', zip: '1111', city: 'Budapest', address: 'Fő utca 1.' },
  items: [{ name: 'Termék', quantity: 2, grossUnitPrice: 5_990, vat: 27 }],
})

console.log(szamla.number, szamla.grossTotal, kassza.calls)

A mock ugyanazt a kliensoldali validációt és kerekítést futtatja, mint az éles kliens. Egy ismeretlen áfakulcs vagy egy kisbetűs nyugta előtag itt is validation hibát dob, a fenti számla bruttó összege pedig itt is 11 980 Ft.

Mock kliens tesztekhez

createMockKassza: hívásnapló, bizonylatok, és szimulált hálózati hiba.

Futtatás a sandboxban
mock-kliens.ts
import type { Kassza } from 'kassza'
import {  } from 'kassza/testing'

async function (: number, : Kassza): <string> {
  const  = `REND-${}`
  const  = await ..({  })
  if () return ..
  const  = await ..({
    ,
    : true,
    : 'bankkártya',
    : { : 'Vevő Kft.', : '1111', : 'Budapest', : 'Fő utca 1.' },
    : [{ : 'Termék', : 12_700, : 27 }],
  })
  return .
}

const  = ()

await (1, )
await (1, )

.(
  'Hívások:',
  ..(() => .),
)
.(
  'Bruttó összegek:',
  [.....()].(() => ...),
)

.('invoices.create')
try {
  await (2, )
} catch () {
  .('A mock hibát dobott:', )
}

A kliens injektálása#

A mockot csak akkor tudod átadni, ha a kódod nem maga hozza létre a klienst. A legegyszerűbb, ha a számlázó függvény paraméterben kapja meg a Kassza típusú klienst:

lib/szamlazas.ts
import { type InvoiceBuyer, isSzamlazzError, type Kassza } from 'kassza'

export interface Rendeles {
  readonly id: number
  readonly vevo: InvoiceBuyer
  readonly vegosszeg: number
}

const BIZONYTALAN = ['network', 'timeout', 'partial_success', 'duplicate']

export async function szamlazRendelest(kassza: Kassza, rendeles: Rendeles): Promise<string> {
  const orderNumber = `REND-${rendeles.id}`
  const meglevo = await kassza.invoices.find({ orderNumber })
  if (meglevo) return meglevo.header.number

  try {
    const szamla = await kassza.invoices.create({
      orderNumber,
      paid: true,
      paymentMethod: 'bankkártya',
      buyer: rendeles.vevo,
      items: [{ name: 'Rendelés', grossUnitPrice: rendeles.vegosszeg, vat: 27 }],
    })
    return szamla.number
  } catch (error) {
    if (isSzamlazzError(error) && BIZONYTALAN.includes(error.category)) {
      const letrejott = await kassza.invoices.find({ orderNumber })
      if (letrejott) return letrejott.header.number
    }
    throw error
  }
}

Élesben a route handler adja át a megosztott klienst, tesztben a mockot:

app/api/rendeles/route.ts
import { kassza } from '@/lib/kassza'
import { szamlazRendelest } from '@/lib/szamlazas'

export async function POST(request: Request) {
  const rendeles = await request.json()
  const szamlaszam = await szamlazRendelest(kassza, rendeles)
  return Response.json({ szamlaszam })
}

Vitest példák#

Egy mock példányt a fájl tetején hozol létre, és minden teszt előtt a reset() kiüríti a hívásnaplót, a bizonylatokat, a beállított hibákat és a sorszámokat.

lib/szamlazas.test.ts
import { SzamlazzError } from 'kassza'
import { createMockKassza } from 'kassza/testing'
import { beforeEach, describe, expect, test } from 'vitest'
import { type Rendeles, szamlazRendelest } from './szamlazas'

const kassza = createMockKassza({ now: () => new Date('2026-09-17T10:00:00Z') })

const rendeles: Rendeles = {
  id: 1001,
  vevo: { name: 'Nagy Péter', zip: '1111', city: 'Budapest', address: 'Fő utca 1.' },
  vegosszeg: 12_700,
}

beforeEach(() => kassza.reset())

describe('szamlazRendelest', () => {
  test('egy rendelésre csak egy számlát állít ki', async () => {
    const elso = await szamlazRendelest(kassza, rendeles)
    const masodik = await szamlazRendelest(kassza, rendeles)

    expect(elso).toBe('E-KASSZA-2026-1')
    expect(masodik).toBe(elso)
    expect(kassza.calls.filter((hivas) => hivas.method === 'invoices.create')).toHaveLength(1)
    expect(kassza.invoiceRecords.get(elso)?.details.totals.grossAmount).toBe(12_700)
  })

  test('hálózati hibánál továbbdobja a hibát, ha nem készült számla', async () => {
    kassza.failNext('invoices.create')

    await expect(szamlazRendelest(kassza, rendeles)).rejects.toMatchObject({ category: 'network' })
    expect(kassza.invoiceRecords.size).toBe(0)
  })

  test('fiókhibánál nem kérdez le újra', async () => {
    kassza.failNext(
      'invoices.create',
      new SzamlazzError('[136] Lejárt előfizetés', { category: 'account', code: 136 }),
    )

    await expect(szamlazRendelest(kassza, rendeles)).rejects.toMatchObject({ code: 136 })
    expect(kassza.calls.map((hivas) => hivas.method)).toEqual(['invoices.get', 'invoices.create'])
  })
})

Ha a kódod egy modul szintű klienst importál, a Vitest vi.mock() függvényével cserélheted mockra. A gyár függvényben dinamikusan importáld a kassza/testing modult, mert a vi.mock() a fájl importjai elé kerül:

lib/webhook.test.ts
import type { MockKassza } from 'kassza/testing'
import { beforeEach, expect, test, vi } from 'vitest'
import { kassza } from './kassza'
import { webhookKezelo } from './webhook'

vi.mock('./kassza', async () => {
  const { createMockKassza } = await import('kassza/testing')
  return { kassza: createMockKassza() }
})

const mock = kassza as MockKassza

beforeEach(() => mock.reset())

test('a fizetési webhook számlát állít ki', async () => {
  await webhookKezelo({ rendelesId: 1001 })

  expect(mock.calls.map((hivas) => hivas.method)).toContain('invoices.create')
})

Opciók#

OpcióTípusAlapértékLeírás
defaultsKasszaDefaultsUgyanaz, mint a createKassza() defaults opciója, például számla előtag vagy nyugta fizetési mód.
taxpayersRecord<string, TaxpayerInfo>A taxpayer.query() válaszai a 8 jegyű törzsszám szerint.
credentialsValidbooleantrueA verifyCredentials() visszatérési értéke.
now() => Date() => new Date()Az aktuális idő. Ebből lesz a kelt, a teljesítés dátuma és a számlaszám éve.

A dátumok a mockban is budapesti idő szerint számolódnak: now: () => new Date('2026-09-16T23:30:00Z') mellett a számla kelte már 2026-09-17.

import { createMockKassza } from 'kassza/testing'

const kassza = createMockKassza({
  defaults: { invoice: { prefix: 'WEB' }, receipt: { prefix: 'NYGT', paymentMethod: 'bankkártya' } },
  taxpayers: { '13421739': { valid: true, name: 'KBOSS.HU KFT.', addresses: [] } },
  credentialsValid: false,
})

const ceg = await kassza.taxpayer.query('13421739-2-41')
const ismeretlen = await kassza.taxpayer.query('11111111-2-42')
const kulcsJo = await kassza.verifyCredentials()

Itt a ceg.valid értéke true, az ismeretlen értéke { valid: false, addresses: [] }, a kulcsJo pedig false. A defaults miatt a következő számla száma E-WEB-2026-1 lesz.

A mock felülete#

A MockKassza a Kassza összes metódusán felül ezeket adja:

MezőTípusLeírás
callsreadonly MockCall[]Minden hívás sorrendben, { method, args } alakban. A hibára futott hívás is benne van.
invoiceRecordsReadonlyMap<string, MockInvoiceRecord>A számlák számlaszám szerint: input, details, payments, reversed, deleted.
receiptRecordsReadonlyMap<string, MockReceiptRecord>A nyugták nyugtaszám szerint: receipt és sentTo, a kiküldött e-mail címek hívásonként.
failNext(method, error?)voidA megadott metódus következő hívása hibát dob. Hiba nélkül egy network kategóriájú SzamlazzError-t.
reset()voidMindent kiürít, a sorszámozás újraindul.

A method nevek az API útvonalát követik:

MetódusnévMelyik hívás
invoices.create, invoices.preview, invoices.reverseSzámla, előnézet, sztornó
invoices.registerPayment, invoices.clearPaymentsBefizetések
invoices.getPdf, invoices.get, invoices.deleteProformaPDF, számla adatai, díjbekérő törlése
receipts.create, receipts.reverse, receipts.get, receipts.sendNyugták
taxpayer.query, verifyCredentials, resetSessionAdószám, kulcs ellenőrzése, munkamenet

Mit szimulál a mock?#

ViselkedésA mockban
SzámlaszámE-KASSZA-2026-1, díjbekérőnél D-KASSZA-2026-1, előtaggal E-WEB-2026-1
SztornóÚj E-STORNO-2026-1 számla, az eredetin reversed: true
NyugtaszámNYGT-2026-1, sztornónál NYGT-STORNO-2026-1
PDFA MOCK_PDF néven exportált minimális PDF, ha a downloadPdf nincs kikapcsolva
BefizetésA registerPayment hozzáad vagy felülír, a hátralékot a bruttó végösszegből számolja
Nem létező számla[7], not_found, a find null-t ad
Nem létező díjbekérő törlése[335], not_found
Ismételt nyugta callId[338], duplicate
Nem létező nyugta[339], not_found, a find null-t ad
Kiállított számla fejlécetest: true, eladó: Kassza Teszt Kft.

A mock nem ellenőrzi a rendelésszám ismétlődését (71, 152), a fiókban nem regisztrált előtagot (202) és a fiók állapotát, és e-mailt sem küld. Ezeket az eseteket a failNext() második paraméterében adott SzamlazzError-ral szimuláld.

Hiba, de a számla elkészült#

A failNext() a bizonylat létrehozása előtt dob, így a hibára futott hívás a mockban nem hoz létre számlát. Azt az esetet, amikor a számla a hiba ellenére elkészült (például [56]), egy csomagoló klienssel teszteled, amely előbb kiállítja a számlát, és csak utána dob:

lib/szamlazas.test.ts
import { type Kassza, SzamlazzError } from 'kassza'
import { createMockKassza } from 'kassza/testing'
import { expect, test } from 'vitest'
import { szamlazRendelest } from './szamlazas'

test('részleges siker után nem állít ki új számlát', async () => {
  const mock = createMockKassza()
  const kassza: Kassza = {
    ...mock,
    invoices: {
      ...mock.invoices,
      create: async (input) => {
        await mock.invoices.create(input)
        throw new SzamlazzError('[56] Az értesítő e-mail nem ment ki.', {
          category: 'partial_success',
          code: 56,
        })
      },
    },
  }

  const szamlaszam = await szamlazRendelest(kassza, {
    id: 1002,
    vevo: { name: 'Nagy Péter', zip: '1111', city: 'Budapest', address: 'Fő utca 1.' },
    vegosszeg: 12_700,
  })

  expect(mock.invoiceRecords.has(szamlaszam)).toBe(true)
  expect(mock.invoiceRecords.size).toBe(1)
})
Oldal szerkesztéseUtoljára frissítve: