feat: improve tablet screen controls and participant action states
- Add wake lock and browser fullscreen controls to encounter header/popout - Re-acquire wake lock after browser release (still doesnt work on tablet) - Retry fullscreen after Android unlock; keep manual control visible - Add larger labeled character Save button - Use distinct panel icon for encounter full-page expansion - Add strong active/inactive, conditions-open, and editing button states - Keep inactive participant controls visible - Add regression tests and update affected characterization tests - Update project TODO notes
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { setupReady } from './testHelpers';
|
||||
|
||||
describe('screen controls', () => {
|
||||
let originalRequestFullscreen;
|
||||
let originalExitFullscreen;
|
||||
let originalFullscreenElement;
|
||||
let originalVisibilityState;
|
||||
let originalWakeLock;
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
originalRequestFullscreen = document.documentElement.requestFullscreen;
|
||||
originalExitFullscreen = document.exitFullscreen;
|
||||
originalFullscreenElement = Object.getOwnPropertyDescriptor(document, 'fullscreenElement');
|
||||
originalVisibilityState = Object.getOwnPropertyDescriptor(document, 'visibilityState');
|
||||
originalWakeLock = Object.getOwnPropertyDescriptor(navigator, 'wakeLock');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.documentElement.requestFullscreen = originalRequestFullscreen;
|
||||
document.exitFullscreen = originalExitFullscreen;
|
||||
if (originalFullscreenElement) Object.defineProperty(document, 'fullscreenElement', originalFullscreenElement);
|
||||
else Object.defineProperty(document, 'fullscreenElement', { configurable: true, value: null });
|
||||
if (originalVisibilityState) Object.defineProperty(document, 'visibilityState', originalVisibilityState);
|
||||
if (originalWakeLock) Object.defineProperty(navigator, 'wakeLock', originalWakeLock);
|
||||
else Object.defineProperty(navigator, 'wakeLock', { configurable: true, value: undefined });
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
test('encounter header exposes prevent-sleep, browser-fullscreen, and popout controls', async () => {
|
||||
await setupReady('ScreenCamp', 'ScreenEnc');
|
||||
|
||||
expect(screen.getAllByRole('button', { name: 'Prevent sleep' }).length).toBeGreaterThanOrEqual(2);
|
||||
expect(screen.getAllByRole('button', { name: 'Enter browser fullscreen' })).toHaveLength(1);
|
||||
expect(screen.getByRole('button', { name: 'Expand encounter to full page' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('re-acquires wake lock when tablet becomes visible after browser release', async () => {
|
||||
let releaseListener;
|
||||
const sentinel = {
|
||||
released: false,
|
||||
release: jest.fn().mockResolvedValue(undefined),
|
||||
addEventListener: jest.fn((event, callback) => { if (event === 'release') releaseListener = callback; }),
|
||||
};
|
||||
const request = jest.fn().mockResolvedValue(sentinel);
|
||||
Object.defineProperty(navigator, 'wakeLock', { configurable: true, value: { request } });
|
||||
let visibility = 'visible';
|
||||
Object.defineProperty(document, 'visibilityState', { configurable: true, get: () => visibility });
|
||||
|
||||
await setupReady('WakeCamp', 'WakeEnc');
|
||||
fireEvent.click(screen.getAllByRole('button', { name: 'Prevent sleep' })[0]);
|
||||
await waitFor(() => expect(request).toHaveBeenCalledTimes(1));
|
||||
|
||||
visibility = 'hidden';
|
||||
releaseListener();
|
||||
visibility = 'visible';
|
||||
document.dispatchEvent(new Event('visibilitychange'));
|
||||
|
||||
await waitFor(() => expect(request).toHaveBeenCalledTimes(2));
|
||||
});
|
||||
|
||||
test('character editor has labeled tablet-sized save button', async () => {
|
||||
await setupReady('SaveCamp', 'SaveEnc');
|
||||
fireEvent.change(screen.getByLabelText('Name', { selector: '#characterName' }), { target: { value: 'Tablet Hero' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Add Character' }));
|
||||
await screen.findByText('Tablet Hero');
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Edit character' }));
|
||||
const save = screen.getByRole('button', { name: 'Save character' });
|
||||
expect(save).toHaveTextContent('Save');
|
||||
expect(save).toHaveClass('min-h-[40px]');
|
||||
});
|
||||
|
||||
test('attempts to restore fullscreen when tablet becomes visible after lock', async () => {
|
||||
const requestFullscreen = jest.fn().mockResolvedValue(undefined);
|
||||
document.documentElement.requestFullscreen = requestFullscreen;
|
||||
document.exitFullscreen = jest.fn().mockResolvedValue(undefined);
|
||||
Object.defineProperty(document, 'fullscreenElement', { configurable: true, get: () => null });
|
||||
let visibility = 'visible';
|
||||
Object.defineProperty(document, 'visibilityState', { configurable: true, get: () => visibility });
|
||||
|
||||
await setupReady('RestoreCamp', 'RestoreEnc');
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Enter browser fullscreen' }));
|
||||
await waitFor(() => expect(requestFullscreen).toHaveBeenCalledTimes(1));
|
||||
|
||||
visibility = 'hidden';
|
||||
document.dispatchEvent(new Event('fullscreenchange'));
|
||||
visibility = 'visible';
|
||||
document.dispatchEvent(new Event('visibilitychange'));
|
||||
|
||||
await waitFor(() => expect(requestFullscreen).toHaveBeenCalledTimes(2));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user