Skip to main content
Testing FlashList components requires special setup because FlashList needs layout measurements to work properly. In test environments like Jest, these measurements aren’t available by default, which would cause FlashList to mount all items at once.

Quick Setup

FlashList provides a Jest setup file that mocks the necessary measurements:
1

Create jest-setup.js

Create a jest-setup.js file in your project root (if you don’t have one already):
jest-setup.js
require("@shopify/flash-list/jestSetup");
2

Configure Jest

Update your jest.config.js to reference the setup file:
jest.config.js
module.exports = {
  preset: 'react-native',
  setupFiles: ['./jest-setup.js'],
  // ... other config
};
3

Run your tests

You’re all set! FlashList components will now work in your tests:
npm test
# or
yarn test

What the Setup Does

The FlashList Jest setup mocks layout measurement functions to return fixed dimensions:
// From @shopify/flash-list/jestSetup.js
jest.mock("@shopify/flash-list/dist/recyclerview/utils/measureLayout", () => {
  const originalModule = jest.requireActual(
    "@shopify/flash-list/dist/recyclerview/utils/measureLayout"
  );
  return {
    ...originalModule,
    measureParentSize: jest.fn().mockImplementation(() => ({
      x: 0,
      y: 0,
      width: 400,
      height: 900,
    })),
    measureFirstChildLayout: jest.fn().mockImplementation(() => ({
      x: 0,
      y: 0,
      width: 400,
      height: 900,
    })),
    measureItemLayout: jest.fn().mockImplementation(() => ({
      x: 0,
      y: 0,
      width: 100,
      height: 100,
    })),
  };
});
This ensures FlashList has the measurements it needs to render a reasonable number of items instead of mounting everything.

Basic Test Example

Here’s a simple test using @testing-library/react-native:
import React from "react";
import { Text, View } from "react-native";
import { render } from "@testing-library/react-native";
import { FlashList } from "@shopify/flash-list";

const MyFlashListComponent = () => {
  const data = [
    { id: "1", title: "First Item" },
    { id: "2", title: "Second Item" },
    { id: "3", title: "Third Item" },
  ];

  return (
    <FlashList
      data={data}
      renderItem={({ item }) => (
        <View>
          <Text>{item.title}</Text>
        </View>
      )}
      keyExtractor={(item) => item.id}
    />
  );
};

describe("MyFlashListComponent", () => {
  it("renders items", () => {
    const { getByText } = render(<MyFlashListComponent />);
    
    const firstItem = getByText("First Item");
    expect(firstItem).toBeTruthy();
  });
});

Testing Common Scenarios

Testing Item Rendering

import { render } from "@testing-library/react-native";
import { FlashList } from "@shopify/flash-list";

interface Product {
  id: string;
  name: string;
  price: number;
}

const ProductList = ({ products }: { products: Product[] }) => (
  <FlashList
    data={products}
    renderItem={({ item }) => (
      <View testID={`product-${item.id}`}>
        <Text>{item.name}</Text>
        <Text>${item.price}</Text>
      </View>
    )}
    keyExtractor={(item) => item.id}
  />
);

describe("ProductList", () => {
  const mockProducts: Product[] = [
    { id: "1", name: "Laptop", price: 999 },
    { id: "2", name: "Mouse", price: 29 },
  ];

  it("renders all products", () => {
    const { getByText } = render(<ProductList products={mockProducts} />);
    
    expect(getByText("Laptop")).toBeTruthy();
    expect(getByText("$999")).toBeTruthy();
    expect(getByText("Mouse")).toBeTruthy();
    expect(getByText("$29")).toBeTruthy();
  });

  it("renders product with testID", () => {
    const { getByTestId } = render(<ProductList products={mockProducts} />);
    
    expect(getByTestId("product-1")).toBeTruthy();
  });
});

Testing Empty States

const ProductList = ({ products }: { products: Product[] }) => (
  <FlashList
    data={products}
    renderItem={({ item }) => <ProductItem item={item} />}
    ListEmptyComponent={
      <View testID="empty-state">
        <Text>No products found</Text>
      </View>
    }
    keyExtractor={(item) => item.id}
  />
);

