This episode covers component testing with Cypress for React, Vue, and Angular, setting up the component test environment, behavior-based component assertions, and integration with Storybook and UI libraries.

Episode 8 closed out the advanced interactions phase. Now you step down one level: from testing full pages to testing components in isolation. Episode 9 covers component testing with Cypress for React, Vue, and Angular — setting up the component environment, writing behavior-based component assertions, and integrating with Storybook and UI libraries.
Why does component testing matter? Full pages are slow and depend on many things: the router, the backend, and global state. Components can be tested on their own, much faster, and they show exactly which component is broken without digging through an entire application flow.
Component testing runs a single UI component in a real browser, complete with events, styling, and interactions, but without loading the entire application. Unlike unit tests that run components in a simulated runtime, Cypress renders components in a real browser — so the behavior you see matches exactly what users experience.
First, install component testing support for your framework:
npm install -D cypress @cypress/react @cypress/vite-dev-serverThe command npm install -D cypress @cypress/react @cypress/vite-dev-server adds React rendering support with the Vite dev server. For Vue, replace @cypress/react with @cypress/vue; for Angular use @cypress/angular.
Add a component block in cypress.config.js:
const { defineConfig } = require("cypress");
module.exports = defineConfig({
component: {
devServer: {
framework: "react",
bundler: "vite",
},
},
});framework: "react" tells Cypress which framework to use for loading components. The value bundler: "vite" uses Vite, which is also used by modern frontend tooling such as Next.js and other Vite-based frameworks.
Component specs live next to the component, or in a separate folder. Here is an example test for a Tombol component:
import React from "react";
import { mount } from "cypress/react";
import Tombol from "./Tombol";
describe("Tombol", () => {
it("menampilkan teks dan merespons klik", () => {
const onClick = cy.stub();
mount(<Tombol label="Kirim" onClick={onClick} />);
cy.get("[data-cy=tombol]").should("have.text", "Kirim");
cy.get("[data-cy=tombol]").click();
expect(onClick).to.have.been.calledOnce;
});
});mount(<Tombol label="Kirim" onClick={onClick} />) renders the component in the browser. cy.stub() creates a mock function to check that onClick was called — this is the behavior-based assertion pattern.
Cypress runs a dev server in the background. This mode is much faster than loading the full application because only the components in use are compiled. You can open specs with a dedicated command:
npx cypress open --componentnpx cypress open --component opens the Test Runner in component mode. Pick a component spec and the test runs directly, usually within seconds.
Avoid asserting on fragile DOM details. Focus on behavior: visible text, changed state, and interactions that work:
it("menampilkan spinner saat loading", () => {
mount(<DaftarProduk loading />);
cy.get("[data-cy=spinner]").should("be.visible");
cy.get("[data-cy=daftar]").should("not.exist");
});
it("menampilkan produk setelah load", () => {
mount(<DaftarProduk items={produk} />);
cy.get("[data-cy=daftar]").children().should("have.length", 3);
});mount(<DaftarProduk loading />) renders the component with the same props as a unit test, but in a real browser. The assertion .should("have.length", 3) verifies the rendered product list.
For components that change state, click and verify the result like a regular E2E test:
it("mengirim status setelah tombol diklik", () => {
mount(<FormStatus />);
cy.get("[data-cy=kirim]").click();
cy.get("[data-cy=status]").should("have.text", "Terkirim");
});cy.get("[data-cy=kirim]").click() mimics a user click, then the have.text assertion checks that the component state changed. This is what behavioral testing means — checking what the component does, not how it is implemented.
Storybook offers a story for every component state. Cypress can use those stories as the basis for tests:
npx cypress run --config baseUrl=http://localhost:6006npx cypress run --config baseUrl=http://localhost:6006 points tests at the Storybook dev server. Each story acts like a page containing a component in a particular state — ideal for state exploration and visual testing.
For UI libraries like MUI, Chakra, or Ant Design, the components are already tested by their maintainers. Focus your tests on how they are used in your application: forms built from library components, validation combinations, and interaction flows. Create a custom mount command to wrap the provider:
Cypress.Commands.add("mountUI", (komponen) => {
mount(<TemaProvider>{komponen}</TemaProvider>);
});Cypress.Commands.add("mountUI", ...) wraps the mount with the theme provider so every library component gets the right context. This pattern avoids repeating the provider in every test.
Tip
Use data-cy on elements inside components, just like in E2E. Component testing with stable selectors survives major component refactors.
Episode 9 took you from testing pages to testing components: component testing for React, Vue, and Angular in a real browser, dev server configuration in cypress.config.js, behavior-based assertions with mount and cy.stub, and integration with Storybook and UI libraries.
Key takeaways:
@cypress/react, @cypress/vue, or @cypress/angular.component block of cypress.config.js.In the next episode, episode 10, you will weave all the interactions together into end-to-end flows — structuring end-to-end test scenarios, login, checkout, and multi-page journeys, managing the state of the application under test, and deterministic data setup and teardown. This is the real essence of E2E testing.