Skip to content

Testing

Syncraft Labs stores state in IndexedDB, which doesn’t exist in Node.js test environments. This guide shows how to set up your test environment and write effective tests.


This polyfill provides an in-memory IndexedDB implementation for Node.js:

Terminal window
npm install -D fake-indexeddb
vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "jsdom",
setupFiles: ["./src/__tests__/setup.ts"],
},
});
src/__tests__/setup.ts
import "fake-indexeddb/auto";
// fake-indexeddb/auto sets up global indexedDB, IDBKeyRange, etc.

Every test must wrap the rendered component in <SyncraftProvider>:

import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { SyncraftProvider, useSync } from "@syncraft-labs/react";
import { describe, it, expect } from "vitest";
interface TodoState {
todos: Array<{ id: string; text: string }>;
}
function TestApp() {
const { data, update, isHydrating } = useSync<TodoState>("test-todos", {
initialState: { todos: [] },
});
if (isHydrating) return <div>Loading…</div>;
return (
<div>
<button
onClick={() =>
update((draft) => {
draft.todos.push({ id: "1", text: "Buy milk" });
})
}
>
Add
</button>
<ul>
{data?.todos.map((t) => (
<li key={t.id}>{t.text}</li>
))}
</ul>
</div>
);
}
describe("TestApp", () => {
it("adds a todo item optimistic update", async () => {
render(
<SyncraftProvider>
<TestApp />
</SyncraftProvider>
);
// Wait for hydration
await waitFor(() => {
expect(screen.queryByText("Loading…")).toBeNull();
});
// Trigger update
fireEvent.click(screen.getByText("Add"));
// Verify optimistic UI update
expect(screen.getByText("Buy milk")).toBeDefined();
});
});

Use @vue/test-utils and mount with createSyncraft() plugin:

import { mount } from "@vue/test-utils";
import { createSyncraft } from "@syncraft-labs/vue";
import { describe, it, expect } from "vitest";
import TodoComponent from "./TodoComponent.vue";
describe("TodoComponent", () => {
it("renders correctly", async () => {
const wrapper = mount(TodoComponent, {
global: {
plugins: [createSyncraft()],
},
});
await wrapper.vm.$nextTick();
expect(wrapper.text()).toContain("Add Todo");
});
});

To ensure test isolation, clean up stores between test runs:

import { beforeEach } from "vitest";
import { _resetRegistry } from "@syncraft-labs/react";
beforeEach(() => {
// Clear any existing store singletons
// When using <SyncraftProvider>, a fresh registry is created automatically per render
});