CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-jest-expo

A Jest preset to painlessly test your Expo / React Native apps.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

rsc.mddocs/

React Server Components (RSC)

Jest Expo provides comprehensive testing support for React Server Components, including specialized presets, utilities for rendering RSC to flight data, and custom Jest matchers for validating RSC output.

Capabilities

RSC Presets

Specialized Jest preset configurations for testing React Server Components across different platforms.

RSC Universal Preset

// In package.json or jest.config.js
{
  "jest": {
    "preset": "jest-expo/rsc"
  }
}

Features:

  • Multi-platform RSC testing for iOS, Android, and web
  • React Server Component testing mode enabled
  • Prettier snapshot formatting for RSC flight data
  • Specialized setup for Node.js web APIs (Blob, File, ReadableStream)

Platform-Specific RSC Presets

// Available RSC platform presets
"jest-expo/rsc/ios"      // RSC iOS testing preset
"jest-expo/rsc/android"  // RSC Android testing preset  
"jest-expo/rsc/web"      // RSC web testing preset

RSC iOS Preset:

  • React Native test environment with RSC enabled
  • iOS-specific snapshot resolver (.rsc.ios.snap files)
  • Platform set to ios with React Server Component mode
  • Uses getIOSPreset({ isReactServer: true })

RSC Android Preset:

  • React Native test environment with RSC enabled
  • Android-specific snapshot resolver (.rsc.android.snap files)
  • Platform set to android with React Server Component mode
  • Uses getAndroidPreset({ isReactServer: true })

RSC Web Preset:

  • jsdom test environment with RSC enabled
  • Web-specific snapshot resolver (.rsc.web.snap files)
  • Platform set to web with React Server Component mode
  • Uses getWebPreset({ isReactServer: true })

Common RSC Features:

  • All presets run in Node.js test environment for RSC compatibility
  • Test path filters to only run __rsc_tests__ directories
  • RSC-specific Babel transforms and bundler configurations
  • Custom expect matchers for RSC flight data validation

RSC Utilities

Core utilities for rendering React Server Components to flight data format for testing.

Stream to String

/**
 * Convert ReadableStream to string for testing
 * @param stream - ReadableStream to convert
 * @returns Promise that resolves to string content
 */
function streamToString(stream: ReadableStream): Promise<string>;

Usage Example:

import { streamToString } from "jest-expo/src/rsc-utils";

test("stream conversion", async () => {
  const stream = new ReadableStream({
    start(controller) {
      controller.enqueue("Hello");
      controller.enqueue(" World");
      controller.close();
    }
  });
  
  const result = await streamToString(stream);
  expect(result).toBe("Hello World");
});

Render JSX to Flight String

/**
 * Render JSX to RSC payload string
 * @param jsx - React element to render
 * @param throwOnError - Whether to throw errors during rendering
 * @returns Promise that resolves to RSC flight string
 */
function renderJsxToFlightStringAsync(
  jsx: React.ReactNode, 
  throwOnError?: boolean
): Promise<string>;

Usage Example:

import { renderJsxToFlightStringAsync } from "jest-expo/src/rsc-utils";

test("RSC rendering", async () => {
  const element = <div>Hello RSC</div>;
  const flightString = await renderJsxToFlightStringAsync(element);
  
  expect(flightString).toContain('"type":"div"');
  expect(flightString).toContain('Hello RSC');
});

Render JSX to ReadableStream

/**
 * Render JSX to RSC ReadableStream
 * @param jsx - React element to render
 * @param options - Rendering options
 * @returns Object containing ReadableStream and client boundaries
 */
function renderJsxToReadableStream(
  jsx: React.ReactNode, 
  options?: RSCRenderOptions
): RSCRenderResult;

interface RSCRenderOptions {
  onError?: (error: Error) => void;
}

interface RSCRenderResult {
  stream: ReadableStream;
  clientBoundaries: string[];
}

Usage Example:

import { renderJsxToReadableStream, streamToString } from "jest-expo/src/rsc-utils";

test("RSC stream rendering", async () => {
  const element = <div>Streaming RSC</div>;
  const { stream, clientBoundaries } = renderJsxToReadableStream(element);
  const result = await streamToString(stream);
  
  expect(result).toContain("Streaming RSC");
  expect(clientBoundaries).toEqual([]);
});

RSC Jest Matchers

Custom Jest matchers specifically designed for testing React Server Components flight data.

toMatchFlight

/**
 * Compare RSC flight data to expected string
 * @param expectedFlight - Expected RSC flight string
 */
expect(data: React.ReactNode | ReadableStream).toMatchFlight(expectedFlight: string);

Features:

  • Accepts JSX elements, flight strings, or ReadableStreams
  • Automatically renders JSX to flight format for comparison
  • Provides detailed diff output for flight data mismatches
  • Handles async stream processing

