The four kinds of Omnibeds tests: unit tests with an in-process database, boundary tests that guard the layers, end-to-end tests of real screens, and live supplier tests.
Omnibeds has four kinds of tests, and each one answers a different question. Run the first three before every commit; run the live tests when you change a supplier adapter. The commands are on Run and test.
Kind
Command
Answers
Unit
npm test
Does each piece do what it should?
Boundaries
part of npm test
Are the layers still apart?
End to end
npm run test:e2e
Does the real app work, screen by screen?
Live suppliers
npm run test:live
Do the real suppliers still accept what we send?
Unit tests
Unit tests (Vitest, in tests/) cover the domain: pricing, guest names by each supplier’s rules, quotes, trips, mapping, the orchestrator’s retries and breaker, and every command’s checks. Tests that need a database run against PGlite, an in-process Postgres, built from the same migrations as production. tests/migrations.test.ts checks a fresh database gets every migration once and every table the code uses, and that a failed migration rolls back.
Boundary tests
tests/boundaries.test.ts and tests/app-layer.test.ts keep the architecture from drifting. They fail when:
a command has no route, or its route file doesn’t serve its method,
a route that isn’t infrastructure does more than call a command,
code in lib/ imports from components/,
a screen imports server code,
a screen writes a command’s URL instead of calling api().
They also check that each command’s checks run for every caller and that errors keep the one format.
End-to-end tests
Playwright tests in e2e/ start the app and drive the real screens. They cover, among others: booking step by step (with a placeholder name prompted), a cheaper equivalent offered and taken, the price-drop switch, quotes with versions, extras, the client link and acceptance, trips and travellers, traveller changes and rebooking, booking documents, the live booking view with its fallback, and every screen in both languages on phone and desktop.
Tests that make a booking cancel it at the end, so the data stays clean.
Live supplier tests
The live suite (vitest.live.config.ts) calls the real suppliers’ test environments: search, price check, book and cancel. It spends real quota, so it isn’t part of the normal run. Every booking it makes is cancelled in a finally block, even when the test fails.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Mintlify Starter Kit","colors":{"primary":"#16A34A","light":"#07C983","dark":"#15803D"},"logo":{"light":"https://mintcdn.com/webbinghub/Iew7DZ8OHFCqnWms/logo/light.svg?fit=max\u0026auto=format\u0026n=Iew7DZ8OHFCqnWms\u0026q=85\u0026s=3386ba64e6fdf84ec70811e291f66f73","dark":"https://mintcdn.com/webbinghub/Iew7DZ8OHFCqnWms/logo/dark.svg?fit=max\u0026auto=format\u0026n=Iew7DZ8OHFCqnWms\u0026q=85\u0026s=3b22c58b1f30cb6f5996f2c1dfe41be0"},"favicon":"https://mintcdn.com/webbinghub/Iew7DZ8OHFCqnWms/favicon.svg?fit=max\u0026auto=format\u0026n=Iew7DZ8OHFCqnWms\u0026q=85\u0026s=bb6e1a0d256aec9563d804939f152390","navbar":{"links":[{"href":"mailto:support@mintlify.com","label":"Support"}],"primary":{"type":"button","label":"Dashboard","href":"https://app.mintlify.com"}},"footer":{"socials":{"x":"https://x.com/mintlify","github":"https://github.com/mintlify","linkedin":"https://linkedin.com/company/mintlify"}},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"webbinghub","hasAudioNarration":false,"actualSubdomain":"webbinghub","customDomains":["demo-travel.webbinghub.io"],"gitSource":{"type":"artifacts","owner":"prod","repo":"6af7296e413c65d2b0df2432","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":"","_id":"6af729ae902237199e11f7bb"},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6af79b4179feaadea80e2041","clientVersion":"0.0.4131","searchFilterCounts":[{"language":"default","tag":"Pipelines","count":6},{"language":"default","tag":"Suppliers","count":5},{"language":"default","tag":"Architecture","count":4},{"language":"default","tag":"Get started","count":2},{"language":"default","tag":"Operations","count":2}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"/docs","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"operations/testing","slug":"/operations/testing","pageMetadata":{"title":"How Omnibeds is tested","sidebarTitle":"Testing","description":"The four kinds of Omnibeds tests: unit tests with an in-process database, boundary tests that guard the layers, end-to-end tests of real screens, and live supplier tests.","keywords":["testing","vitest","playwright","boundaries","live tests"],"href":"/operations/testing"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"The four kinds of Omnibeds tests: unit tests with an in-process database, boundary tests that guard the layers, end-to-end tests of real screens, and live supplier tests.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,tbody:`tbody`,td:`td`,th:`th`,thead:`thead`,tr:`tr`,ul:`ul`,..._provideComponents(),...props.components},{Heading,Table,Tip}=_components;if(!Heading)_missingMdxReference(`Heading`,true);if(!Table)_missingMdxReference(`Table`,true);if(!Tip)_missingMdxReference(`Tip`,true);return _jsxs(_Fragment,{children:[_jsxs(_components.p,{children:[`Omnibeds has four kinds of tests, and each one answers a different question. Run the first three before every commit; run the live tests when you change a supplier adapter. The commands are on `,_jsx(_components.a,{href:`/quickstart`,children:`Run and test`}),`.`]}),`\n`,_jsxs(Table,{children:[_jsx(_components.thead,{children:_jsxs(_components.tr,{children:[_jsx(_components.th,{children:`Kind`}),_jsx(_components.th,{children:`Command`}),_jsx(_components.th,{children:`Answers`})]})}),_jsxs(_components.tbody,{children:[_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Unit`}),_jsx(_components.td,{children:_jsx(_components.code,{children:`npm test`})}),_jsx(_components.td,{children:`Does each piece do what it should?`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Boundaries`}),_jsxs(_components.td,{children:[`part of `,_jsx(_components.code,{children:`npm test`})]}),_jsx(_components.td,{children:`Are the layers still apart?`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`End to end`}),_jsx(_components.td,{children:_jsx(_components.code,{children:`npm run test:e2e`})}),_jsx(_components.td,{children:`Does the real app work, screen by screen?`})]}),_jsxs(_components.tr,{children:[_jsx(_components.td,{children:`Live suppliers`}),_jsx(_components.td,{children:_jsx(_components.code,{children:`npm run test:live`})}),_jsx(_components.td,{children:`Do the real suppliers still accept what we send?`})]})]})]}),`\n`,_jsx(Heading,{level:`2`,id:`unit-tests`,children:`Unit tests`}),`\n`,_jsxs(_components.p,{children:[`Unit tests (Vitest, in `,_jsx(_components.code,{children:`tests/`}),`) cover the domain: pricing, guest names by each supplier’s rules, quotes, trips, mapping, the orchestrator’s retries and breaker, and every command’s checks. Tests that need a database run against PGlite, an in-process Postgres, built from the same migrations as production. `,_jsx(_components.code,{children:`tests/migrations.test.ts`}),` checks a fresh database gets every migration once and every table the code uses, and that a failed migration rolls back.`]}),`\n`,_jsx(Heading,{level:`2`,id:`boundary-tests`,children:`Boundary tests`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`tests/boundaries.test.ts`}),` and `,_jsx(_components.code,{children:`tests/app-layer.test.ts`}),` keep the architecture from drifting. They fail when:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`a command has no route, or its route file doesn’t serve its method,`}),`\n`,_jsx(_components.li,{children:`a route that isn’t infrastructure does more than call a command,`}),`\n`,_jsxs(_components.li,{children:[`code in `,_jsx(_components.code,{children:`lib/`}),` imports from `,_jsx(_components.code,{children:`components/`}),`,`]}),`\n`,_jsx(_components.li,{children:`a screen imports server code,`}),`\n`,_jsxs(_components.li,{children:[`a screen writes a command’s URL instead of calling `,_jsx(_components.code,{children:`api()`}),`.`]}),`\n`]}),`\n`,_jsx(_components.p,{children:`They also check that each command’s checks run for every caller and that errors keep the one format.`}),`\n`,_jsx(Heading,{level:`2`,id:`end-to-end-tests`,children:`End-to-end tests`}),`\n`,_jsxs(_components.p,{children:[`Playwright tests in `,_jsx(_components.code,{children:`e2e/`}),` start the app and drive the real screens. They cover, among others: booking step by step (with a placeholder name prompted), a cheaper equivalent offered and taken, the price-drop switch, quotes with versions, extras, the client link and acceptance, trips and travellers, traveller changes and rebooking, booking documents, the live booking view with its fallback, and every screen in both languages on phone and desktop.`]}),`\n`,_jsx(Tip,{children:_jsx(_components.p,{children:`Tests that make a booking cancel it at the end, so the data stays clean.`})}),`\n`,_jsx(Heading,{level:`2`,id:`live-supplier-tests`,children:`Live supplier tests`}),`\n`,_jsxs(_components.p,{children:[`The live suite (`,_jsx(_components.code,{children:`vitest.live.config.ts`}),`) calls the real suppliers’ test environments: search, price check, book and cancel. It spends real quota, so it isn’t part of the normal run. Every booking it makes is cancelled in a `,_jsx(_components.code,{children:`finally`}),` block, even when the test fails.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"How Omnibeds is tested","sidebarTitle":"Testing","description":"The four kinds of Omnibeds tests: unit tests with an in-process database, boundary tests that guard the layers, end-to-end tests of real screens, and live supplier tests.","keywords":["testing","vitest","playwright","boundaries","live tests"],"href":"/operations/testing"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Unit tests","slug":"unit-tests","depth":2,"children":[]},{"title":"Boundary tests","slug":"boundary-tests","depth":2,"children":[]},{"title":"End-to-end tests","slug":"end-to-end-tests","depth":2,"children":[]},{"title":"Live supplier tests","slug":"live-supplier-tests","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"webbinghub","siteName":"Mintlify Starter Kit","title":"How Omnibeds is tested - Mintlify Starter Kit","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-13T23:16:43.203Z","originalFileLocation":"operations/testing.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"The four kinds of Omnibeds tests: unit tests with an in-process database, boundary tests that guard the layers, end-to-end tests of real screens, and live supplier tests.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Mintlify Starter Kit\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"How Omnibeds is tested - Mintlify Starter Kit\">\u003cmeta data-mint-head property=\"og:description\" content=\"The four kinds of Omnibeds tests: unit tests with an in-process database, boundary tests that guard the layers, end-to-end tests of real screens, and live supplier tests.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Mintlify Starter Kit\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://demo-travel.webbinghub.io/docs/operations/testing\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://webbinghub.mintlify.site/docs/_mintlify/api/og/v2?division=Operations\u0026amp;title=How+Omnibeds+is+tested\u0026amp;description=The+four+kinds+of+Omnibeds+tests%3A+unit+tests+with+an+in-process+database%2C+boundary+tests+that+guard+the+layers%2C+end-to-end+tests+of+real+screens%2C+and+live+suppl\u0026amp;theme=28ad0c88ff140d1c06c8cd29\u0026amp;signature=e95eeb7db456368694aae9773561ae90e24f7c79dff13c01844128b482feb001\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"How Omnibeds is tested - Mintlify Starter Kit\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"The four kinds of Omnibeds tests: unit tests with an in-process database, boundary tests that guard the layers, end-to-end tests of real screens, and live supplier tests.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://webbinghub.mintlify.site/docs/_mintlify/api/og/v2?division=Operations\u0026amp;title=How+Omnibeds+is+tested\u0026amp;description=The+four+kinds+of+Omnibeds+tests%3A+unit+tests+with+an+in-process+database%2C+boundary+tests+that+guard+the+layers%2C+end-to-end+tests+of+real+screens%2C+and+live+suppl\u0026amp;theme=28ad0c88ff140d1c06c8cd29\u0026amp;signature=e95eeb7db456368694aae9773561ae90e24f7c79dff13c01844128b482feb001\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/docs/mintlify-assets/_mintlify/favicons/webbinghub/SoZ-qChwfO1EVphr/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Mintlify Starter Kit\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#16A34A\">\u003clink data-mint-head rel=\"canonical\" href=\"https://demo-travel.webbinghub.io/docs/operations/testing\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/docs/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/operations/testing.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://demo-travel.webbinghub.io/#organization\",\"name\":\"Mintlify Starter Kit\",\"url\":\"https://demo-travel.webbinghub.io\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/webbinghub/Iew7DZ8OHFCqnWms/logo/light.svg?fit=max\u0026auto=format\u0026n=Iew7DZ8OHFCqnWms\u0026q=85\u0026s=3386ba64e6fdf84ec70811e291f66f73\"}},{\"@type\":\"WebSite\",\"@id\":\"https://demo-travel.webbinghub.io/docs#website\",\"name\":\"Mintlify Starter Kit\",\"url\":\"https://demo-travel.webbinghub.io/docs\",\"publisher\":{\"@id\":\"https://demo-travel.webbinghub.io/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://demo-travel.webbinghub.io/docs/operations/testing#webpage\",\"url\":\"https://demo-travel.webbinghub.io/docs/operations/testing\",\"name\":\"How Omnibeds is tested\",\"description\":\"The four kinds of Omnibeds tests: unit tests with an in-process database, boundary tests that guard the layers, end-to-end tests of real screens, and live supplier tests.\",\"dateModified\":\"2026-11-13T23:16:43.203Z\",\"isPartOf\":{\"@id\":\"https://demo-travel.webbinghub.io/docs#website\"},\"breadcrumb\":{\"@id\":\"https://demo-travel.webbinghub.io/docs/operations/testing#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://demo-travel.webbinghub.io/docs/operations/testing#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Operations\",\"item\":\"https://demo-travel.webbinghub.io/docs/operations/errors-and-logs\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How Omnibeds is tested\",\"item\":\"https://demo-travel.webbinghub.io/docs/operations/testing\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://demo-travel.webbinghub.io/docs/operations/testing#article\",\"headline\":\"How Omnibeds is tested\",\"name\":\"How Omnibeds is tested\",\"description\":\"The four kinds of Omnibeds tests: unit tests with an in-process database, boundary tests that guard the layers, end-to-end tests of real screens, and live supplier tests.\",\"url\":\"https://demo-travel.webbinghub.io/docs/operations/testing\",\"mainEntityOfPage\":{\"@id\":\"https://demo-travel.webbinghub.io/docs/operations/testing#webpage\"},\"dateModified\":\"2026-11-13T23:16:43.203Z\",\"keywords\":\"testing, vitest, playwright, boundaries, live tests\",\"publisher\":{\"@id\":\"https://demo-travel.webbinghub.io/#organization\"},\"isPartOf\":{\"@id\":\"https://demo-travel.webbinghub.io/docs#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Mintlify Starter Kit\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"Mintlify Starter Kit\"},\"provider\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","agentPointerHref":"/docs/operations/testing.md","siteName":"Mintlify Starter Kit","nav":{"global":null,"pages":[{"group":"Get started","pages":[{"title":"Omnibeds: how the platform is built and how it works","sidebarTitle":"Introduction","href":"/index"},{"title":"Run Omnibeds locally and check a change","sidebarTitle":"Run and test","href":"/quickstart"}]},{"group":"Architecture","pages":[{"title":"The layers of Omnibeds and how a request moves through them","sidebarTitle":"Layers","href":"/architecture/layers"},{"title":"Commands: every action with its risk and its checks","sidebarTitle":"Commands","href":"/architecture/commands"},{"title":"Data: migrations, agency scope and transactions","sidebarTitle":"Data","href":"/architecture/data"},{"title":"Front end: screens call the server through one typed client","sidebarTitle":"Front end","href":"/architecture/front-end"}]},{"group":"Pipelines","pages":[{"title":"Search pipeline: from one query to one merged list","sidebarTitle":"Search","href":"/pipelines/search"},{"title":"Booking pipeline: price check, guests, review, confirmation","sidebarTitle":"Booking","href":"/pipelines/booking"},{"title":"Quote lifecycle: from draft to booking","sidebarTitle":"Quotes","href":"/pipelines/quotes"},{"title":"Trips and saved travellers: one journey from search to booking","sidebarTitle":"Trips and travellers","href":"/pipelines/trips"},{"title":"After booking: live view, traveller changes, rebooking, price drops","sidebarTitle":"After booking","href":"/pipelines/after-booking"},{"title":"Reconciliation and the scheduled jobs","sidebarTitle":"Reconciliation and jobs","href":"/pipelines/jobs"}]},{"group":"Suppliers","pages":[{"title":"Supplier adapters: one contract for every supplier","sidebarTitle":"Adapters","href":"/suppliers/adapters"},{"title":"Confidential suppliers and presenter mode","sidebarTitle":"Confidential suppliers","href":"/suppliers/confidential"},{"title":"Hotelbeds integration: rules, flow and mapping","sidebarTitle":"Hotelbeds","href":"/suppliers/hotelbeds"},{"title":"LiteAPI integration: rules, flow and mapping","sidebarTitle":"LiteAPI","href":"/suppliers/liteapi"},{"title":"RateHawk integration: rules, flow and mapping","sidebarTitle":"RateHawk","href":"/suppliers/ratehawk"}]},{"group":"Operations","pages":[{"title":"Errors, traces and supplier health","sidebarTitle":"Errors and logs","description":"Every Omnibeds failure answers in one format with a plain reason and, when unexpected, a trace id. See the error codes, the Inspector, retention and the Health page.","href":"/operations/errors-and-logs"},{"title":"How Omnibeds is tested","sidebarTitle":"Testing","href":"/operations/testing"}]}]},"basePath":"","title":"How Omnibeds is tested - Mintlify Starter Kit","buildId":"dpl_Eok1jboeiLTUE4ccnKdogAktkDhH","deploymentId":"dpl_Eok1jboeiLTUE4ccnKdogAktkDhH","dynamics":[],"chunks":[]}