Workplace Image eurofunk Kappacher GmbH

Cypress Component Tests

Description

Patrick Pichler von eurofunk Kappacher demonstriert in seinem devjobs.at TechTalk die Herangehensweise des Teams, wie sie Component Tests mit cypress durchführen.

By playing the video, you agree to data transfer to YouTube and acknowledge the privacy policy.

Video Summary

In "Cypress Component Tests," Patrick Pichler (eurofunk Kappacher GmbH) explains how Cypress Component Testing bridges the gap between unit and end-to-end tests—motivated by Angular unit-testing pain points (configuration, DOM interaction, async, change detection, HTTP mocks) and slow, complex E2E/Storybook setups. Using a login-form demo, he shows the runner and concrete techniques: mounting with providers, custom commands, passing inputs (including Signals) and outputs (CreateOutputSpy), template-based integration, DI access, and HTTP mocking with cy.intercept. After migrating, their CI drops Storybook and runs around 259 component tests in about three minutes, giving fast, actionable feedback that teams can apply to test frontend components in isolation.

Cypress Component Tests for Angular: How Patrick Pichler (eurofunk Kappacher GmbH) closes the gap between Unit and E2E

Context: Real quality needs, real testing pain

In “Cypress Component Tests,” Patrick Pichler from eurofunk Kappacher GmbH shares how his team rebalanced their frontend testing strategy. Pichler has 17 years of professional experience with a strong frontend focus and works on the EOX (Eurofunk Operations Center Suite). eurofunk Kappacher GmbH delivers complete control center solutions—hardware, software, multimedia integration, video walls, furniture, servers, and cable management. Pichler works in the “Products Foundation” department, building platform capabilities so stream-aligned teams can ship features faster.

Quality is non-negotiable, but the reality of testing often drifts from the ideal. The classic testing pyramid says: many unit tests, fewer integration tests, and very few end-to-end (E2E) tests. In Pichler’s department, the actual situation was different: many unit tests, almost no integration tests, and a lot of E2E tests with Cypress. They didn’t consciously choose that path—it “just happened,” largely due to their stack (Angular) and the friction around conventional component testing.

Where classic Angular unit tests hurt

Pichler points to five recurring pain points in Angular unit testing: test configuration, DOM interaction, asynchrony, change detection (synchronization), and HTTP mocks.

1) Test configuration

  • Understanding the Angular module system raises the complexity of the setup. Standalone helps in newer Angular versions, but the friction doesn’t vanish.
  • You must provide all dependencies in the testbed. That implies knowing how the component is wired in the app and replicating it for tests.
  • Deciding what to mock is on you—core features like routing and HTTP often require explicit mocking.

2) DOM interaction

  • Simple checks often produce surprising boilerplate. Grabbing a paragraph and asserting its text is not hard—but it is cumbersome.
  • For inputs and reactive elements, you must simulate native browser behavior precisely. The wrong events mean you’re not testing real user behavior. This is not Angular-specific and trips up newcomers in particular.

3) Asynchrony

  • “Asynchrony is just hard in general.” The correct use of fakeAsync and async depends on context and is easy to misuse.
  • tick and flush in fakeAsync are conceptually tricky; timing-driven failures make debugging hard.
  • zone.js monkey-patches setTimeout and setInterval. Pure async/await can sidestep Angular’s machinery, leading to unexpected effects.

4) Change detection (synchronization)

  • In tests, you sometimes need to trigger change detection manually, unlike in the real app runtime.
  • Combined with asynchrony, timing pitfalls multiply.
  • With the OnPush strategy, complexity increases even further.

5) HTTP mocks

  • Angular’s HttpTestingController adds its own learning curve.
  • Asynchrony, change detection, and HTTP combine into a tricky trio.
  • Mocking error responses isn’t as straightforward as the API might suggest.

The broader effect is familiar: these pain points push more scenarios up into E2E land—exactly what the testing pyramid warns against.

E2E with Cypress: powerful—and expensive in turnaround time

For end-to-end testing, eurofunk Kappacher GmbH uses Cypress. The runner shows test steps on the left and renders the real application on the right. Pichler estimates “around 1,000” E2E tests by a quick filename search—across his project and others.

With that much Cypress experience, the team tried a natural idea: run Cypress against isolated components to speed up frontend integration testing. The first iteration paired Cypress with Storybook.

Storybook + Cypress: good in theory, too slow in practice

