Skip to content

React 19 - Objects are not valid as a React child #1415

Open

Description

@emgdevteam
  • @testing-library/react version: 16.3.0
  • Testing Framework and version: vitest 3.2.4
  • DOM Environment: jsdom 26.1.0

Relevant code or config:

//package.json
{
  "name": "@emg-hub/ui",
  "version": "0.0.0",
  "private": true,
  "exports": {
    "./*": "./src/*.tsx"
  },
  "scripts": {
    "lint": "eslint . --max-warnings 0",
    "generate:component": "turbo gen react-component",
    "test": "vitest"
  },
  "devDependencies": {
    "@emg-hub/eslint-config": "*",
    "@emg-hub/typescript-config": "*",
    "@testing-library/dom": "^10.4.1",
    "@testing-library/jest-dom": "^6.8.0",
    "@testing-library/react": "^16.3.0",
    "@testing-library/user-event": "^14.6.1",
    "@types/node": "^24.3.0",
    "@types/react": "19.1.12",
    "@types/react-dom": "19.1.9",
    "@vitejs/plugin-react": "^5.0.2",
    "@vitest/coverage-v8": "^3.2.4",
    "@vitest/ui": "^3.2.4",
    "eslint": "^9.34.0",
    "jsdom": "^26.1.0",
    "typescript": "5.9.2",
    "vite-tsconfig-paths": "^5.1.4",
    "vitest": "^3.2.4"
  },
  "dependencies": {
    "react": "^19.1.1",
    "react-dom": "^19.1.1"
  }
}
//vitest.config.mjs
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { configDefaults } from 'vitest/config'

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    exclude: [...configDefaults.exclude, 'e2e/*'], // optional
    coverage: {
      provider: 'v8', // or 'c8'
      reporter: ['text', 'json', 'html'],
      exclude: ['vite.config.*', 'src/main.*', '**/*.d.ts', '**/__tests__/**'],
    },
  },
})
//button.tsx
import { ReactNode } from "react";

interface ButtonProps {
  children: ReactNode;
  className?: string;
  appName: string;
}

export const Button = ({ children, className, appName }: ButtonProps) => {
  return (
    <button
      className={className}
      onClick={() => alert(`Hello from your ${appName} app!`)}
    >
      {children}
    </button>
  );
};
//button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { Button } from './button';

describe('Button', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('rendering', () => {
    it('renders simple div', () => {
      render(<div>Click me</div>);
      expect(screen.getByText('Click me')).toBeInTheDocument();
    });
    it('renders with children text', () => {
      render(<Button appName="test">Click me</Button>);
      expect(screen.getByRole('button', { name: 'Click me' })).toBeInTheDocument();
    });
 });
});

What you did:

Tried running simple test using npm run test

What happened:

I got the error "Objects are not valid as a React child (found: object with keys {$$typeof, type, key, props, _owner, _store}). If you meant to render a collection of children, use an array instead." even on the simple test 'renders simple div'

Problem description:

I can't seem to run any test on this React component, with React 19. I also tried using Jest but same issues. I followed a guide to setup my test config. It's a simple internal package in a turborepo arch. The issue is always on the render method of the @testing-library/react

Suggested solution

I don't have any. I saw a similar issue #1387 but it was for a NextJs project and the solution offered isn't possible for me.

Activity

  1. changed the title [-]React 1[/-] [+]React 19 - Objects are not valid as a React child[/+] on Sep 4, 2025
  2. aralroca commented on Oct 1, 2025

    @aralroca

    A workaround for this?

  3. johnhkchen commented on Nov 14, 2025

    @johnhkchen

    Hi, this appears to be a Turbo / monorepo config issue. I stumbled into this bug and this is what Claude claims the workaround/fix is, YMMV:

    React 19 + Vitest Testing Issue (Turborepo/Workspaces)
    
      The Problem: You assume installing React 19 in your app is enough. In Turborepo, hoisted dependencies need React at root too.
    
      What's Actually Wrong: Dependencies with React 18 peer deps pull in React 18. Your lock file doesn't respect overrides from previous installs. Testing libraries are hoisted to root but can't find React 19.
    
      The Config Error to Expect:
      npm list react
      # Shows BOTH versions:
      ├─┬ @ant-design/icons@6.1.0
      │ └── react@18.3.1  # ← Dependencies pulling in v18
      ├── react@19.2.0    # ← Your version
    
      Why This Happens in Turborepo: npm install in workspaces hoists packages to root. If React isn't in root package.json, hoisted @testing-library/react can't find it or finds wrong version.
    
      The Fix:
      # 1. Clean install to apply overrides properly
      rm -rf node_modules package-lock.json
      npm install
    
      # 2. Add React to ROOT package.json (not just app)
      {
        "devDependencies": {
          "react": "^19.2.0",
          "react-dom": "^19.2.0"
        },
        "overrides": {
          "react": "^19.2.0",
          "react-dom": "^19.2.0"
        }
      }
    
      # 3. Ensure @testing-library/dom is installed
      npm install @testing-library/dom --save-dev
    
      # 4. In vitest.config.ts, point to root React:
      resolve: {
        alias: {
          'react': path.resolve(__dirname, '../../node_modules/react'),
          // ... other React aliases
        }
      }
    
  4. d-ellis commented on May 27, 2026

    @d-ellis

    Ran into this same issue with React 19 + Vitest.
    I just added resolve.dedupe to my vite.config.ts, like so:

    import {defineConfig} from 'vite';
    import react from '@vitejs/plugin-react';
    
    export default defineConfig({
        plugins: [react()],
        resolve: {
            dedupe: ['react', 'react-dom']
        }
    });

    and it works with no errors now

  5. beanscg commented on Jun 9, 2026

    @beanscg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions