Skip to main content
This guide walks you through setting up Jest testing for a Next.js application that uses the Dynamic Labs SDK. You’ll learn how to properly mock Dynamic components and hooks to write effective unit tests.

Prerequisites

  • Node.js installed on your machine
  • Basic familiarity with Next.js and React Testing Library
  • A Dynamic Labs account with an environment ID

Step 1: Create a New Next.js Project

First, create a new Next.js application using the latest version:
npx create-next-app@latest my-test-app
Follow the prompts to set up your project with TypeScript and other preferred options.

Step 2: Install Dynamic Labs SDK

Install the required Dynamic Labs packages:
npm install @dynamic-labs/sdk-react-core @dynamic-labs/ethereum

Step 3: Add Dynamic to Your Application

Configure the Layout

Open src/app/layout.tsx and add the DynamicContextProvider. Replace <YOUR_ENVIRONMENT_ID> with your actual environment ID from the Dynamic dashboard:
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { DynamicContextProvider } from "@dynamic-labs/sdk-react-core";
import { EthereumWalletConnectors } from "@dynamic-labs/ethereum";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        <DynamicContextProvider
          theme="auto"
          settings={{
            environmentId: "<YOUR_ENVIRONMENT_ID>",
            walletConnectors: [EthereumWalletConnectors],
          }}
        >
          {children}
        </DynamicContextProvider>
      </body>
    </html>
  );
}

Add the DynamicWidget

Open src/app/page.tsx and add the DynamicWidget component:
import { DynamicWidget } from "@dynamic-labs/sdk-react-core";

export default function Home() {
  return (
    <div className="font-sans grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
      <h1>Hello World</h1>
      <DynamicWidget />
    </div>
  );
}

Step 4: Configure Jest for Testing

Install Testing Dependencies

Install Jest and React Testing Library along with necessary type definitions:
npm install -D jest jest-environment-jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom ts-node @types/jest

Initialize Jest Configuration

Create a basic Jest configuration file:
npm init jest@latest

Configure Jest for Next.js

Create a jest.config.ts file in your project root with the following configuration:
import type { Config } from "jest";
import nextJest from "next/jest.js";

const createJestConfig = nextJest({
  dir: "./",
});

const config: Config = {
  coverageProvider: "v8",
  testEnvironment: "jsdom",
};

export default createJestConfig(config);

Set Up Jest Custom Matchers

Create a jest.setup.ts file in your project root to configure testing utilities:
import "@testing-library/jest-dom";

Update Jest Configuration

Update your jest.config.ts to include the setup file:
import type { Config } from "jest";
import nextJest from "next/jest.js";

const createJestConfig = nextJest({
  dir: "./",
});

const config: Config = {
  coverageProvider: "v8",
  testEnvironment: "jsdom",
  setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
};

export default createJestConfig(config);

Step 5: Write Tests for Dynamic Components

Test the Layout Component

Create a __tests__/layout.test.jsx file to test your layout:
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import Layout from "../src/app/layout";

// Mock the Dynamic SDK components to isolate layout logic in tests
jest.mock("@dynamic-labs/sdk-react-core", () => ({
  DynamicContextProvider: ({ children }) => (
    <div data-testid="dynamic-context">{children}</div>
  ),
}));

// Mock the Ethereum wallet connectors
jest.mock("@dynamic-labs/ethereum", () => ({
  EthereumWalletConnectors: [],
}));

// Mock Next.js font imports to avoid font loading issues in tests
jest.mock("next/font/google", () => ({
  Geist: () => ({ variable: "--font-geist-sans" }),
  Geist_Mono: () => ({ variable: "--font-geist-mono" }),
}));

describe("Layout", () => {
  it("renders Layout with children", () => {
    render(<Layout>Hello World</Layout>);

    const heading = screen.getByText("Hello World");
    const dynamicContext = screen.getByTestId("dynamic-context");

    expect(heading).toBeInTheDocument();
    expect(dynamicContext).toBeInTheDocument();
  });
});

Test the Page Component

Create a __tests__/page.test.jsx file to test your page:
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import Page from "../src/app/page";

// Mock the Dynamic SDK components
jest.mock("@dynamic-labs/sdk-react-core", () => ({
  DynamicWidget: () => <div>DynamicWidget</div>,
}));