The CI pipeline looked like this:

  1. Build Storybook (produce artifacts)
  2. Start a Node-based HTTP server to serve the artifacts
  3. Build Cypress (bundle tests)
  4. Run Cypress against the local server

It worked—but it took “10+ minutes” even for just a few tests. Two build processes, an extra HTTP server, and Storybook (version 6 at the time) created significant friction for fast feedback.

Familiar E2E pain points

Pichler summarizes the known drawbacks of E2E testing:

  • Slower than unit or integration tests due to real user interaction and reactivity.
  • Longer feedback cycles slow development. In their case, E2E tests don’t run with every CI but on a schedule several times a day—so feedback can arrive hours after deploys, with all the context-switching that implies.
  • Flakiness erodes trust. Environmental hiccups—from network issues to service dependencies—can cause spurious failures.
  • Complex setup and debugging. You end up debugging a mini production-like environment instead of an isolated component.
  • Infrastructure cost and realistic test data management add up.

Cypress Component Testing aims squarely at this gap.

Cypress Component Testing: isolation plus real DOM interaction

Cypress Component Testing sits between unit and E2E tests. Supported frameworks include React, Angular, Vue, and Svelte (at the time of the talk). The idea: mount components in isolation, interact with them through the real DOM, and let Cypress manage asynchrony for you.

Practical advantages

  • Isolated components with the precision and control of unit tests.
  • No manual async handling: Cypress does the waiting, like in E2E.
  • No manual change detection: the component behaves as it does in the app rather than in a synthetic test harness.
  • Strong developer experience: clear step-by-step UI, screenshots, and CI videos when needed.
  • Speed: no backend setup, no Storybook/server overhead—feedback loops are much faster.

“The developer experience is great … and of course, the speed is increased.”

Limits and trade-offs

  • Test configuration still matters: you must supply what the component needs to run.
  • Time control: Cypress’s clock control currently conflicts with Angular’s and React’s change detection; there’s an open bug.
  • Tests without DOM interaction don’t make sense in a UI-focused framework.

Pipeline after migration: one command, minutes instead of ten-minute chunks

The team removed the Storybook and HTTP server steps entirely. The new CI pipeline consists of a single Cypress command that builds and tests.

  • In a project with 259 tests, CI runtime is about 3 minutes (compilation plus execution).
  • Locally: compile once, then a file watcher; a full run completes in about 1 minute.
  • During development: focusing on a single test yields runtimes in seconds.
  • Their goal is feedback in under 5 minutes per job—met comfortably.

For a platform group enabling feature teams, that turnaround is a meaningful productivity gain.

The demo: login form, mount mechanics, and a better debugging loop

To illustrate, Pichler uses a login form (“GooseCorp”) with live validation and a delayed banner confirming success or failure after a few seconds.

Cypress runner and browser choice

On startup, Cypress clearly differentiates between end-to-end and component tests. You can choose the target browser—e.g., Chrome—and verify both behavior and styling across different browsers if needed.

Step-by-step visibility

The runner lists test steps on the left and shows the rendered component on the right. The debugging story is where Cypress feels compelling:

  • You can open individual steps; the targeted element is highlighted on the right.
  • Pinning an element lets you inspect details via DevTools—how many elements matched, returned nodes, and more.
  • Cypress shows the exact click coordinates and ensures the element is truly clickable (visible, not covered). If not, you get a clear error message.

“Cypress checks whether an element is clickable … and throws an error if the coordinates wouldn’t produce a click event.”

Test structure and mounting: familiar syntax, focused providers

Cypress Component Testing uses the familiar describe, beforeEach, and it structure. The key is the mount call and the test-specific configuration it encapsulates.

  • Pichler mounts the login component and provides what it needs—an animation configuration and an internal icon library via provideIcons.
  • DOM queries use cy.get with a jQuery-like syntax. Assertions such as be.visible are straightforward and come with autocompletion.
  • type simulates real typing, character by character, and triggers the right browser events. click verifies clickability and performs robust interactions.

The effect: less cognitive load. You focus on behavior rather than event simulation and change detection nudges.

Comfort layer: custom commands for mounting and selectors

To reduce boilerplate further, Pichler’s team adds custom commands:

  • A custom mount that always injects default providers—animations and icons—so every component gets what it needs without repeated setup.
  • A getByQA command that targets data-qa attributes for stable selectors and readable tests.

This trims down test code and keeps intent front and center.

Inputs, live updates, and outputs: drive the component like the app would