describe("ProductList", () => {
  it("shows empty state when no products", () => {
    const { getByTestId, getByText } = render(
      <ProductList products={[]} />
    );
    
    expect(getByTestId("empty-state")).toBeTruthy();
    expect(getByText("No products found")).toBeTruthy();
  });
});

Testing User Interactions

import { fireEvent } from "@testing-library/react-native";

const TodoList = () => {
  const [todos, setTodos] = useState([
    { id: "1", text: "Buy groceries", completed: false },
    { id: "2", text: "Walk dog", completed: false },
  ]);

  const toggleTodo = (id: string) => {
    setTodos((current) =>
      current.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  return (
    <FlashList
      data={todos}
      renderItem={({ item }) => (
        <Pressable
          testID={`todo-${item.id}`}
          onPress={() => toggleTodo(item.id)}
        >
          <Text>{item.completed ? "✓" : "○"} {item.text}</Text>
        </Pressable>
      )}
      keyExtractor={(item) => item.id}
    />
  );
};

describe("TodoList", () => {
  it("toggles todo completion on press", () => {
    const { getByTestId, getByText } = render(<TodoList />);
    
    const todo = getByTestId("todo-1");
    expect(getByText("○ Buy groceries")).toBeTruthy();
    
    fireEvent.press(todo);
    
    expect(getByText("✓ Buy groceries")).toBeTruthy();
  });
});

Testing with Custom Mock Dimensions

If you need different mock dimensions for specific tests:
import { jest } from "@jest/globals";

const mockMeasureLayout = (width: number, height: number) => {
  jest.mock("@shopify/flash-list/dist/recyclerview/utils/measureLayout", () => ({
    measureParentSize: jest.fn().mockImplementation(() => ({
      x: 0,
      y: 0,
      width,
      height,
    })),
    measureFirstChildLayout: jest.fn().mockImplementation(() => ({
      x: 0,
      y: 0,
      width,
      height,
    })),
    measureItemLayout: jest.fn().mockImplementation(() => ({
      x: 0,
      y: 0,
      width: 100,
      height: 100,
    })),
  }));
};

describe("Responsive List", () => {
  it("renders correctly on tablet", () => {
    mockMeasureLayout(768, 1024);
    const { getByText } = render(<MyList />);
    // ... assertions
  });
});

Testing Different Layouts

Grid Layout

const GridList = () => (
  <FlashList
    data={mockData}
    numColumns={2}
    renderItem={({ item }) => <GridItem item={item} />}
    keyExtractor={(item) => item.id}
  />
);

describe("GridList", () => {
  it("renders items in grid", () => {
    const { getAllByTestId } = render(<GridList />);
    const items = getAllByTestId(/grid-item-/);
    expect(items.length).toBeGreaterThan(0);
  });
});

Masonry Layout

const MasonryList = () => (
  <FlashList
    data={mockData}
    masonry
    numColumns={3}
    renderItem={({ item }) => <MasonryCard item={item} />}
    keyExtractor={(item) => item.id}
  />
);

describe("MasonryList", () => {
  it("renders masonry layout", () => {
    const { getByTestId } = render(<MasonryList />);
    expect(getByTestId("masonry-container")).toBeTruthy();
  });
});

Testing with TypeScript

Fully typed test example:
import { render, RenderAPI } from "@testing-library/react-native";
import { FlashList } from "@shopify/flash-list";

interface User {
  id: string;
  name: string;
  email: string;
}

const UserList = ({ users }: { users: User[] }) => (
  <FlashList<User>
    data={users}
    renderItem={({ item }) => (
      <View testID={`user-${item.id}`}>
        <Text>{item.name}</Text>
        <Text>{item.email}</Text>
      </View>
    )}
    keyExtractor={(item) => item.id}
  />
);

describe("UserList", () => {
  const mockUsers: User[] = [
    { id: "1", name: "John Doe", email: "[email protected]" },
    { id: "2", name: "Jane Smith", email: "[email protected]" },
  ];

  let component: RenderAPI;

  beforeEach(() => {
    component = render(<UserList users={mockUsers} />);
  });

  it("renders user names", () => {
    expect(component.getByText("John Doe")).toBeTruthy();
    expect(component.getByText("Jane Smith")).toBeTruthy();
  });

  it("renders user emails", () => {
    expect(component.getByText("[email protected]")).toBeTruthy();
    expect(component.getByText("[email protected]")).toBeTruthy();
  });
});

Best Practices

Use testID liberally

Add testID props to make elements easy to query in tests:
<View testID={`item-${item.id}`}>

Test behavior, not implementation

Focus on what the user sees and does, not internal component details:
// Good
expect(getByText("Product added")).toBeTruthy();

// Avoid
expect(component.state.cartItems.length).toBe(1);

Mock external dependencies

Mock API calls, navigation, and other external dependencies:
jest.mock('../api/products', () => ({
  fetchProducts: jest.fn(),
}));

Clean up after tests

Use beforeEach and afterEach to reset state:
afterEach(() => {
  jest.clearAllMocks();
});

Common Issues

This usually means the Jest setup file isn’t loaded. Verify:
  1. jest-setup.js contains require("@shopify/flash-list/jestSetup")
  2. jest.config.js has setupFiles: ['./jest-setup.js']
  3. The path to jest-setup.js is correct
The mock dimensions might be too small. Try increasing them in a custom mock:
mockMeasureLayout(400, 1200); // Larger viewport
Make sure items are actually rendered. Check the mock viewport size or add testID for more reliable queries.
Import types explicitly:
import type { FlashListProps } from "@shopify/flash-list";

Testing Libraries

Recommended testing libraries for FlashList:
npm install --save-dev @testing-library/react-native
The de facto standard for testing React Native components. Great API and excellent documentation.

Complete Test Suite Example

import React from "react";
import { View, Text, Pressable } from "react-native";
import { render, fireEvent, waitFor } from "@testing-library/react-native";
import { FlashList } from "@shopify/flash-list";

interface Task {
  id: string;
  title: string;
  completed: boolean;
}

const TaskList = () => {
  const [tasks, setTasks] = React.useState<Task[]>([
    { id: "1", title: "Task 1", completed: false },
    { id: "2", title: "Task 2", completed: false },
  ]);

  const toggleTask = (id: string) => {
    setTasks((current) =>
      current.map((task) =>
        task.id === id ? { ...task, completed: !task.completed } : task
      )
    );
  };

  return (
    <FlashList
      testID="task-list"
      data={tasks}
      renderItem={({ item }) => (
        <Pressable
          testID={`task-${item.id}`}
          onPress={() => toggleTask(item.id)}
        >
          <View>
            <Text testID={`task-title-${item.id}`}>
              {item.completed ? "✓" : "○"} {item.title}
            </Text>
          </View>
        </Pressable>
      )}
      keyExtractor={(item) => item.id}
    />
  );
};

describe("TaskList", () => {
  it("renders the list", () => {
    const { getByTestId } = render(<TaskList />);
    expect(getByTestId("task-list")).toBeTruthy();
  });

  it("renders all tasks", () => {
    const { getByTestId } = render(<TaskList />);
    expect(getByTestId("task-1")).toBeTruthy();
    expect(getByTestId("task-2")).toBeTruthy();
  });

  it("displays task titles", () => {
    const { getByText } = render(<TaskList />);
    expect(getByText("○ Task 1")).toBeTruthy();
    expect(getByText("○ Task 2")).toBeTruthy();
  });

  it("toggles task completion", async () => {
    const { getByTestId, getByText } = render(<TaskList />);
    
    const task = getByTestId("task-1");
    fireEvent.press(task);
    
    await waitFor(() => {
      expect(getByText("✓ Task 1")).toBeTruthy();
    });
  });

  it("toggles task back to incomplete", async () => {
    const { getByTestId, getByText } = render(<TaskList />);
    
    const task = getByTestId("task-1");
    fireEvent.press(task);
    fireEvent.press(task);
    
    await waitFor(() => {
      expect(getByText("○ Task 1")).toBeTruthy();
    });
  });
});

Testing Library Docs

Official React Native Testing Library documentation

Jest Documentation

Learn more about Jest testing framework

Build docs developers (and LLMs) love