Usage Example:

describe("RSC flight matching", () => {
  test("JSX to flight comparison", () => {
    const element = <div className="test">Content</div>;
    const expectedFlight = '{"type":"div","props":{"className":"test"},"children":["Content"]}';
    
    expect(element).toMatchFlight(expectedFlight);
  });

  test("stream to flight comparison", async () => {
    const element = <span>Stream test</span>;
    const stream = renderJsxToReadableStream(element);
    const expectedFlight = '{"type":"span","props":{},"children":["Stream test"]}';
    
    expect(stream).toMatchFlight(expectedFlight);
  });
});

toMatchFlightSnapshot

/**
 * Compare RSC flight data to snapshot file
 */
expect(data: React.ReactNode | ReadableStream).toMatchFlightSnapshot();

Features:

  • Creates RSC-specific snapshot files with platform extensions
  • Automatically handles JSX rendering to flight format
  • Supports RSC snapshot updates with --updateSnapshot
  • Platform-specific snapshot naming (.rsc.ios.snap, etc.)

Usage Example:

describe("RSC snapshot testing", () => {
  test("component flight snapshot", () => {
    const element = (
      <div>
        <h1>Title</h1>
        <p>Description</p>
      </div>
    );
    
    expect(element).toMatchFlightSnapshot();
  });

  test("async component snapshot", async () => {
    const AsyncComponent = async () => {
      const data = await fetchData();
      return <div>{data.title}</div>;
    };
    
    const element = <AsyncComponent />;
    expect(element).toMatchFlightSnapshot();
  });
});

RSC Setup and Configuration

Environment Setup

RSC presets automatically configure the test environment with necessary globals:

// Automatically configured in RSC presets
global.__DEV__ = true;
global.Blob = Blob;
global.File = File;
global.ReadableStream = ReadableStream;
global.WritableStream = WritableStream;
global.TransformStream = TransformStream;
global.TextDecoder = TextDecoder;
global.TextEncoder = TextEncoder;

Custom RSC Test Setup

// Custom RSC test setup
import { expect } from "@jest/globals";

// Extend Jest matchers with RSC matchers
declare global {
  namespace jest {
    interface Matchers<R> {
      toMatchFlight(expectedFlight: string): R;
      toMatchFlightSnapshot(): R;
    }
  }
}

Advanced RSC Testing Patterns

Server Component Testing

describe("Server Components", () => {
  test("async server component", async () => {
    const ServerComponent = async ({ userId }) => {
      const user = await fetchUser(userId);
      return <div>Hello {user.name}</div>;
    };
    
    const element = <ServerComponent userId="123" />;
    expect(element).toMatchFlightSnapshot();
  });
});

Client Component Boundary Testing

describe("Client/Server boundaries", () => {
  test("server component with client children", () => {
    const ServerWrapper = ({ children }) => (
      <div className="server-wrapper">{children}</div>
    );
    
    const ClientComponent = () => <button>Click me</button>;
    
    const element = (
      <ServerWrapper>
        <ClientComponent />
      </ServerWrapper>
    );
    
    expect(element).toMatchFlightSnapshot();
  });
});

Types

// RSC utility types
interface RSCRenderOptions {
  onError?: (error: Error) => void;
  identifierPrefix?: string;
}

// Jest matcher interfaces
interface JestExpoMatchers<R> extends Record<string, any> {
  /**
   * Compare RSC flight data to expected string
   */
  toMatchFlight(expectedFlight: string): R;
  
  /**
   * Compare RSC flight data to snapshot file
   */
  toMatchFlightSnapshot(): R;
}

// RSC utility function types
declare function streamToString(stream: ReadableStream): Promise<string>;

declare function renderJsxToFlightStringAsync(
  jsx: React.ReactNode, 
  throwOnError?: boolean
): Promise<string>;

declare function renderJsxToReadableStream(
  jsx: React.ReactNode, 
  options?: RSCRenderOptions
): RSCRenderResult;

// RSC utility interfaces
interface RSCRenderOptions {
  onError?: (error: Error) => void;
}

interface RSCRenderResult {
  stream: ReadableStream;
  clientBoundaries: string[];
}

// Global extensions for RSC testing
declare global {
  namespace jest {
    interface Matchers<R> extends JestExpoMatchers<R> {}
    interface Expect extends JestExpoMatchers<any> {}
    interface InverseAsymmetricMatchers extends Expect {}
  }
}

// React Server Component types
type ServerComponent<P = {}> = (props: P) => Promise<React.ReactElement>;
type ClientComponent<P = {}> = React.ComponentType<P>;

interface RSCFlightData {
  type: string;
  props: Record<string, any>;
  children?: React.ReactNode[];
}

docs

configuration.md

index.md

presets.md

rsc.md

testing-utilities.md

tile.json