API contracts don’t protect Vue 3 frontends. Integration tests do.
In a previous article, we looked at Vue 3 reactivity and how something elegant and powerful can occasionally work against us. This time, we move slightly higher in the stack and focus on a different illusion, one that is deeply rooted in modern frontend and backend collaboration.
The idea that a passing API contract means the frontend is safe.
API contracts are formal, automated, and reassuring. When they pass, pipelines turn green and deployments feel justified. The problem is that contracts answer a very specific question, and it is not the one users care about.
A contract tells you whether a response is valid. It does not tell you whether the application still works.
So, in layman’s words, it’s a classic case of “the operation was extremely successful, unfortunately the patient is dead” – how ironic.
When everything is OK but the UI is not
Most teams have lived through a variation of this scenario.
A backend endpoint evolves as new requirements appear.
A new optional field is added or an existing one becomes richer.
OpenAPI or Pact tests pass without hesitation.
A limited set of end to end tests runs on the happy paths.
The release goes out.
Shortly after, subtle issues appear.
A dashboard renders an empty state with no visible error.
A computed property behaves differently because undefined became null or an empty string or something.
A longer string stretches a layout and pushes an important action out of view.
It’s important to highlight that:
From the backend perspective, nothing broke
From the contract perspective, everything is correct
From the user perspective, something is clearly wrong
How could this happen you ask? Why do backenders hate frontenders you wonder? I’m afraid I can only answer the former, so let’s start with that.
What API contracts do and do not protect
API contracts are not the enemy. They are extremely good at what they are designed to do.
They protect:
The shape of requests and responses, consistency you might say
Required and optional fields,
Types and structural compatibility
They do not protect:
How the frontend branches on data
How Vue templates react to new or newly populated fields
How real data affects layout, visibility, and interaction
These problems only appear when real responses flow through real components.
That is an integration problem, not a contract problem.
The jsdom comfort zone and its hard limits
For years, Vue component tests have been executed in Vitest or Jest using jsdom. This setup is fast, accessible, and well suited for unit level testing. It becomes problematic when the goal shifts to verifying real integrations.
jsdom is not a browser. It is a JavaScript approximation of one. That distinction matters in several practical ways.
There is no real browser network stack. CORS, cookies, and modern fetch behavior are simplified or missing
There is no layout engine. jsdom cannot tell you whether something is visible, overlapped, or pushed off screen
Many modern Web APIs are missing or incomplete, leading to heavy mocking
At that point, tests start validating assumptions instead of behavior.
If the question is whether a real API change breaks the UI, a simulated browser is simply not enough.
Running integration tests where users actually are
Instead of extending the simulation, we moved the tests into a real browser.
Vitest Browser Mode, using Playwright under the hood, allows Vue tests to run inside actual browser engines such as Chromium, Firefox, and WebKit.
This creates a useful middle ground.
It is not a full end to end test
It does not require navigation flows or authentication
It focuses on components and compositions, not entire applications
At the same time, it gives us:
Real network behavior
Real CSS and layout calculations
The full Vue lifecycle as it runs in production
The environment stops being theoretical and starts behaving like the user’s machine.
Using snapshots as a functional safety net
Once tests run in a real browser, snapshots become far more meaningful.
We treat the API response as input and the rendered UI as output.
Key aspects of this approach:
We snapshot real API payloads from staging or production, not idealized mocks
These payloads can include edge cases such as large strings, null values, and deeply nested objects
We snapshot the rendered DOM, not just data structures
A simplified example looks like this:
If an API change causes a conditional rendering to flip or a computed property to behave differently, the snapshot fails immediately in CI.
No manual verification is required.
When the DOM is correct but the UI Is still broken
DOM snapshots are effective, but they are not the final word. It is entirely possible for the HTML structure to be correct while the visual result is not.
To catch these cases, we are adding visual regression testing using Playwright powered screenshot comparisons.
This allows us to detect:
Layout shifts caused by unexpected content
Components overflowing or collapsing
Visual regressions that contracts and DOM snapshots cannot describe
At this point, the test does not just verify correctness. It verifies that literally nothing has been damaged in the process (pretty cool right?)
Peace of mind is the real outcome
The primary benefit of this approach is not higher test coverage. It is confidence.
When the frontend is automatically verified against real API responses:
Backend teams can evolve APIs more freely
Adding new fields becomes trivial, not riskier
Frontend robustness is continuously validated, not assumed
We moved from hoping the UI would survive API changes to know for a fact that it did. Not bad right?
By stepping outside the limits of jsdom and embracing real browser based integration testing with Vitest and Playwright, we gained something extremely valuable, a reliable way to make sure that a butterfly that flaps its wings in Brazil, won’t create a hurricane somewhere else.
If anybody tells you this not impressive, you do not need that person in your life, I assure you.
Thanks for your time, we hope this can help you too!
These Solutions are Engineered by Humans
Did you find this article interesting? Does it match your skill set? Programming is at the heart of how we develop customized solutions. In fact, we’re currently hiring for roles just like this and others here at Würth Phoenix.
UX Front-end engineer by day, UX wizard by night, and an Interaction design ninja all the time. Always on the hunt for those ‘wow, didn’t see that coming!’ solutions to problems.
Author
Marco Berlanda
UX Front-end engineer by day, UX wizard by night, and an Interaction design ninja all the time. Always on the hunt for those ‘wow, didn’t see that coming!’ solutions to problems.
At first glance, rebuilding an RPM may sound like a purely mechanical task: take a patch, rebuild the package, ship it. In reality, that small fix goes through a much longer journey that touches reliability, security, trust, and long-term maintainability. Read More
If you've ever tried integrating an external system or website with Jira Service Management (JSM), you've probably hit one or more roadblocks, especially when it comes to creating requests on behalf of end users without using the default Jira Service Read More
Let me start by saying: sure React is great, Angular is enterprise-ready, but my love falls on Vue. The reactivity system? Chef's kiss. Watching values magically update the DOM like it's reading your mind? Ammmazing. But sometimes, it feels less Read More
At the beginning of March 2025, my colleague Oscar and I attended the VueJS Amsterdam 2025 conference, and among the hundreds of very cool new concepts and ideas we had a chance to discover, one particular talk stood out for Read More
We recently completed the update of the Tornado UI from Vue 2 to Vue 3. This was a major upgrade that required careful planning and execution. To ensure a smooth transition, we followed the official migration guide provided by the Read More