@roughapp/replimock v15.1.0
Replimock
A lightweight, intuitive testing utility for mocking Replicache clients in your unit and integration tests.
Why Use Replimock?
When building applications with Replicache, testing can be challenging because the real Replicache client requires IndexedDB and a full sync infrastructure. Replimock solves this problem by providing:
- Simplified Testing: Test your Replicache mutators and queries without the need for a real database or sync infrastructure
- Fast Tests: No network or indexedDB means your tests run lightning fast
- Predictable Environment: Full control over the Replicache client state for deterministic testing
- API Compatibility: Works with the standard Replicache client API, so your tests reflect real usage
Installation
# Using npm
npm install @roughapp/replimock --save-dev
# Using yarn
yarn add @roughapp/replimock --dev
# Using pnpm
pnpm add @roughapp/replimock --save-devUsage
Replimock provides a simple API to create a mock Replicache client that mimics the behavior of a real Replicache client.
Basic Example
import { mockReplicache } from '@roughapp/replimock';
import { expect, test } from 'vitest'; // or your testing framework of choice
test('should add a new todo', async () => {
// Create a mock Replicache client
const rep = mockReplicache({
mutators: {
addTodo: async (tx, todo) => {
await tx.set(`todo/${todo.id}`, todo);
return todo;
},
},
});
// Use the mock client just like you would use a real Replicache client
const todo = await rep.mutate.addTodo({ id: '123', text: 'Buy milk', done: false });
// Query the data to verify the mutation worked
const storedTodo = await rep.query(tx => tx.get(`todo/${todo.id}`));
expect(storedTodo).toEqual({ id: '123', text: 'Buy milk', done: false });
});With Initial Data
You can initialize the mock client with data:
const rep = mockReplicache({
initialData: {
'todo/1': { id: '1', text: 'Existing todo', done: false },
'todo/2': { id: '2', text: 'Another todo', done: true },
},
mutators: {
// your mutators here
},
});
// Query existing data
const todos = await rep.query(tx => tx.scan({ prefix: 'todo/' }).values().toArray());
console.log(todos); // will include the initial dataTesting Watchers
Replimock supports the experimentalWatch API for testing reactive code:
import { mockReplicache } from '@roughapp/replimock';
import { vi } from 'vitest';
test('should call watcher when data changes', async () => {
const rep = mockReplicache({
mutators: {
addTodo: async (tx, todo) => {
await tx.set(`todo/${todo.id}`, todo);
},
},
});
const watcher = vi.fn();
rep.experimentalWatch(watcher, { prefix: 'todo/' });
// Trigger a mutation that should notify the watcher
await rep.mutate.addTodo({ id: '123', text: 'New todo', done: false });
// Wait for the next tick to allow the callback to be called
await new Promise(resolve => setTimeout(resolve, 0));
expect(watcher).toHaveBeenCalledWith([
{
op: 'add',
key: 'todo/123',
newValue: { id: '123', text: 'New todo', done: false }
}
]);
});API
mockReplicache(options)
Creates a mock Replicache client.
Options:
mutators: Object containing mutator functions (required)initialData: Object containing initial data to populate the store (optional)
The returned mock client implements the Replicache API, focusing on the most commonly used features:
query: Execute read-only operationsmutate: Execute mutationsexperimentalWatch: Watch for changes to data
Limitations
Replimock aims to provide a testing environment that's faithful to the real Replicache API, but there are some limitations:
- Indexes are not fully supported
- Some advanced features like conflict resolution might behave differently
- Network-related features (push/pull/sync) are stubbed out
License
MIT
Contributing
Contributions are welcome! Please feel free to open issues or PRs on GitHub.