A Nuxt tesztelő-eszközkészlete jó, és négy rétegben fedi le az alkalmazást. A gond az, hogy mind a négy réteg Node-ban fut — vagyis pontosan azokat a hibákat nem látja, amiktől egy Nuxt app Workers-en elhasal. Ez a modul először felépíti a négy réteget, aztán megmutatja, hogyan hidald át az ötödiket: a valódi workerd-t.
Egy Nuxt-alkalmazás annyiféle helyen tud eltörni, hogy egyetlen teszttípus reménytelen. A @nuxt/test-utils ezért négy, egyre drágább és egyre valósághűbb réteget kínál. Érdemes mind a négyet használni, de tudni kell, melyik mit fog meg — és mit nem.
| Réteg | Mit fog meg | Mit nem fog meg |
|---|---|---|
| ① unit | logikai hibák, rossz élesetek, elrontott validáció | bármit, ami Nuxt-kontextust igényel |
| ② Nuxt-env | komponens-render, composable-viselkedés, props/emit-szerződés | valódi hálózat, valódi SSR-lánc, hydration |
| ③ Nitro | route-ok, státuszkódok, middleware-sorrend, szerver-oldali logika | böngésző-oldali működés, workerd-viselkedés |
| ④ E2E | hydration-hiba, kliensnavigáció, teljes user flow | mindent, ami csak Cloudflare-en romlik el |
| ⑤ workerd | a fenti táblázat harmadik oszlopának a maradékát | — |
A négy réteg négyféle környezetet igényel, és ha egy konfigba zsúfolod őket, minden teszt a leglassabb réteg árát fizeti. A megoldás a Vitest projects mechanizmusa: külön futtatókörnyezet, közös parancs.
# telepítés — a peer dependencyk nem opcionálisak
npm i -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import { defineVitestProject } from '@nuxt/test-utils/config'
export default defineConfig({
test: {
projects: [
{
test: {
name: 'unit',
include: ['test/unit/*.{test,spec}.ts'],
environment: 'node', // gyors: nincs Nuxt-bootstrap
},
},
await defineVitestProject({
test: {
name: 'nuxt',
include: ['test/nuxt/*.{test,spec}.ts'],
environment: 'nuxt', // lassabb: felhúzza a Nuxt-kontextust
},
}),
],
},
})
A könyvtárszerkezet ezt tükrözze, mert a Nuxt TypeScript-kontextusa automatikusan beleveszi a test/nuxt/ és tests/nuxt/ könyvtárakat — ott működnek az auto-importok a tesztfájlban is:
test/
├── unit/ # environment: 'node' — tiszta függvények
├── nuxt/ # environment: 'nuxt' — komponensek, composable-ök
└── e2e/ # setup() — épít és futtat egy szervert
Opcionálisan bekapcsolhatod a test-utils Nuxt-modulját is; ez az IDE- és típusintegrációt javítja:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/test-utils/module'],
})
shared/utils/ tartalma, a Zod/Valibot sémák, a server/utils/ tiszta függvényei, ár- és dátumszámítás, tenant-azonosító feloldás, jogosultság-döntés. Ha a 11. modul tanácsát követted és a tenant-szűrés egy külön függvényben van, az itt egy tízsoros teszttel bizonyítható — és ez a projekt legfontosabb tesztje lesz.A environment: 'nuxt' projekt egy majdnem teljes Nuxt-futásidőt ad: működnek az auto-importok, a #components alias, a composable-ök. A belépőpont két függvény, aszerint, hogy Vue Test Utils vagy Testing Library stílusban dolgozol.
// test/nuxt/price-badge.spec.ts
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { PriceBadge } from '#components'
it('a kedvezményt százalékban mutatja', async () => {
const c = await mountSuspended(PriceBadge, {
props: { original: 10000, current: 7500 },
})
expect(c.text()).toContain('-25%')
})
A mountSuspended lényege a névben van: megvárja az aszinkron setup-ot. Ha a komponensed <script setup>-ban await-el (mert például useAsyncData-t hív), a sima mount egy félig kész komponenst adna vissza. Van egy route opciója is — alapból /, de megadhatsz útvonalat, vagy false-szal kihagyhatod a router inicializálását.
Testing Library-vel ugyanez renderSuspended:
import { renderSuspended } from '@nuxt/test-utils/runtime'
import { screen } from '@testing-library/vue'
await renderSuspended(PriceBadge, { props: { original: 10000, current: 7500 } })
expect(screen.getByText('-25%')).toBeDefined()
import { mockNuxtImport, mockComponent, registerEndpoint } from '@nuxt/test-utils/runtime'
// ① auto-importált composable kicserélése
mockNuxtImport('useUserSession', () => {
return () => ({ loggedIn: ref(true), user: ref({ id: 'u1', role: 'admin' }) })
})
// típusbiztosan, az eredetire építve
mockNuxtImport<typeof useState>('useState', (original) => {
return (...args) => ({ ...original('key'), value: 'mocked' })
})
// ② komponens kicserélése — név vagy útvonal alapján
mockComponent('MapWidget', {
setup() { return () => h('div', '[térkép]') },
})
mockComponent('~/components/heavy-chart.vue', () => import('./ChartStub.vue'))
// ③ Nitro-végpont kigúnyolása — a komponens $fetch-e ezt kapja
registerEndpoint('/api/products', () => [{ id: 'p1', name: 'Bögre' }])
registerEndpoint('/api/orders', {
method: 'POST',
handler: () => ({ id: 'o1', status: 'created' }),
})
mockNuxtImport hoistolódik. A háttérben vi.mock-ot használ, amit a Vitest a fájl tetejére emel. Ebből két szabály következik: (1) egy importra csak egyszer hívhatod egy fájlban — ha több teszt más-más viselkedést akar, a mockon belül kell változót olvasnod (és a változót vi.hoisted-del létrehoznod); (2) a mock-gyáron kívüli fájlszintű változókra nem hivatkozhatsz, mert azok még nem léteznek, amikor a mock lefut. Ez a leggyakoribb „miért undefined?” a Nuxt-tesztekben.Két olyan böngésző-API van, amit a happy-dom nem ad meg, viszont a valós komponensek gyakran használják. Ezeket a Nuxt tesztkörnyezete pótolja, konfigurálhatóan:
// vitest.config.ts — a nuxt projekten belül
environmentOptions: {
nuxt: {
mock: {
intersectionObserver: true, // alap: true — üres osztály
indexedDb: true, // alap: false — fake-indexeddb, működő
},
},
}
Az intersectionObserver-mock azért van bekapcsolva alapból, mert enélkül minden hydrate-on-visible komponens és minden lazy-load kép elhasalna a tesztben. Ha viszont a 15. modul stratégiáit használod, jegyezd meg: a mock nem figyel semmit, tehát a láthatóságra épülő viselkedést nem tudod ezen a rétegen tesztelni — az a ④ réteg dolga.
Ez a réteg lép ki először a szimulációból: a setup() lefordítja a teljes alkalmazást és elindít egy valódi szervert, aztán HTTP-n keresztül beszélsz vele. Cserébe lassú — külön projektbe való, és nem érdemes minden mentésre futtatni.
// test/e2e/api.spec.ts
import { describe, test, expect } from 'vitest'
import { setup, $fetch, fetch, url } from '@nuxt/test-utils/e2e'
describe('termék-API', async () => {
await setup({ setupTimeout: 120_000 })
test('listáz', async () => {
const data = await $fetch('/api/products')
expect(data).toHaveLength(3)
})
test('auth nélkül 401', async () => {
// fetch() — teljes válaszobjektum, fejlécekkel és státusszal
const res = await fetch('/api/admin/users')
expect(res.status).toBe(401)
})
test('a SSR HTML tartalmazza a címet', async () => {
const html = await $fetch('/') // oldalon: nyers HTML jön vissza
expect(html).toContain('<h1>Bolt</h1>')
})
})
setup() opció | Alap | Mire jó |
|---|---|---|
rootDir | '.' | monorepóban a Nuxt-app útvonala |
configFile | 'nuxt.config' | külön teszt-konfig használata |
build | true | false: ne fordítson újra (előre buildelt kimenet) |
server | true | false: ne indítson szervert |
host | — | meglévő URL-t céloz build helyett — lásd 16.6 |
port | véletlen | fix port, ha külső eszköz is csatlakozik |
browser | false | Playwright-példány indítása (createPage-hez) |
setupTimeout | 120000 | lassú CI-n emeld; a build ideje ebbe számít |
teardownTimeout | 30000 | leállítási türelem |
Ha azt akarod bizonyítani, hogy egy handler naplózott valamit (audit-log, hibaág), nem elég a válaszkódot nézni:
import { getServerLogs, clearServerLogs } from '@nuxt/test-utils/e2e'
await setup({ captureServerLogs: true })
test('sikertelen belépést naplóz', async () => {
clearServerLogs()
await fetch('/api/login', { method: 'POST', body: JSON.stringify({ email: 'x@y.z', password: 'rossz' }) })
expect(getServerLogs().join('\n')).toContain('auth.failed')
})
/api/orders-ben adatszivárgás.Két út van. Vitest-runnerrel a createPage()-et hívod a setup({ browser: true }) után; a másik — és tisztább — út a Playwright saját runnerje, amihez a test-utils külön belépőpontot ad.
npm i -D @playwright/test @nuxt/test-utils
// playwright.config.ts
import { defineConfig } from '@playwright/test'
import type { ConfigOptions } from '@nuxt/test-utils/playwright'
export default defineConfig<ConfigOptions>({
use: {
nuxt: { rootDir: '.' },
},
})
// test/e2e/checkout.spec.ts
import { expect, test } from '@nuxt/test-utils/playwright'
test('a kosár túléli az oldalfrissítést', async ({ page, goto }) => {
await goto('/termek/bogre', { waitUntil: 'hydration' })
await page.getByRole('button', { name: 'Kosárba' }).click()
await page.reload()
await expect(page.getByTestId('cart-count')).toHaveText('1')
})
A waitUntil: 'hydration' az egyetlen ok, amiért érdemes a test-utils goto-ját használni a natív page.goto helyett. A Playwright alap várakozásai (load, networkidle) nem tudják, mikor fejeződött be a Vue hydratálása — ezért ír az ember flaky teszteket tele waitForTimeout-tal. Ez a beállítás pontosan arra a pillanatra vár.
Az E2E drága és törékeny, ezért ne az üzleti szabályokat teszteld vele — azokat a ① és ③ réteg olcsóbban lefedi. Az E2E arra való, ami csak a teljes láncban derül ki:
page.on('console')-ra, és elbukni minden hydration-warningon.NuxtLink-es útvonalváltás nem tölt újra oldalt — a middleware-ek, a useAsyncData újrafutása és az állapotmegőrzés csak így ellenőrizhető.Most jön a modul lényege. Fussuk át még egyszer, mit csinál a setup(): lefordítja az appot az alapértelmezett presettel, és elindítja Node-ban. Nem workerd-ben. Nem a te wrangler.jsonc-d szerint. Nem a te bindingjaiddal.
Ebből az következik, hogy egy tökéletesen zöld tesztkészlet mellett is elhasalhat az éles deploy, mégpedig pontosan azokon, amikről az előző modulok szóltak:
| Hibaosztály | Node-tesztben | Workers-en |
|---|---|---|
Node-only API (fs, natív addon) | működik | futásidejű hiba vagy build-hiba |
| Bundle túllépi a 3/10 MB gzip limitet | nem érdekli | a deploy elutasítva |
| Modul-scope inicializálás > 1 s | nem érdekli | indulási hiba |
| Modul-szintű mutable állapot | többnyire nem látszik | kereszt-kérés szivárgás |
| Kérésenként > 50 (ill. 1000) subrequest | működik | a további hívások elhasalnak |
| Hosszú szinkron CPU-blokk | lassú, de lefut | CPU-limit túllépés |
| D1/KV konzisztencia-feltételezés | a mock mindig konzisztens | KV: eventual consistency |
A wrangler dev nem szimulátor: ugyanazt a workerd bináris futtatókörnyezetet indítja el, ami élesben is fut, csak a bindingokat emulálja Miniflare-rel. Ez elkap mindent, ami a fenti tábla első hat sora.
# build a Cloudflare-presettel, majd futtatás valódi workerd-ben
npx nuxt build
npx wrangler dev
# hasznos kapcsolók
npx wrangler dev --remote # valódi, éles bindingok (nem emulált)
npx wrangler dev --test-scheduled # /__scheduled útvonal a cron-handlerhez
npx wrangler dev --log-level debug
npx wrangler dev --inspector-port 9229
Ez a lépés a CI-ben is elfér, mint füstteszt: build → wrangler dev háttérben → néhány curl a kritikus útvonalakra → leállítás. Ha az app el sem indul workerd alatt, ezt a merge előtt akarod megtudni.
Ez a legjobb trükk a modulban, és alig ismert. A setup() host opciója azt mondja: ne buildelj, ne indíts szervert — ezt az URL-t célozd. Ami azt jelenti, hogy ugyanaz a tesztfájl, amit lokálisan Node ellen futtatsz, változtatás nélkül futtatható egy valódi Workers-deploy ellen.
// test/e2e/smoke.spec.ts — kettős életű teszt
import { setup, $fetch } from '@nuxt/test-utils/e2e'
describe('füstteszt', async () => {
await setup(
process.env.PREVIEW_URL
? { host: process.env.PREVIEW_URL } // CI: valódi workerd, valódi bindingok
: { setupTimeout: 120_000 }, // lokál: Node-build
)
test('a főoldal SSR-el', async () => {
expect(await $fetch('/')).toContain('<h1')
})
test('az API él és az adatbázist látja', async () => {
expect(await $fetch('/api/health/db')).toMatchObject({ ok: true })
})
})
A CI-lánc ehhez a 8. modul verzió-alapú deployára épül: feltöltesz egy verziót anélkül, hogy forgalmat kapna, megkapod a preview URL-t, ráengeded a füsttesztet, és csak siker esetén léptetsz elő.
# .github/workflows/deploy.yml — a lényegi rész
- name: Verzió feltöltése (forgalom nélkül)
id: upload
run: |
npx nuxt build
npx wrangler versions upload --json > version.json
echo "url=$(jq -r '.preview_url' version.json)" >> $GITHUB_OUTPUT
- name: Füstteszt a valódi Workers-deploy ellen
env:
PREVIEW_URL: ${{ steps.upload.outputs.url }}
run: npx vitest run test/e2e/smoke.spec.ts
- name: Előléptetés 100%-ra
run: npx wrangler versions deploy --yes
@cloudflare/vitest-pool-workers?A Cloudflare saját Vitest-integrációja workerd-ben futtatja a teszteket, teljes binding-hozzáféréssel — papíron pont az, amit keresünk:
// vitest.config.ts — Cloudflare-integráció (Vitest 4.1+ szükséges)
import { cloudflareTest } from '@cloudflare/vitest-pool-workers'
import { defineConfig } from 'vitest/config'
export default defineConfig({
plugins: [cloudflareTest({ wrangler: { configPath: './wrangler.jsonc' } })],
})
import { env, exports } from 'cloudflare:workers'
import { createExecutionContext, waitOnExecutionContext } from 'cloudflare:test'
it('a KV-binding valódi', async () => {
await env.CACHE.put('k', 'v')
expect(await env.CACHE.get('k')).toBe('v')
})
.output/server/index.mjs — egy generált, több ezer soros bundle, amit előbb le kell fordítani, és amiben egy-egy handler nem címezhető külön. Használható a Nuxt-tól független Worker-kódra (külön Durable Object, külön queue-consumer, cron-worker), és arra érdemes is; a Nuxt-alkalmazás maga viszont a 16.6-os két áthidaláson keresztül tesztelhető józanul.A nuxt dev régen nem látta a Cloudflare-bindingokat, ezért terjedt el a nitro-cloudflare-dev modul, ami a wrangler getPlatformProxy API-jával pótolta őket. Erre már nincs szükség: a Nitro újabb verziói beépítve emulálják a Cloudflare-környezetet Miniflare-rel — ugyanazzal a workerd-vel, amit a wrangler is használ.
Elég, ha a bindingok szerepelnek a wrangler.jsonc-ben; ha nem akarsz külön fájlt, inline is megadhatod:
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: 'cloudflare_module',
cloudflare: {
wrangler: {
vars: { APP_MODE: 'dev' },
kv_namespaces: [{ binding: 'CACHE', id: 'xxx' }],
},
wranglerEnv: 'preview', // melyik wrangler-környezetet emulálja
},
},
})
A lokális állapot a .wrangler/state/v3 alá kerül — ez a te lokális D1-ed, KV-d, R2-d. Tedd .gitignore-ba, és tudd, hogy törölhető: ha összekuszálódott a lokális adatbázisod, a könyvtár törlése tiszta lapot ad.
| Binding | Lokálisan | Amiben eltér az élestől |
|---|---|---|
| D1 | helyi SQLite | nincs hálózati késleltetés, nincs sorlimit, nincs régió-kérdés |
| KV | SQLite-alapú emuláció | azonnal konzisztens — élesben eventual consistency |
| R2 | helyi fájlrendszer | nincs valódi latencia, nincs multipart-korlát |
| Queues | helyi emuláció | a batch-viselkedés és az újrapróbálkozás időzítése más |
| Hyperdrive | közvetlen kapcsolat | nincs pooling és nincs cache — a legnagyobb eltérés |
| Secrets | .dev.vars | élesben wrangler secret; könnyű elfelejteni feltölteni |
A wrangler dev futása közben nyomj D-t: megnyílik a Chrome DevTools a Workeredre kötve. Ez nem konzol-tükrözés, hanem teljes értékű debugger:
Ha Vite-tal futtatod a Cloudflare-pluginnal, ugyanez a http://localhost:5173/__debug címen érhető el.
wrangler tail — élő logfolyam éles forgalomból# minden, ami hibával végződik
npx wrangler tail --status error
# egy konkrét szövegre szűrve, gépi feldolgozásra
npx wrangler tail --search "tenant:acme" --format json | jq '.logs[].message'
# csak a saját kéréseim (fejlesztés közben aranyat ér)
npx wrangler tail --ip self
# egy frissen feltöltött verzió viselkedése, forgalom előtt
npx wrangler tail --version-id <id>
| Kapcsoló | Érték | Mikor |
|---|---|---|
--format | json | pretty | json + jq, ha keresel; pretty, ha olvasol |
--status | ok | error | canceled | hibavadászat forgalmas Workeren |
--search | szöveg | a console.log üzenetekben keres |
--method / --header | szöveg | egy konkrét endpoint izolálása |
--ip | IP vagy self | saját kérés kiszűrése éles forgalomból |
--version-id | verzió-azonosító | fokozatos bevezetés megfigyelése |
--sampling-rate | 0–1 | ha a nagy forgalom elnyomja a logokat |
Amit a tail nem tud (tárolás, visszamenőleges keresés), azt a Workers Logs adja. Bekapcsolni egy sor:
// wrangler.jsonc
{
"observability": {
"enabled": true,
"head_sampling_rate": 1 // 1 = minden kérés, 0.01 = 1%
}
}
| Tulajdonság | Free | Paid |
|---|---|---|
| Napi keret | 200 000 log | havi 20 millió benne, utána 0,60 $ / millió |
| Megőrzés | 3 nap | 7 nap |
| Max. logméret | 256 KB / bejegyzés | |
| Fiókszintű plafon | napi 5 milliárd log fölött 1%-os mintavétel | |
| Minimum wrangler | 3.78.6 | |
console.log({ event: 'order.created', orderId, tenantId, ms }) mezőnként kereshető lesz; a console.log('Order ' + id + ' created in ' + ms + 'ms') viszont csak szövegkeresésre alkalmas. Ugyanannyi munka, és a különbség akkor derül ki, amikor éjjel fél háromkor keresel valamit.Minifikált bundle-ben egy stack trace körülbelül annyit ér, mint a semmi: index.mjs:1:284471. A Cloudflare fel tudja tölteni és használni a source mapet, de két helyen kell bekapcsolni, mert alapból egyik sincs bekapcsolva:
// nuxt.config.ts — a Nitro alapból NEM generál source mapet (alap: false)
export default defineNuxtConfig({
nitro: { sourceMap: true },
})
// wrangler.jsonc — a feltöltés külön kapcsoló (wrangler 3.46.0+)
{ "upload_source_maps": true }
Ezután a nem kezelt kivételek stack trace-e az eredeti forrásfájlokra és sorszámokra mutat, és ez látszik a valós idejű logokban és a Tail Workerekben is. A visszafejtés a kérés lefutása után, aszinkron történik, tehát nem terheli a Worker CPU-idejét — nincs teljesítménybeli ok kihagyni. A source map maximális mérete 15 MB gzip.
A hibakeresés másik fele az, hogy amikor mégis eltörik valami, az ne fehér képernyő legyen. A Nuxt eszközei:
// dobás bárhonnan — oldalról, komponensből, server route-ból
throw createError({
status: 404,
statusText: 'Ilyen termék nincs',
data: { sku }, // ← ez ELJUT a klienshez
// message: '…' ← ez NEM jut el a klienshez API-route-ból
})
message szándékosan nem propagál a kliensre szerveroldali hibánál — ez biztonsági döntés, nehogy belső részletek szivárogjanak ki. Ha a kliensnek is kell információ, tedd data-ba vagy statusText-be. Ez a leggyakoribb „miért látok üres hibaüzenetet?” a Nuxt-projektekben. (Megjegyzés: a Nuxt 4 dokumentáció a status / statusText neveket használja; a régebbi statusCode / statusMessage a h3 korábbi elnevezése.)| Eszköz | Mit csinál |
|---|---|
~/error.vue | a teljes képernyős hibaoldal; NuxtError objektumot kap propként |
useError() | az aktuálisan kezelt globális hiba |
showError() | hibaoldal kikényszerítése — de a throw createError() az ajánlott |
clearError({ redirect }) | hiba törlése és opcionális átirányítás — a „Vissza a főoldalra” gomb |
<NuxtErrorBoundary> | lokális hibakezelés: csak egy komponensfa dől el, nem az oldal |
fatal: true | kliensoldalon is teljes képernyős hibát vált ki (alapból nem) |
<!-- egy widget elhasalása ne vigye el az egész oldalt -->
<NuxtErrorBoundary>
<RecommendationCarousel />
<template #error="{ error, clearError }">
<p>Az ajánlások most nem érhetők el.</p>
<button @click="clearError">Újra</button>
</template>
</NuxtErrorBoundary>
Ez a Cloudflare-en különösen releváns. Amikor deployolsz, a JS-chunkok hash-e megváltozik, és a régi fájlok eltűnnek. Egy felhasználó, akinek nyitva volt az oldal a deploy előtt, kattint egy linkre → a Nuxt letölteni akarja a régi hash-ű chunkot → 404. Mivel a Workers-deploy globálisan azonnali, ez nem néhány szerverre igaz, hanem mindenkire, egyszerre.
A Nuxt alapból ezt kemény újratöltéssel kezeli, ami helyes viselkedés. Ha finomabban akarod (például mentetlen űrlapadat miatt), átveheted az irányítást:
// nuxt.config.ts
experimental: {
emitRouteChunkError: 'manual', // alap: automatikus újratöltés; false: kikapcsolva
}
A 4.5 óta a Nuxt hibái és figyelmeztetései stabil azonosítót kapnak: NUXT_E1001, NUXT_B5001 és társaik. Fejlesztésben a kód mellé megkapod, hogy miért történt és hogyan javítható; a bonyolultabbakhoz dokumentációs oldal is tartozik. A klasszikus „a composable Nuxt-kontextuson kívül lett meghívva” például NUXT_E1001.
A 4.5 bevezetett egy diszkrét, de fontos képességet: a Nuxt diagnostics-channel nyomokat publikál a szerveroldali műveleteiről. Ez az a horog, amire OpenTelemetry-t (vagy bármi mást) építhetsz — és a lényeg, hogy Cloudflare Workers-en is működik, nem csak Node-on.
// nuxt.config.ts
export default defineNuxtConfig({
tracingChannel: true,
// vagy szemcsésebben: tracingChannel: { nuxt: true }
})
Négy csatorna publikál: nuxt.render, nuxt.island, nuxt.data és nuxt.plugin. Ezekkel megválaszolhatóvá válik az a kérdés, amit a 15. modulban felvetettünk, de nem tudtunk megmérni: egy lassú kérésen belül mire ment el az idő — a renderelésre, egy adatlekérésre, vagy egy plugin inicializálására.
Összerakva a modult, egy Cloudflare-re szánt Nuxt-projekt teszt-CI-je három sávban fut, és mindegyik más ponton áll meg:
| Mikor | Mi fut | Idő |
|---|---|---|
| Minden mentésre (lokál) | vitest --project unit figyelő módban | < 1 s |
| Minden pusholt commitra | unit + nuxt projekt, lint, nuxt typecheck | 1–2 perc |
| Pull requestre | + Nitro-tesztek, + wrangler deploy --dry-run méretellenőrzés | 3–5 perc |
| Merge után, deploy előtt | verzió feltöltése → E2E füstteszt a preview URL ellen → előléptetés | 5–10 perc |
host opció miatt ez ugyanaz a fájl, amit lokálisan is használsz, a bevezetése nagyjából tíz sor CI-konfiguráció.@nuxt/test-utils elvileg sem tud elkapni.
Bármi ebből: hiányzó Node API a workerd-ben, bundle-méret a 3/10 MB gzip limit fölött, 1 másodpercnél hosszabb modul-scope inicializálás, kereszt-kérés állapotszivárgás isolate-újrahasználatnál, subrequest-limit, CPU-limit, KV eventual consistency. A közös ok: a setup() Node-ban buildel és futtat, nem workerd-ben.
Lazy prefix és a mockComponent között a tesztelés szempontjából? (Csapdakérdés.)
Semmi közük egymáshoz — az egyik futásidejű optimalizálás (15. modul), a másik tesztidejű helyettesítés. A kérdés arra megy, hogy nehéz komponenst (térkép, chart) tesztben mockComponent-tel cserélsz ki, nem Lazy-vel: a Lazy a tesztben is betöltené.
page.goto() Playwrightban egy Nuxt-oldalnál?
Mert a Playwright alap várakozásai (load, networkidle) nem tudják, mikor fejeződött be a Vue hydratálása. A test-utils goto(url, { waitUntil: 'hydration' }) pontosan erre a pillanatra vár — enélkül flaky tesztek lesznek, tele waitForTimeout-tal.
setup() melyik opciójával futtatod ugyanazt a tesztfájlt egy valódi Workers-deploy ellen?
host. Ha megadod, a test-utils nem buildel és nem indít szervert, hanem a megadott URL-t célozza. Így a lokálisan Node ellen futó füstteszt CI-ben a preview URL ellen fut, változtatás nélkül.
A lokális KV-emuláció SQLite-alapú és azonnal konzisztens; az éles KV globálisan eventually consistent. Ez a hibaosztály lokálisan sosem reprodukálódik — csak valódi deploy ellen futó teszt fogja meg.
wrangler tail folyamát, és mi történik nagy forgalomnál?
Legfeljebb 10 (a dashboard és a CLI együtt számít). Nagy forgalomnál a tail mintavételi módba vált és üzeneteket dob el — ezért érdemes --status, --search vagy --ip self szűréssel indítani.
nitro.sourceMap: true a Nuxt-konfigban (a Nitro alapból nem generál source mapet) és upload_source_maps: true a wrangler-konfigban (a feltöltés külön kapcsoló). A visszafejtés a kérés után aszinkron történik, tehát nincs CPU-költsége.
createError({ status: 500, message: 'DB timeout a users táblán' })-t. Mit lát a kliens?
Nem látja a message-et — az szándékosan nem propagál szerveroldali hibánál, hogy belső részletek ne szivárogjanak. Ha kell neki információ, statusText-be vagy data-ba tedd.
Mert a Workers-deploy globálisan azonnali: nincs fokozatos kigördülés régiónként. A deploy pillanatában minden nyitott böngészőlapon egyszerre válnak érvénytelenné a régi hash-ű chunkok. A Nuxt alapból kemény újratöltéssel kezeli; az experimental.emitRouteChunkError: 'manual' adja vissza az irányítást.
@cloudflare/vitest-pool-workers magára a Nuxt-appra?
Mert kézzel írt Workerre tervezték, ahol a forrásfájl a belépőpont. A Nuxt belépőpontja a .output/server/index.mjs: generált bundle, amit előbb le kell fordítani, és amiben az egyes handlerek nem címezhetők külön. A Nuxt-tól független Worker-kódra (Durable Object, queue-consumer, cron-worker) viszont kifejezetten jó választás.