Skip to main content
Create project
Reference

Testing

Test utilities for mocking the Sheepit SDK in unit tests, integration tests, and Storybook.

TestProvider

A test-only provider that accepts a partial client mock. Import from @sheepit-ai/react/test:

test-utils.tsx
import { TestProvider } from "@sheepit-ai/react/test";

function renderWithGoaTech(ui: React.ReactElement, overrides = {}) {
  return render(
    <TestProvider client={{ flag: () => true, ...overrides }}>
      {ui}
    </TestProvider>
  );
}

createMockClient

Creates a complete mock Sheepit client with spy functions:

my-component.test.ts
import { createMockClient } from "@sheepit-ai/react/test";
import { vi } from "vitest";

const client = createMockClient(
  {
    flag: (key) => key === "new_feature" ? true : false,
    experiment: () => ({ variant: "control" }),
  },
  vi.fn // Pass your test framework's spy factory
);

// All methods are spies
expect(client.track).toHaveBeenCalledWith("signup", { source: "hero" });

Default mock return values:

  • flag() — returns the defaultValue argument
  • experiment(){ variant: "control" }
  • track() — void (noop)
  • identify() — void (noop)
  • status(){ initialized: true, online: true, ... }
  • flush() — resolves immediately

Testing Feature Flags

dashboard.test.tsx
import { render, screen } from "@testing-library/react";
import { TestProvider } from "@sheepit-ai/react/test";
import { Dashboard } from "./dashboard";

test("shows new nav when flag is on", () => {
  render(
    <TestProvider client={{ flag: (key) => key === "new_nav" }}>
      <Dashboard />
    </TestProvider>
  );

  expect(screen.getByTestId("new-nav")).toBeInTheDocument();
});

test("shows old nav when flag is off", () => {
  render(
    <TestProvider client={{ flag: () => false }}>
      <Dashboard />
    </TestProvider>
  );

  expect(screen.getByTestId("old-nav")).toBeInTheDocument();
});

Testing Experiments

hero-section.test.tsx
test("renders variant B for experiment", () => {
  render(
    <TestProvider client={{
      experiment: () => ({ variant: "variant_b", payload: { color: "blue" } })
    }}>
      <HeroSection />
    </TestProvider>
  );

  expect(screen.getByText("Try our new design")).toBeInTheDocument();
});

Testing Event Tracking

signup-button.test.tsx
import { createMockClient } from "@sheepit-ai/react/test";
import { vi } from "vitest";

test("tracks button click", async () => {
  const client = createMockClient({}, vi.fn);

  render(
    <TestProvider client={client}>
      <SignupButton />
    </TestProvider>
  );

  await userEvent.click(screen.getByRole("button"));

  expect(client.track).toHaveBeenCalledWith("signup_clicked", { source: "hero" });
});

Storybook

Use TestProvider in Storybook decorators:

.storybook/preview.tsx
// .storybook/preview.tsx
import { TestProvider } from "@sheepit-ai/react/test";

const preview = {
  decorators: [
    (Story) => (
      <TestProvider client={{ flag: () => true }}>
        <Story />
      </TestProvider>
    ),
  ],
};

noopClient

For cases where you need a client that silently does nothing (SSR, tests that do not care about Sheepit):

Example
import { TestProvider } from "@sheepit-ai/react/test";

// TestProvider with no client prop uses noopClient internally
<TestProvider>
  <MyComponent />
</TestProvider>

TestProvider with no client prop uses noopClient internally.