Back to Repositories

Testing React DevTools Profiler Snapshot Navigation in facebook/react

This test suite validates the React DevTools Profiler functionality, focusing on recording and navigating through render snapshots. It ensures proper profiling behavior for React applications version 16.5 and above.

Test Coverage Overview

The test suite provides comprehensive coverage of the React DevTools Profiler component’s core functionality.

  • Validates profiler recording activation and deactivation
  • Tests snapshot navigation through UI controls
  • Verifies correct snapshot count and selection state
  • Covers circular navigation through snapshots

Implementation Analysis

The testing approach utilizes Playwright for end-to-end testing, implementing a systematic verification of the Profiler’s UI interactions and state management.

The test leverages custom utility functions for DevTools and list operations, employing async/await patterns for handling UI interactions and state changes. Test assertions focus on snapshot selector state validation.

Technical Details

  • Testing Framework: Playwright with Jest
  • Custom Utilities: devToolsUtils, listAppUtils
  • React Version Requirement: >=16.5
  • Setup: Browser page initialization, iframe handling
  • DOM Selectors: Custom test name selectors for component identification

Best Practices Demonstrated

The test implementation showcases several testing best practices for complex UI interactions.

  • Modular test utility functions for reusability
  • Proper test isolation and setup/teardown
  • Version-specific test conditions
  • Explicit wait conditions for async operations
  • Clear test case organization and readability

facebook/react

packages/react-devtools-inline/__tests__/__e2e__/profiler.test.js

            
/** @flow */

'use strict';

const {runOnlyForReactRange} = require('./utils');
const listAppUtils = require('./list-app-utils');
const devToolsUtils = require('./devtools-utils');
const {test, expect} = require('@playwright/test');
const config = require('../../playwright.config');
test.use(config);
test.describe('Profiler', () => {
  let page;

  test.beforeEach(async ({browser}) => {
    page = await browser.newPage();
    await page.goto(config.use.url, {
      waitUntil: 'domcontentloaded',
    });

    await page.waitForSelector('#iframe');

    await devToolsUtils.clickButton(page, 'TabBarButton-profiler');
  });

  test('should record renders and commits when active', async () => {
    // Profiling is only available in 16.5 and over
    runOnlyForReactRange('>=16.5');
    async function getSnapshotSelectorText() {
      return await page.evaluate(() => {
        const {createTestNameSelector, findAllNodes} =
          window.REACT_DOM_DEVTOOLS;
        const container = document.getElementById('devtools');

        const input = findAllNodes(container, [
          createTestNameSelector('SnapshotSelector-Input'),
        ])[0];
        const label = findAllNodes(container, [
          createTestNameSelector('SnapshotSelector-Label'),
        ])[0];
        return `${input.value}${label.innerText}`;
      });
    }

    async function clickButtonAndVerifySnapshotSelectorText(
      buttonTagName,
      expectedText
    ) {
      await devToolsUtils.clickButton(page, buttonTagName);
      const text = await getSnapshotSelectorText();
      expect(text).toBe(expectedText);
    }

    await devToolsUtils.clickButton(page, 'ProfilerToggleButton');

    await listAppUtils.addItem(page, 'four');
    await listAppUtils.addItem(page, 'five');
    await listAppUtils.addItem(page, 'six');

    await devToolsUtils.clickButton(page, 'ProfilerToggleButton');

    await page.waitForFunction(() => {
      const {createTestNameSelector, findAllNodes} = window.REACT_DOM_DEVTOOLS;
      const container = document.getElementById('devtools');

      const input = findAllNodes(container, [
        createTestNameSelector('SnapshotSelector-Input'),
      ]);

      return input.length === 1;
    });

    const text = await getSnapshotSelectorText();
    expect(text).toBe('1 / 3');

    await clickButtonAndVerifySnapshotSelectorText(
      'SnapshotSelector-NextButton',
      '2 / 3'
    );
    await clickButtonAndVerifySnapshotSelectorText(
      'SnapshotSelector-NextButton',
      '3 / 3'
    );
    await clickButtonAndVerifySnapshotSelectorText(
      'SnapshotSelector-NextButton',
      '1 / 3'
    );
    await clickButtonAndVerifySnapshotSelectorText(
      'SnapshotSelector-PreviousButton',
      '3 / 3'
    );
    await clickButtonAndVerifySnapshotSelectorText(
      'SnapshotSelector-PreviousButton',
      '2 / 3'
    );
    await clickButtonAndVerifySnapshotSelectorText(
      'SnapshotSelector-PreviousButton',
      '1 / 3'
    );
    await clickButtonAndVerifySnapshotSelectorText(
      'SnapshotSelector-PreviousButton',
      '3 / 3'
    );
  });
});