Skip to main content
View

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.

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: 'YEARLY', 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
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();
💡 Tip:
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
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?

Having trouble getting your login working? We're here to help!

Thank you for choosing Memberstack 🙏