describe("Page", () => {
  it("renders a heading", () => {
    render(<Page />);

    const heading = screen.getByText("Hello World");

    expect(heading).toBeInTheDocument();
  });
});

Step 6: Test Components Using Dynamic Hooks

Update Your Page to Use Hooks

Modify src/app/page.tsx to use Dynamic hooks for displaying user information:
"use client";

import {
  DynamicWidget,
  useDynamicContext,
  useIsLoggedIn,
  useUserWallets,
} from "@dynamic-labs/sdk-react-core";

export default function Home() {
  const { sdkHasLoaded } = useDynamicContext();
  const isLoggedIn = useIsLoggedIn();
  const userWallets = useUserWallets();

  return (
    <div className="font-sans grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
      <h1>Hello World</h1>
      <p>SDK has loaded: {sdkHasLoaded ? "Yes" : "No"}</p>
      <p>Is logged in: {isLoggedIn ? "Yes" : "No"}</p>
      <p>
        User wallets:{" "}
        {userWallets.length > 0 ? (
          userWallets.map((wallet) => (
            <span key={wallet.address}>{wallet.address}</span>
          ))
        ) : (
          <span>No wallets</span>
        )}
      </p>
      <DynamicWidget />
    </div>
  );
}

Test with Mocked Hooks

Update __tests__/page.test.jsx to properly mock and test Dynamic hooks:
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import Page from "../src/app/page";
import {
  useDynamicContext,
  useIsLoggedIn,
  useUserWallets,
} from "@dynamic-labs/sdk-react-core";

// Mock the Dynamic SDK components and hooks
jest.mock("@dynamic-labs/sdk-react-core", () => ({
  DynamicWidget: () => <div>DynamicWidget</div>,
  useDynamicContext: jest.fn(),
  useIsLoggedIn: jest.fn(),
  useUserWallets: jest.fn(),
}));

describe("Page", () => {
  beforeEach(() => {
    useDynamicContext.mockReturnValue({ sdkHasLoaded: true });
    useIsLoggedIn.mockReturnValue({ isLoggedIn: false });
    useUserWallets.mockReturnValue([]);
  });

  it("render render No wallets", () => {
    render(<Page />);

    expect(screen.getByText("No wallets")).toBeInTheDocument();
  });

  describe("when the has user logged in with wallets", () => {
    beforeEach(() => {
      useDynamicContext.mockReturnValue({ sdkHasLoaded: true });
      useIsLoggedIn.mockReturnValue({ isLoggedIn: true });
      useUserWallets.mockReturnValue([{ address: "0x123" }]);
    });

    it("render the list of wallets", () => {
      render(<Page />);

      const wallets = screen.getByText("0x123");

      expect(wallets).toBeInTheDocument();
    });
  });
});

Understanding the Mocking Strategy

When testing components that use the Dynamic Labs SDK, the key approach is to mock the SDK modules and hooks:

Mock the Entire Module

Mock @dynamic-labs/sdk-react-core to replace all components and hooks with Jest mock functions:
jest.mock("@dynamic-labs/sdk-react-core", () => ({
  DynamicWidget: () => <div>DynamicWidget</div>,
  DynamicContextProvider: ({ children }) => children,
  useDynamicContext: jest.fn(),
  useIsLoggedIn: jest.fn(),
  useUserWallets: jest.fn(),
}));

Mock Individual Hooks

Each hook can return different values for different test scenarios:
beforeEach(() => {
  useDynamicContext.mockReturnValue({ sdkHasLoaded: true });
  useIsLoggedIn.mockReturnValue({ isLoggedIn: false });
  useUserWallets.mockReturnValue([]);
});

Running Your Tests

Add a test script to your package.json:
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch"
  }
}
Run your tests:
npm test

Summary

You’ve successfully set up Jest testing for your Next.js application with Dynamic Labs SDK. The key takeaways are:
  • Mock the entire @dynamic-labs/sdk-react-core module to replace components and hooks
  • Use jest.fn() to create mock implementations that can return different values for different test scenarios
  • Configure Jest custom matchers from @testing-library/jest-dom for better test assertions
This testing approach allows you to thoroughly test your application’s behavior without needing to connect to actual wallets or authenticate real users during your test runs.
I