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.
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:
| Method | Behavior |
|---|---|
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 plansCustom 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
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 */ }));
});