Inputs at mount time

Using “component properties” in the mount setup, you can bind inputs directly—e.g., setting a custom info message instead of a default prompt.

Live updates with signals

To change inputs after mount, Pichler uses signals. Create a signal, bind it as an input, and set a new value later. Change detection and UI updates follow automatically—ideal for dynamic test scenarios. Signals are a larger topic in itself; the talk focuses on practical test usage.

Outputs with CreateOutputSpy

For component outputs (events), Cypress provides CreateOutputSpy. For example, an afterLogin output can be spied, given an alias, and asserted with familiar patterns—“called once,” “called with parameters,” and so on.

Component-level integration: template syntax for cooperating parts

Some questions involve more than one component. A typical case is an accordion with panels. Cypress Component Testing supports a template string syntax to compose multiple components. Inputs and outputs are bound using standard Angular syntax.

One subtlety: when using a template, componentProperties refer to a generic host component. It’s helpful to define an interface capturing all bound inputs and spies—e.g., infoMessage and afterLoginSpy—for clarity and type safety.

Access instances and DI: fixture, injector, and component instance

After mounting, Cypress exposes a wrapper that includes a fixture. You can use it to reach the Angular injector, pull in a service, set spies, or interact with dependencies. The component instance itself is also available when you need to assert static properties or inspect internal state. Pichler shows how to work through the injector; accessing the component instance is likewise part of the wrapper.

HTTP mocking: three approaches—one usually best

Sooner or later, a component fires network requests. In tests, you typically don’t want to leave the process—for stability and speed.

Pichler demonstrates three patterns:

  1. Override the service: Replace the calling service with a mock that returns test data. Simple and effective.
  2. Use Angular’s HttpTestingController: Set it up via provideHttpTestingClient, intercept requests, and flush responses. Possible—but not the preferred approach here.
  3. Use Cypress intercept: Define a URL pattern, stub the response, give it an alias, and wait on the request. Then assert against the UI. For this use case, this is “probably the right way.”

The third option aligns best with Cypress’s strengths: real DOM interaction, Cypress-managed timing, and visible effects in the UI.

Why this matters: speed, trust, focus

Pichler’s core message:

  • Cypress Component Testing helps restore the testing pyramid in practice. Isolated, fast tests catch many scenarios that would otherwise drift into E2E.
  • Cypress takes on tricky async and interaction details. Engineers focus on behavior rather than hand-crafting event and change detection mechanics.
  • The pipeline becomes lean, with feedback in minutes. This fits CI goals—“under five minutes per job.”
  • E2E remains important—but not by default for component concerns. Keep it for true system integration, where infrastructure and networks must be part of the picture.

“Cypress Component Tests are a great tool to fill the gap between end-to-end and unit tests.”

Practical takeaways for Angular teams

  • Own your test configuration. Invest in a custom mount command with default providers. It pays off immediately and compounds over time.
  • Use data-qa attributes with a getByQA command to keep selectors stable and your tests readable.
  • Simulate user behavior with Cypress commands like type and click. Rely on Cypress’s built-in checks—such as clickability—instead of ad-hoc heuristics.
  • Bind inputs at mount and use signals for live updates. That’s a realistic way to test dynamic UIs without manual change detection.
  • Verify outputs via CreateOutputSpy. It feels like unit testing, but with a real DOM layer in the loop.
  • For multi-component behavior, adopt the template syntax and define a host interface for clean bindings.
  • When HTTP is involved, start with intercept. Override services when your architecture calls for it; reach for HttpTestingController only when you have a strong reason.
  • Reserve E2E for system-level behavior. For component logic and interaction, component tests are the efficient first line.

Closing

Patrick Pichler demonstrates how Cypress Component Testing removes practical friction in an Angular stack: less boilerplate, no manual async or change detection juggling, and more genuine interaction and visibility. By moving away from Storybook-driven tests toward pure Cypress Component Testing, the team reduced the pipeline to a single command and brought runtimes down from “10+ minutes” to just a few minutes for hundreds of tests.

For teams like those at eurofunk Kappacher GmbH, who deliver sophisticated frontends under real constraints, that’s a compelling lever. The testing pyramid becomes real again: unit and component tests shoulder most of the load, while E2E covers the true integration edges. The payoff is faster feedback, more stable tests, and higher confidence in what matters most—the quality of the behavior you ship.

More Tech Talks

More Tech Lead Stories

More Dev Stories