Testing
BlaC provides first-party testing utilities so you can write fast, isolated tests for your cubits and the components that use them. The utilities live in two entry points:
@blac/core/testing— registry isolation, state seeding, stubs, and method mocks@blac/react/testing— React component rendering with controlled bloc state
Both are tree-shakable and shipped as separate entry points, so they are never included in your production bundle.
Installation
Section titled “Installation”The core testing utilities have no extra dependencies. Install your test runner of choice (Vitest is recommended):
pnpm add -D vitestnpm install -D vitestyarn add -D vitestFor React component tests, you also need @testing-library/react:
pnpm add -D @testing-library/reactnpm install -D @testing-library/reactyarn add -D @testing-library/reactWhy registry isolation matters
Section titled “Why registry isolation matters”BlaC stores every bloc instance in a single global registry. That is what lets any component call useBloc(CounterCubit) and reach the same instance without prop drilling. In tests, that same shared-by-default behavior works against you: a bloc created or mutated in one test is still in the registry when the next test runs, so tests leak state into each other and fail depending on execution order.
The mental model for testing BlaC is therefore simple: give every test its own registry. Once each test starts from an empty registry, the shared-instance model becomes a feature again — you seed exactly the instances a test needs and nothing carries over.
Every testing utility in this guide is built around that idea. The most common approach is blacTestSetup(), which swaps in a fresh registry before each test and restores the original after:
import { describe, it, expect } from 'vite-plus/test';import { blacTestSetup } from '@blac/core/testing';import { ensure } from '@blac/core';
blacTestSetup();
describe('CounterCubit', () => { it('starts at zero', () => { const counter = ensure(CounterCubit); expect(counter.state.count).toBe(0); });
it('does not see state from the previous test', () => { // This test gets a completely fresh registry const counter = ensure(CounterCubit); expect(counter.state.count).toBe(0); });});Quick start
Section titled “Quick start”Testing a cubit in isolation
Section titled “Testing a cubit in isolation”import { it, expect } from 'vite-plus/test';import { blacTestSetup, withBlocState } from '@blac/core/testing';import { ensure } from '@blac/core';import { TodoCubit } from '../blocs/TodoCubit';
blacTestSetup();
it('adds an item', () => { const todo = ensure(TodoCubit); todo.addItem('Buy milk'); expect(todo.state.items).toHaveLength(1);});
it('can start with seeded state', () => { withBlocState(TodoCubit, { items: ['Existing item'] }); const todo = ensure(TodoCubit); expect(todo.state.items).toHaveLength(1);});Testing a React component
Section titled “Testing a React component”import { it, expect } from 'vite-plus/test';import { screen } from '@testing-library/react';import { renderWithBloc } from '@blac/react/testing';import { Counter } from '../components/Counter';import { CounterCubit } from '../blocs/CounterCubit';
it('displays the current count', () => { renderWithBloc(<Counter />, { bloc: CounterCubit, state: { count: 42 }, }); expect(screen.getByText('42')).toBeInTheDocument();});See also
Section titled “See also”- Core Testing API — the full helper reference (
blacTestSetup, stubs, overrides, seeding) - React Testing API — rendering components with controlled bloc state
- Instance Management — the registry these helpers isolate
- Glossary — definitions for registry, stub, override, instance key