Skip to content

fix(ci): raise Node.js heap limit for RIT type-check & test step#35973

Open
Copilot wants to merge 3 commits intocopilot/enforce-consistent-type-importsfrom
copilot/add-rit-config-for-react-charts
Open

fix(ci): raise Node.js heap limit for RIT type-check & test step#35973
Copilot wants to merge 3 commits intocopilot/enforce-consistent-type-importsfrom
copilot/add-rit-config-for-react-charts

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 10, 2026

The react-major-versions-integration CI job OOMs when Jest runs the react-charts suite via RIT — the D3 + VegaDeclarativeChart render load exhausts the default ~2 GB V8 heap on a single worker.

Changes

  • .github/workflows/pr.yml: Added NODE_OPTIONS: --max-old-space-size=4096 as an env variable on the "React Versions Integration Tests (17,18) - Type-check & Test" step. This is inherited by all Node.js subprocesses (including Jest workers) spawned in that step, raising the V8 heap limit to 4 GB without requiring per-package config changes.

The rit.config.js approach was not used because RIT remaps commands to add its own node ../node_modules/.bin/ prefix, making a custom command-based heap override ineffective.

Original prompt

Problem

The react-major-versions-integration CI job is OOMing (JavaScript heap out of memory) when running Jest tests for the react-charts package via the React Integration Tester (RIT) tool with React 17 and 18.

The crash happens because the react-charts test suite is large and memory-intensive (D3 + React renders, VegaDeclarativeChart tests), and the default Node.js V8 heap limit (~2 GB) is hit by a single Jest worker process.

The RIT template test command jest --passWithNoTests -u has no heap limit set, and modifying the shared templates to fix 1-2 packages is not desired.

Solution

Add a rit.config.js to packages/charts/react-charts/library/ that overrides the test command for both React 17 and 18 to raise the Node.js heap limit to 4096 MB using node --max-old-space-size=4096.

This follows the existing per-project RIT override pattern used in the repo (e.g. packages/react-components/react-provider/library/rit.config.js).

File to create

Create packages/charts/react-charts/library/rit.config.js with the following content:

// @ts-check

/** @type {import('@fluentui/react-integration-tester').Config} */
const config = {
  react: {
    17: {
      runConfig: {
        test: {
          command: 'node --max-old-space-size=4096 ../node_modules/.bin/jest --passWithNoTests -u',
        },
      },
    },
    18: {
      runConfig: {
        test: {
          command: 'node --max-old-space-size=4096 ../node_modules/.bin/jest --passWithNoTests -u',
        },
      },
    },
  },
};

module.exports = config;

No other files need to be changed.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: Please find a solution for this failing job. Use the logs, job definition, and any referenced files where the failure occurred. Keep your response focused on the solution and include code suggestions when appropriate.

Assistant: Now let me fetch the key files referenced in the errors:

Assistant: Looking at the logs and source files, there are two distinct failure categories:


Failure 1: rejects excessively deep JSON specs test (line 1345)

Root cause: The test at VegaDeclarativeChart.test.tsx:1345 calls expect(...).toThrow('Maximum JSON depth exceeded'), but the error is being thrown inside React's render cycle — not caught synchronously by the expect wrapper. React catches it internally and logs it as an unhandled exception (console.error), so toThrow() never sees it.

This happens because validateJsonDepth is called inside the component body (line 398 of VegaDeclarativeChart.tsx), which means React's error boundary / rendering pipeline intercepts it before Jest's .toThrow() can.

Fix: Wrap render(...) with @testing-library/react's recommended pattern for expecting render-time throws — use a try/catch or suppress the React error boundary noise. The most reliable fix is to wrap the render call so the error propagates correctly:

// VegaDeclarativeChart.test.tsx  ~line 1329
it('rejects excessively deep JSON specs (DoS prevention)', () => {
  let nested: Record<string, unknown> = { values: [{ x: 1, y: 1 }] };
  for (let i = 0; i < 20; i++) {
    nested = { wrapper: nested };
  }

  const deepSpec: VegaLiteSpec = {
    mark: 'bar',
    data: nested as VegaLiteSpec['data'],
    encoding: {
      x: { field: 'x', type: 'nominal' },
      y: { field: 'y', type: 'quantitative' },
    },
  };

  // Suppress React's internal error logging for this test
  const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});

  expect(() =>
    render(<VegaDeclarativeChart chartSchema={{ vegaLiteSpec: deepSpec }} />),
  ).toThrow('Maximum JSON depth exceeded');

  consoleSpy.mockRestore();
});

Alternatively, move the validation before the component renders — e.g., validate in the parent or call validateJsonDepth directly in the test to verify the utility itself:

it('rejects excessively deep JSON specs (DoS prevention)', () => {
  let nested: Record<string, unknown> = { values: [{ x: 1, y: 1 }] };
  for (let i = 0; i < 20; i++) {
    nested = { wrapper: nested };
  }

  const deepSpec: VegaLiteSpec = {
    mark: 'bar',
    data: nested as VegaLiteSpec['data'],
    encoding: {
      x: { field: 'x', type: 'nominal' },
      y: { field: 'y', type: 'quantitative' },
    },
  };

  // Validate the guard function directly — render-time throws are caught by React
  // and don't surface cleanly through expect().toThrow()
  expect(() => {
    // Simulate what the component does at render time
    const { vegaLiteSpec } = { vegaLiteSpec: deepSpec };
    // Re-invoke validateJsonDepth logic inline or export + import it for testing
    let depth = 0;
    const check = (val: unknown, d: number): void => {
      if (d > 15) throw new Error('VegaDeclarativeChart: Maximum JSON depth exceeded');
      if (val !== null && typeof val === 'object') {
        for...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

…or RIT tests

Co-authored-by: Hotell <1223799+Hotell@users.noreply.github.com>
Copilot AI changed the title [WIP] Add rit.config.js to increase heap limit for react-charts tests fix(react-charts): add rit.config.js to raise Node.js heap limit for RIT tests Apr 10, 2026
Copilot AI requested a review from Hotell April 10, 2026 12:11
@Hotell Hotell changed the title fix(react-charts): add rit.config.js to raise Node.js heap limit for RIT tests test(react-charts): add rit.config.js to raise Node.js heap limit for RIT tests Apr 10, 2026
@Hotell
Copy link
Copy Markdown
Contributor

Hotell commented Apr 10, 2026

@copilot this won't work because RIT actually remaps commands in template or rit.config.js to use explicit node ../node_modules/.bin prefix of provided command

we would need to exapnd the rit configuration options with NODE_OPTIONS probably, but that's adding too much coupling atm. we should go with simple NODE_OPTIONS: --max-old-space-size=4096 env set within the workflow

- name: React Versions Integration Tests (17,18) - Type-check & Test
        env:
          NODE_OPTIONS: --max-old-space-size=4096
        run: |
          FLUENT_JEST_WORKER=2 yarn nx affected -t test-rit--17--type-check,test-rit--18--type-check,test-rit--17--test,test-rit--18--test --exclude='react-19-tests-v9'  

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 10, 2026

@copilot this won't work because RIT actually remaps commands in template or rit.config.js to use explicit node ../node_modules/.bin prefix of provided command

we would need to exapnd the rit con...

Done — removed rit.config.js and instead added NODE_OPTIONS: --max-old-space-size=4096 as an env var on the "React Versions Integration Tests (17,18) - Type-check & Test" step in .github/workflows/pr.yml (commit 60389ec8).

Copilot AI changed the title test(react-charts): add rit.config.js to raise Node.js heap limit for RIT tests fix(ci): raise Node.js heap limit for RIT type-check & test step Apr 10, 2026
@github-actions github-actions bot added the CI label Apr 10, 2026
@Hotell Hotell marked this pull request as ready for review April 10, 2026 13:40
@Hotell Hotell requested a review from a team as a code owner April 10, 2026 13:40
@Hotell Hotell requested a review from dmytrokirpa April 10, 2026 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants