Skip to main content
Memberstack Docs
Dashboard

Testing Utilities

The @memberstack/dom/testing subpath provides mock factories, a mock SDK instance, and custom test matchers for unit testing your Memberstack integration. No API calls needed.

/dom-package/testing.md
Works with Jest & Vitest

All testing utilities work with both Jest and Vitest. The custom matchers extend the expect API in both frameworks.

Import

Testing utilities are available from the @memberstack/dom/testing subpath. No additional packages to install.

import {
  createMockMemberstack,
  mockMember,
  mockPlan,
  mockPlanConnection,
  mockCard,
  mockPrice,
  mockApp,
  mockContentGroup,
  memberstackMatchers
} from '@memberstack/dom/testing';

Mock Factories

Mock factories create realistic test data with sensible defaults. Pass an overrides object to customize any fields.

mockMember(overrides?)

Creates a mock Member object with all fields populated.

import { mockMember } from '@memberstack/dom/testing';

// Default member
const member = mockMember();
// {
//   id: "mem_abc123xyz",
//   verified: true,
//   profileImage: "",
//   auth: { email: "test@example.com", hasPassword: true, providers: [] },
//   loginRedirect: "/",
//   stripeCustomerId: "",
//   createdAt: "2025-01-01T00:00:00.000Z",  // dynamic: new Date().toISOString()
//   metaData: {},
//   customFields: {},
//   permissions: [],
//   planConnections: []
// }

// With overrides
const verifiedMember = mockMember({
  verified: true,
  auth: { email: 'pro@example.com', hasPassword: true, providers: [] },
  customFields: { 'first-name': 'Jane' }
});

mockPlan(overrides?)

Creates a mock Plan object.

import { mockPlan } from '@memberstack/dom/testing';

const plan = mockPlan();
// { id: "pln_abc123", name: "Test Plan", description: "A test plan", status: "PUBLISHED",
//   redirects: { afterLogin: "/", afterLogout: "/", afterSignup: "/" }, prices: [] }

const proPlan = mockPlan({
  name: 'Pro',
  prices: [mockPrice({ amount: '29', name: 'Monthly' })]
});

mockPlanConnection(overrides?)

Creates a mock PlanConnection representing a member's subscription to a plan.

import { mockPlanConnection } from '@memberstack/dom/testing';

const connection = mockPlanConnection();
// {
//   id: "conn_abc123",
//   active: true,
//   status: "ACTIVE",
//   planId: "pln_abc123",
//   type: "FREE",
//   payment: null
// }

// Member with an active plan
const memberWithPlan = mockMember({
  planConnections: [
    mockPlanConnection({ planId: 'pln_pro-plan' })
  ]
});

Other Factories

import { mockPrice, mockCard, mockApp, mockContentGroup } from '@memberstack/dom/testing';

// Mock a price tier
const price = mockPrice({ amount: '49', name: 'Annual', interval: { type: 'year', count: 1 } });

// Mock a saved card
const card = mockCard({ brand: 'visa', last4: '4242' });

// Mock app configuration
const app = mockApp({ name: 'My App', mode: 'sandbox' });

// Mock a content group (gated content)
const group = mockContentGroup({ name: 'Premium Content', key: 'premium' });

createMockMemberstack(options?)

Creates a complete mock Memberstack SDK instance that behaves like the real thing but runs entirely in memory. All methods return promises and update internal state correctly.

import { createMockMemberstack, mockMember, mockPlan } from '@memberstack/dom/testing';

const mockMs = createMockMemberstack({
  // Pre-set a logged-in member
  member: mockMember({
    auth: { email: 'test@example.com', hasPassword: true, providers: [] }
  }),
  // Available plans
  plans: [
    mockPlan({ id: 'pln_free', name: 'Free' }),
    mockPlan({ id: 'pln_pro', name: 'Pro' })
  ]
});

// Use it like the real SDK
const { data } = await mockMs.getCurrentMember();
console.log(data.auth.email); // "test@example.com"

// Login/logout update internal state
await mockMs.logout();
const { data: afterLogout } = await mockMs.getCurrentMember();
console.log(afterLogout); // null

await mockMs.loginMemberEmailPassword({
  email: 'test@example.com',
  password: 'any-password'
});
const { data: afterLogin } = await mockMs.getCurrentMember();
console.log(afterLogin.auth.email); // "test@example.com"

Available Mock Methods

The mock instance supports these methods:

