UNPKG

qnce-engine

Version:

Core QNCE (Quantum Narrative Convergence Engine) - Framework agnostic narrative engine with performance optimization

245 lines 13.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("@testing-library/react"); const dom_1 = require("@testing-library/dom"); const user_event_1 = __importDefault(require("@testing-library/user-event")); const UndoRedoControls_1 = require("../components/UndoRedoControls"); const core_1 = require("../../engine/core"); const demo_story_1 = require("../../engine/demo-story"); // Mock the useUndoRedo hook jest.mock('../../integrations/react', () => ({ useUndoRedo: jest.fn() })); // Get the mocked version const react_2 = require("../../integrations/react"); const mockUseUndoRedo = react_2.useUndoRedo; describe('UndoRedoControls', () => { let engine; let mockUndoRedoState; beforeEach(() => { engine = (0, core_1.createQNCEEngine)(demo_story_1.DEMO_STORY); mockUndoRedoState = { undo: jest.fn().mockResolvedValue({ success: true, description: 'Undid action' }), redo: jest.fn().mockResolvedValue({ success: true, description: 'Redid action' }), canUndo: true, canRedo: true, undoCount: 2, redoCount: 1 }; // Setup the mock to return our mock state mockUseUndoRedo.mockReturnValue(mockUndoRedoState); }); afterEach(() => { jest.clearAllMocks(); }); describe('Basic Rendering', () => { it('renders undo and redo buttons', () => { (0, react_1.act)(() => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); }); expect(dom_1.screen.getByRole('button', { name: /undo/i })).toBeInTheDocument(); expect(dom_1.screen.getByRole('button', { name: /redo/i })).toBeInTheDocument(); }); it('displays custom labels when provided', () => { const customLabels = { undo: 'Go Back', redo: 'Go Forward' }; (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, labels: customLabels })); expect(dom_1.screen.getByRole('button', { name: /go back/i })).toBeInTheDocument(); expect(dom_1.screen.getByRole('button', { name: /go forward/i })).toBeInTheDocument(); }); it('hides labels when showLabels is false', () => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, showLabels: false })); // Should still have accessible names but no visible text expect(dom_1.screen.getByRole('button', { name: /undo/i })).toBeInTheDocument(); expect(dom_1.screen.getByRole('button', { name: /redo/i })).toBeInTheDocument(); // Text should not be visible (aria-label only) expect(dom_1.screen.queryByText('Undo')).not.toBeInTheDocument(); expect(dom_1.screen.queryByText('Redo')).not.toBeInTheDocument(); }); }); describe('Button States', () => { it('enables buttons when actions are available', () => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const undoButton = dom_1.screen.getByRole('button', { name: /undo/i }); const redoButton = dom_1.screen.getByRole('button', { name: /redo/i }); expect(undoButton).not.toBeDisabled(); expect(redoButton).not.toBeDisabled(); }); it('disables undo button when canUndo is false', () => { mockUseUndoRedo.mockReturnValue({ ...mockUndoRedoState, canUndo: false }); (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const undoButton = dom_1.screen.getByRole('button', { name: /undo/i }); expect(undoButton).toBeDisabled(); }); it('disables redo button when canRedo is false', () => { mockUseUndoRedo.mockReturnValue({ ...mockUndoRedoState, canRedo: false }); (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const redoButton = dom_1.screen.getByRole('button', { name: /redo/i }); expect(redoButton).toBeDisabled(); }); it('disables all buttons when disabled prop is true', () => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, disabled: true })); const undoButton = dom_1.screen.getByRole('button', { name: /undo/i }); const redoButton = dom_1.screen.getByRole('button', { name: /redo/i }); expect(undoButton).toBeDisabled(); expect(redoButton).toBeDisabled(); }); }); describe('User Interactions', () => { it('calls undo function when undo button is clicked', async () => { const user = user_event_1.default.setup(); (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const undoButton = dom_1.screen.getByRole('button', { name: /undo/i }); await user.click(undoButton); expect(mockUndoRedoState.undo).toHaveBeenCalledTimes(1); }); it('calls redo function when redo button is clicked', async () => { const user = user_event_1.default.setup(); (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const redoButton = dom_1.screen.getByRole('button', { name: /redo/i }); await user.click(redoButton); expect(mockUndoRedoState.redo).toHaveBeenCalledTimes(1); }); it('calls onUndo callback when provided', async () => { const onUndo = jest.fn(); const user = user_event_1.default.setup(); (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, onUndo: onUndo })); const undoButton = dom_1.screen.getByRole('button', { name: /undo/i }); await user.click(undoButton); await (0, dom_1.waitFor)(() => { expect(onUndo).toHaveBeenCalledWith({ success: true, description: 'Undid action' }); }); }); it('calls onRedo callback when provided', async () => { const onRedo = jest.fn(); const user = user_event_1.default.setup(); (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, onRedo: onRedo })); const redoButton = dom_1.screen.getByRole('button', { name: /redo/i }); await user.click(redoButton); await (0, dom_1.waitFor)(() => { expect(onRedo).toHaveBeenCalledWith({ success: true, description: 'Redid action' }); }); }); }); describe('Layout and Styling', () => { it('applies horizontal layout by default', () => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const container = dom_1.screen.getByRole('group'); expect(container).toHaveStyle({ flexDirection: 'row' }); }); it('applies vertical layout when specified', () => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, layout: "vertical" })); const container = dom_1.screen.getByRole('group'); expect(container).toHaveStyle({ flexDirection: 'column' }); }); it('applies custom className', () => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, className: "custom-controls" })); const container = dom_1.screen.getByRole('group'); expect(container).toHaveClass('custom-controls'); }); it('applies custom style', () => { const customStyle = { backgroundColor: 'red' }; (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, style: customStyle })); const container = dom_1.screen.getByRole('group'); expect(container).toHaveAttribute('style'); expect(container.getAttribute('style')).toContain('background-color: red'); }); it('applies different sizes correctly', () => { const { rerender } = (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, size: "sm" })); let buttons = dom_1.screen.getAllByRole('button'); expect(buttons[0]).toHaveStyle({ fontSize: '0.875rem' }); rerender((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, size: "lg" })); buttons = dom_1.screen.getAllByRole('button'); expect(buttons[0]).toHaveStyle({ fontSize: '1.125rem' }); }); }); describe('Accessibility', () => { it('has proper ARIA attributes', () => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const container = dom_1.screen.getByRole('group'); expect(container).toHaveAttribute('aria-label', 'Undo and redo controls'); const undoButton = dom_1.screen.getByRole('button', { name: /undo/i }); const redoButton = dom_1.screen.getByRole('button', { name: /redo/i }); expect(undoButton).toHaveAttribute('aria-label'); expect(redoButton).toHaveAttribute('aria-label'); }); it('shows tooltips with state information', () => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const undoButton = dom_1.screen.getByRole('button', { name: /undo/i }); const redoButton = dom_1.screen.getByRole('button', { name: /redo/i }); expect(undoButton).toHaveAttribute('title'); expect(redoButton).toHaveAttribute('title'); }); it('supports keyboard navigation', async () => { const user = user_event_1.default.setup(); (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); // Tab to first button await user.tab(); expect(dom_1.screen.getByRole('button', { name: /undo/i })).toHaveFocus(); // Tab to second button await user.tab(); expect(dom_1.screen.getByRole('button', { name: /redo/i })).toHaveFocus(); }); it('activates buttons with Enter and Space keys', async () => { const user = user_event_1.default.setup(); (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const undoButton = dom_1.screen.getByRole('button', { name: /undo/i }); undoButton.focus(); // Test Enter key await user.keyboard('{Enter}'); expect(mockUndoRedoState.undo).toHaveBeenCalledTimes(1); // Test Space key await user.keyboard(' '); expect(mockUndoRedoState.undo).toHaveBeenCalledTimes(2); }); }); describe('Theme Integration', () => { it('applies default theme', () => { (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine })); const buttons = dom_1.screen.getAllByRole('button'); buttons.forEach((button) => { expect(button).toHaveStyle({ 'border-radius': '0.375rem' }); }); }); it('applies custom theme', () => { const customTheme = { borderRadius: { sm: '2px', md: '8px', lg: '12px' } }; (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, theme: customTheme })); const buttons = dom_1.screen.getAllByRole('button'); buttons.forEach((button) => { expect(button).toHaveStyle({ borderRadius: '8px' }); }); }); }); describe('Error Handling', () => { it('handles undo/redo failures gracefully', async () => { mockUseUndoRedo.mockReturnValue({ ...mockUndoRedoState, undo: jest.fn().mockResolvedValue({ success: false, error: 'Undo failed' }) }); const onUndo = jest.fn(); const user = user_event_1.default.setup(); (0, react_1.render)((0, jsx_runtime_1.jsx)(UndoRedoControls_1.UndoRedoControls, { engine: engine, onUndo: onUndo })); const undoButton = dom_1.screen.getByRole('button', { name: /undo/i }); await user.click(undoButton); await (0, dom_1.waitFor)(() => { expect(onUndo).toHaveBeenCalledWith({ success: false, error: 'Undo failed' }); }); }); }); }); //# sourceMappingURL=UndoRedoControls.test.js.map