Skip to main content

Testing Best Practices

Learn how to test your Resync integration effectively.

Unit Testing

Mock Resync SDK

Create a mock for unit tests:

// __mocks__/resync-javascript.js
const mockConfig = {};
const mockContent = [];

const Resync = {
init: jest.fn(() => Promise.resolve()),
getConfig: jest.fn((key) => mockConfig[key]),
getContent: jest.fn(() => mockContent),
getVariant: jest.fn(() => Promise.resolve(null)),
logEvent: jest.fn(),
loginUser: jest.fn(() => Promise.resolve()),
setUserAttributes: jest.fn(() => Promise.resolve()),
};

export default Resync;

Test Component with Resync

import { render } from '@testing-library/react';
import Resync from 'resync-javascript';
import MyComponent from './MyComponent';

jest.mock('resync-javascript');

describe('MyComponent', () => {
it('renders with feature enabled', () => {
// Mock config
Resync.getConfig.mockReturnValue(true);

const { getByText } = render(<MyComponent />);
expect(getByText('New Feature')).toBeInTheDocument();
});

it('renders without feature', () => {
// Mock config
Resync.getConfig.mockReturnValue(false);

const { getByText } = render(<MyComponent />);
expect(getByText('Old Feature')).toBeInTheDocument();
});
});

Integration Testing

Test with Real SDK

import Resync from 'resync-javascript';

describe('Resync Integration', () => {
beforeAll(async () => {
await Resync.init({
key: process.env.RESYNC_TEST_API_KEY,
appId: 7,
storage: localStorage,
environment: 'sandbox',
});
});

it('fetches config successfully', () => {
const config = Resync.getConfig('TEST_KEY');
expect(config).toBeDefined();
});

it('logs events successfully', async () => {
await expect(
Resync.logEvent({ eventId: 'test_event' })
).resolves.not.toThrow();
});
});

E2E Testing

React Native with Detox

describe('Onboarding Flow', () => {
beforeAll(async () => {
await device.launchApp();
});

it('completes onboarding', async () => {
// Welcome screen
await expect(element(by.text('Welcome'))).toBeVisible();
await element(by.text('Get Started')).tap();

// Features screen
await expect(element(by.text('Features'))).toBeVisible();
await element(by.text('Continue')).tap();

// Account setup
await element(by.id('name-input')).typeText('Test User');
await element(by.id('email-input')).typeText('test@example.com');
await element(by.text('Create Account')).tap();

// Verify completion
await expect(element(by.text('Home'))).toBeVisible();
});
});

Testing Campaigns

Test Variant Assignment

import Resync from 'resync-javascript';

describe('Campaign Variant', () => {
it('assigns variant correctly', async () => {
// Set up user
await Resync.loginUser('test_user_123');

// Get variant
const variant = await Resync.getVariant('test_campaign');

// Verify variant is assigned
expect(variant).toBeDefined();
expect([101, 102]).toContain(variant);
});

it('maintains consistent variant for same user', async () => {
const userId = 'test_user_456';
await Resync.loginUser(userId);

const variant1 = await Resync.getVariant('test_campaign');
const variant2 = await Resync.getVariant('test_campaign');

// Same user should get same variant
expect(variant1).toBe(variant2);
});
});

Testing Forms

Test Form Submission

import { render, fireEvent, waitFor } from '@testing-library/react-native';
import { ResyncContentView } from 'resync-react-native';

describe('Contact Form', () => {
it('submits form successfully', async () => {
const mockSubmit = jest.fn();

const functionRegistry = {
handleFormSubmit: mockSubmit,
};

const { getByPlaceholderText, getByText } = render(
<ResyncContentView
name="ContactForm"
functionRegistry={functionRegistry}
/>
);

// Fill form
fireEvent.changeText(
getByPlaceholderText('Name'),
'Test User'
);
fireEvent.changeText(
getByPlaceholderText('Email'),
'test@example.com'
);

// Submit
fireEvent.press(getByText('Submit'));

// Verify submission
await waitFor(() => {
expect(mockSubmit).toHaveBeenCalledWith({
name: 'Test User',
email: 'test@example.com',
});
});
});
});

Snapshot Testing

Test Content Rendering

import { render } from '@testing-library/react-native';
import { ResyncContentView } from 'resync-react-native';
import Resync from 'resync-react-native';

jest.mock('resync-react-native');

describe('Content Snapshot', () => {
it('matches snapshot', () => {
// Mock content
Resync.getContent.mockReturnValue([
{
name: 'WelcomeCard',
items: [
{ type: 'text', content: 'Welcome!' },
],
},
]);

const { toJSON } = render(
<ResyncContentView name="WelcomeCard" />
);

expect(toJSON()).toMatchSnapshot();
});
});

Test Environment Setup

Separate Test Account

Create a dedicated Resync app for testing:

  1. Create new app in dashboard
  2. Name it "MyApp (Test)"
  3. Use separate API key
  4. Configure test campaigns and content

Environment Variables

# .env.test
RESYNC_API_KEY=rsk_sandbox_test123
RESYNC_APP_ID=999

Continuous Integration

GitHub Actions Example

name: Tests

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: '18'

- name: Install dependencies
run: npm install

- name: Run tests
env:
RESYNC_API_KEY: ${{ secrets.RESYNC_TEST_API_KEY }}
RESYNC_APP_ID: ${{ secrets.RESYNC_TEST_APP_ID }}
run: npm test

Best Practices

1. Use Sandbox Environment

Resync.init({
// ...
environment: 'sandbox', // For testing
});

2. Clean Up After Tests

afterEach(() => {
jest.clearAllMocks();
});

afterAll(() => {
// Clean up test data
deleteTestData();
});

3. Test Error Cases

it('handles network errors gracefully', async () => {
// Mock network failure
Resync.init.mockRejectedValue(new Error('Network error'));

// Should handle error
await expect(initializeApp()).rejects.toThrow();
});

4. Test Loading States

it('shows loading state', () => {
const { getByTestId } = render(<MyComponent />);
expect(getByTestId('loading')).toBeVisible();
});

Next Steps