MethodBehavior
getCurrentMember()Returns the current mock member or null
loginMemberEmailPassword()Sets the mock member as logged in
signupMemberEmailPassword()Creates and sets a mock member
logout()Clears the current member
updateMember()Updates custom fields on the mock member
getPlans()Returns the configured mock plans
getPlan()Returns a specific plan by ID
getApp()Returns the mock app configuration
getRestrictedUrlGroups()Returns mock content groups
getMemberCards()Returns the configured mock cards
onAuthChange(callback)Subscribes to auth state changes

Test Helpers

The mock instance also includes test-only helpers for manipulating state directly:

// Directly set the current member (without triggering login flow)
mockMs._setMember(mockMember({ verified: true }));

// Inspect the internal mock state
const state = mockMs._getMockState();
console.log(state.member);  // Current member
console.log(state.plans);   // Available plans

Custom Test Matchers

Extend Jest or Vitest with Memberstack-specific assertions for cleaner, more readable tests.

import { memberstackMatchers, mockMember, mockPlanConnection } from '@memberstack/dom/testing';

// Register matchers (do this once, e.g., in a setup file)
expect.extend(memberstackMatchers);

// toBeLoggedIn() - asserts member is not null
const member = mockMember();
expect(member).toBeLoggedIn();
expect(null).not.toBeLoggedIn();

// toHavePlan(planId) - asserts member has a specific plan
const memberWithPlan = mockMember({
  planConnections: [mockPlanConnection({ planId: 'pln_pro' })]
});
expect(memberWithPlan).toHavePlan('pln_pro');
expect(memberWithPlan).not.toHavePlan('pln_enterprise');

// toBeVerified() - asserts member's email is verified
const verifiedMember = mockMember({ verified: true });
expect(verifiedMember).toBeVerified();

Register the matchers once in your test setup file (e.g., vitest.setup.ts or jest.setup.js) so they're available in all tests.

Full Test Example

Here's a complete example testing a component that uses Memberstack for authentication and plan checking.

auth.test.ts
// auth.test.ts
import { describe, it, expect, beforeEach } from 'vitest';
import {
  createMockMemberstack,
  mockMember,
  mockPlan,
  mockPlanConnection,
  memberstackMatchers
} from '@memberstack/dom/testing';

expect.extend(memberstackMatchers);

describe('Authentication Flow', () => {
  let mockMs;

  beforeEach(() => {
    mockMs = createMockMemberstack({
      plans: [
        mockPlan({ id: 'pln_free', name: 'Free' }),
        mockPlan({ id: 'pln_pro', name: 'Pro' })
      ]
    });
  });

  it('should start logged out', async () => {
    const { data } = await mockMs.getCurrentMember();
    expect(data).not.toBeLoggedIn();
  });

  it('should login and return member', async () => {
    mockMs._setMember(mockMember({
      auth: { email: 'user@test.com', hasPassword: true, providers: [] }
    }));

    const { data } = await mockMs.getCurrentMember();
    expect(data).toBeLoggedIn();
    expect(data.auth.email).toBe('user@test.com');
  });

  it('should check plan access', async () => {
    const member = mockMember({
      planConnections: [
        mockPlanConnection({ planId: 'pln_pro', status: 'ACTIVE' })
      ]
    });
    mockMs._setMember(member);

    const { data } = await mockMs.getCurrentMember();
    expect(data).toHavePlan('pln_pro');
    expect(data).not.toHavePlan('pln_enterprise');
  });

  it('should logout and clear member', async () => {
    mockMs._setMember(mockMember());

    await mockMs.logout();

    const { data } = await mockMs.getCurrentMember();
    expect(data).not.toBeLoggedIn();
  });

  it('should list available plans', async () => {
    const { data } = await mockMs.getPlans();
    expect(data).toHaveLength(2);
    expect(data[0].name).toBe('Free');
    expect(data[1].name).toBe('Pro');
  });
});

Using with Dependency Injection

For the mock to work with your app code, pass the Memberstack instance as a dependency rather than importing it directly. Here's a pattern that works with most frameworks.

// memberstack.ts - your app's Memberstack wrapper
let instance = null;

export function setMemberstack(ms) {
  instance = ms;
}

export function getMemberstack() {
  return instance;
}

// main.ts - production code
import memberstack from '@memberstack/dom';
import { setMemberstack } from './memberstack';

const ms = await memberstack.init({ publicKey: 'pk_...' });
setMemberstack(ms);

// test.ts - test code
import { createMockMemberstack } from '@memberstack/dom/testing';
import { setMemberstack } from './memberstack';

beforeEach(() => {
  setMemberstack(createMockMemberstack({ /* options */ }));
});
Need help?
Can't find what you're looking for? Our team is here to help.