/**
* Unit tests for Portal component
*
* Tests the Portal component which uses ReactDOM.createPortal to render
* children outside the parent DOM hierarchy. This is useful for modals,
* tooltips, and other UI elements that need to escape parent stacking contexts.
*/
import { describe, it, expect, afterEach } from 'vitest';
import { render, screen, cleanup } from '@testing-library/react';
import Portal from '../Portal';
describe('Portal', () => {
afterEach(() => {
// Clean up any rendered components
cleanup();
});
describe('Basic Rendering', () => {
it('should render children', () => {
render(
Portal Content
);
expect(screen.getByTestId('portal-content')).toBeInTheDocument();
expect(screen.getByText('Portal Content')).toBeInTheDocument();
});
it('should render text content', () => {
render(Simple text content);
expect(screen.getByText('Simple text content')).toBeInTheDocument();
});
it('should render complex JSX children', () => {
render(
);
expect(screen.getByTestId('nested')).toBeInTheDocument();
expect(screen.getByText('Nested Component')).toBeInTheDocument();
expect(screen.getByText('Other content')).toBeInTheDocument();
});
});
describe('Mounting Behavior', () => {
it('should not render before component is mounted', () => {
// This test verifies the internal mounting state
const { rerender } = render(
Content
);
// After initial render, content should be present
expect(screen.getByTestId('portal-content')).toBeInTheDocument();
// Re-render should still show content
rerender(
);
expect(screen.getByTestId('portal-1')).toBeInTheDocument();
expect(screen.getByTestId('portal-2')).toBeInTheDocument();
expect(screen.getByTestId('portal-3')).toBeInTheDocument();
// All portals should be in document.body
expect(document.body.contains(screen.getByTestId('portal-1'))).toBe(true);
expect(document.body.contains(screen.getByTestId('portal-2'))).toBe(true);
expect(document.body.contains(screen.getByTestId('portal-3'))).toBe(true);
});
it('should keep portals separate from each other', () => {
render(
Content 1
Content 2
);
const portal1 = screen.getByTestId('portal-1');
const portal2 = screen.getByTestId('portal-2');
const content1 = screen.getByTestId('content-1');
const content2 = screen.getByTestId('content-2');
// Each portal should contain only its own content
expect(portal1.contains(content1)).toBe(true);
expect(portal1.contains(content2)).toBe(false);
expect(portal2.contains(content2)).toBe(true);
expect(portal2.contains(content1)).toBe(false);
});
});
describe('Cleanup', () => {
it('should remove content from body when unmounted', () => {
const { unmount } = render(
Temporary Content
);
// Content should exist initially
expect(screen.getByTestId('portal-content')).toBeInTheDocument();
// Unmount the component
unmount();
// Content should be removed from DOM
expect(screen.queryByTestId('portal-content')).not.toBeInTheDocument();
});
it('should clean up multiple portals on unmount', () => {
const { unmount } = render(