Open the global terminal outside Livewire navigation, clarify that image tag and SHA256 digest are mutually exclusive, inset the GitLab empty state, and show loading on Dockerfile create. Add regression tests.
492 lines
24 KiB
PHP
492 lines
24 KiB
PHP
<?php
|
|
|
|
it('renders the resource terminal shell while containers are discovered', function () {
|
|
$terminalComponent = file_get_contents(app_path('Livewire/Project/Shared/ExecuteContainerCommand.php'));
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
|
|
expect($terminalComponent)
|
|
->toContain('public bool $containersLoaded = false;')
|
|
->and($terminalView)
|
|
->toContain('wire:init="loadContainers"')
|
|
->not->toContain('@if (! $containersLoaded)')
|
|
->not->toContain('Loading terminal containers…')
|
|
->toContain(':auto-start="$type === \'server\' || ! $containersLoaded || $containers->count() === 1"')
|
|
->not->toContain('Loading targets…')
|
|
->not->toContain('<x-loading text="Loading containers" />');
|
|
});
|
|
|
|
it('provides opt-in diagnostics for connected terminal theme changes', function () {
|
|
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->toContain('terminal-debug')
|
|
->toContain("'[Terminal Theme] Applying theme'")
|
|
->toContain("'[Terminal Theme] Theme applied'")
|
|
->toContain('requestedTheme: themeName')
|
|
->toContain('shellTheme: shell?.dataset.consoleTheme')
|
|
->toContain("getComputedStyle(shell, '::before').background");
|
|
});
|
|
|
|
it('starts a single discovered resource container without waiting for a missed browser event', function () {
|
|
$terminalComponent = file_get_contents(app_path('Livewire/Project/Shared/ExecuteContainerCommand.php'));
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
|
|
expect($terminalComponent)
|
|
->toMatch('/if \(\$this->containers->count\(\) === 1\) \{\s*\$this->selected_container = [^;]+;\s*\$this->connectToContainer\(\);/s')
|
|
->and($terminalView)
|
|
->not->toContain('x-on:containers-loaded.window');
|
|
});
|
|
|
|
it('integrates automatic terminal startup into the terminal console', function () {
|
|
$terminalComponent = file_get_contents(app_path('Livewire/Project/Shared/Terminal.php'));
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
$commandView = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
|
|
expect($terminalComponent)
|
|
->toContain('public bool $autoStart = false;')
|
|
->and($terminalView)
|
|
->toContain('data-auto-start="{{ $autoStart ? \'true\' : \'false\' }}"')
|
|
->toContain("starting ? 'connecting…'")
|
|
->and($commandView)
|
|
->toContain(':auto-start="$type === \'server\' || ! $containersLoaded || $containers->count() === 1"')
|
|
->not->toContain('terminalLoading')
|
|
->not->toContain('Starting terminal');
|
|
});
|
|
|
|
it('resynchronizes the themed canvas whenever a terminal enters a loading state', function () {
|
|
$resourceView = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
$globalView = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
|
|
|
foreach ([$resourceView, $globalView] as $view) {
|
|
expect($view)
|
|
->toContain('x-on:terminal-starting.window="syncTheme()"')
|
|
->toContain('syncTheme() {')
|
|
->toContain("this.consoleTheme = this.themeKeys.includes(savedTheme) ? savedTheme : 'system';");
|
|
}
|
|
});
|
|
|
|
it('keeps the xterm mount visible while the terminal connection starts', function () {
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
|
|
expect($terminalView)
|
|
->toMatch('/<div id="terminal"[^>]*wire:ignore/s')
|
|
->not->toMatch('/<div id="terminal"[^>]*x-show="terminalActive"/s');
|
|
});
|
|
|
|
it('shows the initial resource container launcher and keeps the header picker for switching', function () {
|
|
$commandView = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
|
|
expect($commandView)
|
|
->toContain('targetChosen: @js($selected_container !== \'default\')')
|
|
->toContain('data-terminal-target-picker="launcher"')
|
|
->toContain('x-show="!targetChosen"')
|
|
->toContain('x-show="targetChosen"')
|
|
->toContain('this.targetChosen = true;');
|
|
});
|
|
|
|
it('uses a larger high-contrast label for every terminal loading phase', function () {
|
|
$resourceView = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
$globalView = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
|
$styles = file_get_contents(resource_path('css/app.css'));
|
|
|
|
expect(substr_count($resourceView.$terminalView.$globalView, 'terminal-loading-label'))
|
|
->toBeGreaterThanOrEqual(3)
|
|
->and($styles)
|
|
->toContain('.terminal-loading-label')
|
|
->toContain('font-size: 0.875rem;')
|
|
->toContain('color: rgb(255 255 255 / 0.75);')
|
|
->toContain('html:not(.dark) .application-console-shell[data-console-theme="system"] .terminal-loading-label');
|
|
});
|
|
|
|
it('styles centered terminal target pickers from the selected console theme', function () {
|
|
$resourceView = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
$globalView = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
|
$styles = file_get_contents(resource_path('css/app.css'));
|
|
|
|
expect(substr_count($resourceView.$globalView, 'terminal-target-picker'))
|
|
->toBeGreaterThanOrEqual(2)
|
|
->and($styles)
|
|
->toContain('.terminal-target-picker')
|
|
->toContain('.application-console-shell[data-console-theme="system"] .terminal-target-picker')
|
|
->toContain('background: rgb(0 0 0 / 0.18);')
|
|
->toContain('background: #fff;')
|
|
->toContain('color: #52525b;');
|
|
});
|
|
|
|
it('presents initial terminal targets as a top-aligned launcher instead of a centered dialog', function () {
|
|
$resourceView = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
$globalView = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
|
|
|
expect($resourceView.$globalView)
|
|
->toContain('data-terminal-target-picker="launcher"')
|
|
->toContain('items-start justify-start')
|
|
->toContain('Start a terminal session')
|
|
->not->toContain('data-terminal-target-picker="center"');
|
|
});
|
|
|
|
it('shows connection progress in the terminal body instead of the header', function () {
|
|
$resourceView = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
$globalView = file_get_contents(resource_path('views/livewire/terminal/index.blade.php'));
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
|
|
|
expect($resourceView.$globalView)
|
|
->toContain("new CustomEvent('terminal-starting')")
|
|
->not->toContain('wire:loading.flex wire:target="selected_container,connectToContainer"')
|
|
->not->toContain('wire:loading.flex wire:target="selected_uuid,connectToContainer"')
|
|
->and($terminalView)
|
|
->toContain("x-on:terminal-starting.window=\"starting = true; setTerminalTheme(localStorage.getItem('coolify-console-theme') ?? 'system')\"")
|
|
->toContain('data-auto-start="{{ $autoStart ? \'true\' : \'false\' }}"')
|
|
->toContain("starting ? 'connecting…'")
|
|
->and($terminalClient)
|
|
->toContain('starting: false')
|
|
->toContain("this.starting = this.\$el.dataset.autoStart === 'true';");
|
|
});
|
|
|
|
it('uses the redesigned terminal canvas and controls on resource terminal pages', function () {
|
|
$view = file_get_contents(resource_path('views/livewire/project/shared/execute-container-command.blade.php'));
|
|
|
|
expect($view)
|
|
->toContain('data-terminal-session-canvas')
|
|
->toContain('terminal-session-toolbar absolute top-3 right-3 left-3')
|
|
->toContain('terminal-session-panel mt-8')
|
|
->toContain('<x-terminal.theme-selector')
|
|
->not->toContain('application-console-header flex h-[30px]');
|
|
});
|
|
|
|
it('uses a readable theme-aware terminal session expiry label', function () {
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
$styles = file_get_contents(resource_path('css/app.css'));
|
|
|
|
expect($terminalView)
|
|
->toContain('terminal-session-expiry')
|
|
->and($styles)
|
|
->toContain('.terminal-session-expiry')
|
|
->toContain('font-size: 0.75rem;')
|
|
->toContain('color: rgb(255 255 255 / 0.6);')
|
|
->toContain('.terminal-fullscreen-shell[data-console-theme="system"] .terminal-session-expiry');
|
|
});
|
|
|
|
it('copies the realtime terminal utilities into the container image', function () {
|
|
$dockerfile = file_get_contents(base_path('docker/coolify-realtime/Dockerfile'));
|
|
|
|
expect($dockerfile)->toContain('COPY docker/coolify-realtime/terminal-utils.js /terminal/terminal-utils.js');
|
|
});
|
|
|
|
it('mounts the realtime terminal utilities in local development compose files', function (string $composeFile) {
|
|
$composeContents = file_get_contents(base_path($composeFile));
|
|
|
|
expect($composeContents)->toContain('./docker/coolify-realtime/terminal-utils.js:/terminal/terminal-utils.js');
|
|
})->with([
|
|
'default dev compose' => 'docker-compose.dev.yml',
|
|
'maxio dev compose' => 'docker-compose-maxio.dev.yml',
|
|
]);
|
|
|
|
it('keeps terminal browser logging restricted to Vite development mode', function () {
|
|
$terminalClient = file_get_contents(base_path('resources/js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->toContain('const terminalDebugEnabled = import.meta.env.DEV;')
|
|
->toContain("logTerminal('log', '[Terminal] WebSocket connection established.');")
|
|
->not->toContain("console.log('[Terminal] WebSocket connection established. Cool cool cool cool cool cool.');");
|
|
});
|
|
|
|
it('keeps realtime terminal server logging behind the explicit debug flag', function () {
|
|
$terminalServer = file_get_contents(base_path('docker/coolify-realtime/terminal-server.js'));
|
|
|
|
expect($terminalServer)
|
|
->toContain('const debugOverride = String(process.env.TERMINAL_DEBUG')
|
|
->toContain("['1', 'true', 'yes', 'on'].includes(debugOverride)")
|
|
->toContain('if (!terminalDebugEnabled) {')
|
|
->not->toContain("console.log('Coolify realtime terminal server listening on port 6002. Let the hacking begin!');");
|
|
});
|
|
|
|
it('configures a server-initiated WebSocket heartbeat to survive proxy idle timeouts', function () {
|
|
$terminalServer = file_get_contents(base_path('docker/coolify-realtime/terminal-server.js'));
|
|
|
|
expect($terminalServer)
|
|
->toContain('ws.isAlive = true;')
|
|
->toContain("ws.on('pong'")
|
|
->toContain('ws.ping();')
|
|
->toContain('ws.terminate();')
|
|
->toContain('HEARTBEAT_INTERVAL_MS');
|
|
});
|
|
|
|
it('removes the keepalive short-circuit that fired when the tab was hidden', function () {
|
|
$terminalClient = file_get_contents(base_path('resources/js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->not->toContain('// Skip keepalive when document is hidden to prevent unnecessary disconnects');
|
|
});
|
|
|
|
it('uses a fast probe timeout when the tab regains visibility', function () {
|
|
$terminalClient = file_get_contents(base_path('resources/js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->toContain("'Visibility-resume timeout'");
|
|
});
|
|
|
|
it('does not hard close terminal sessions after 30 minutes on the server', function () {
|
|
$terminalServer = file_get_contents(base_path('docker/coolify-realtime/terminal-server.js'));
|
|
|
|
expect($terminalServer)
|
|
->not->toContain('IDLE_TIMEOUT_MS = 30 * 60 * 1000')
|
|
->not->toContain("ws.send('idle-timeout');")
|
|
->not->toContain("ws.close(1000, 'Idle timeout');");
|
|
});
|
|
|
|
it('does not close the client terminal from an idle-timeout sentinel', function () {
|
|
$terminalClient = file_get_contents(base_path('resources/js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->not->toContain("event.data === 'idle-timeout'")
|
|
->not->toContain('Terminal closed after 30 minutes of inactivity.');
|
|
});
|
|
|
|
it('keeps Livewire alive in background tabs while a terminal is connected', function () {
|
|
$terminalComponent = file_get_contents(base_path('app/Livewire/Project/Shared/Terminal.php'));
|
|
$terminalView = file_get_contents(base_path('resources/views/livewire/project/shared/terminal.blade.php'));
|
|
|
|
expect($terminalComponent)
|
|
->toContain('public bool $isTerminalConnected = false;')
|
|
->toContain("#[On('terminalConnected')]")
|
|
->toContain('public function markTerminalConnected(): void')
|
|
->toContain('public function keepTerminalPageAlive(): void')
|
|
->and($terminalView)
|
|
->toContain('@if ($isTerminalConnected)')
|
|
->toContain('wire:poll.keep-alive.30s="keepTerminalPageAlive"');
|
|
});
|
|
|
|
it('exits fullscreen when the terminal process exits', function () {
|
|
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->toContain("event.data === 'pty-exited'")
|
|
->toContain('this.exitFullscreen();')
|
|
->toContain('this.mobileToolbarCollapsed = false;
|
|
this.terminalActive = false;');
|
|
});
|
|
|
|
it('replays the last command on reconnect so the PTY respawns automatically', function () {
|
|
$terminalClient = file_get_contents(base_path('resources/js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->toContain('lastSentCommand')
|
|
->toContain('Replaying last command after reconnect.')
|
|
->toContain('this.lastSentCommand = null;');
|
|
});
|
|
|
|
it('buffers messages received before the realtime server finishes auth so the replay is not lost', function () {
|
|
$terminalServer = file_get_contents(base_path('docker/coolify-realtime/terminal-server.js'));
|
|
|
|
expect($terminalServer)
|
|
->toContain('authReady: false')
|
|
->toContain('pendingMessages: []')
|
|
->toContain('userSession.pendingMessages.push(message)')
|
|
->toContain('userSession.authReady = true');
|
|
});
|
|
|
|
it('preserves terminal scrollback across transient reconnects', function () {
|
|
$terminalClient = file_get_contents(base_path('resources/js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->toContain('── Connection lost at')
|
|
->toContain('── Reconnected at')
|
|
// resetTerminal must NOT call term.reset()/term.clear() any more — those wipe scrollback.
|
|
->not->toContain("this.term.reset();\n this.term.clear();");
|
|
});
|
|
|
|
it('renders a compact mobile terminal toolbar with shell control keys', function () {
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
$appCss = file_get_contents(resource_path('css/app.css'));
|
|
|
|
expect($terminalView)
|
|
->toContain('Terminal keys')
|
|
->toContain('sm:hidden')
|
|
->toContain("sendTerminalControl('arrowUp')")
|
|
->toContain("sendTerminalControl('arrowDown')")
|
|
->toContain("sendTerminalControl('arrowLeft')")
|
|
->toContain("sendTerminalControl('arrowRight')")
|
|
->toContain("sendTerminalControl('tab')")
|
|
->toContain("sendTerminalControl('escape')")
|
|
->not->toContain("sendTerminalControl('ctrlC')")
|
|
->not->toContain('pasteFromClipboard()')
|
|
->not->toContain('copyTerminalSelection()')
|
|
->toContain('mobileToolbarCollapsed')
|
|
->toContain("fullscreen ? 'absolute inset-x-0 bottom-0 z-[2] px-2 pb-2' : 'relative mt-2 shrink-0'")
|
|
->toContain('data-terminal-mobile-toolbar')
|
|
->and($appCss)
|
|
->toContain('.terminal-mobile-key');
|
|
});
|
|
|
|
it('sends terminal mobile toolbar controls through the websocket', function () {
|
|
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->toContain('sendTerminalInput(data)')
|
|
->toContain('sendTerminalControl(sequence)')
|
|
->toContain("arrowUp: '\\x1b[A'")
|
|
->toContain("arrowDown: '\\x1b[B'")
|
|
->toContain("arrowRight: '\\x1b[C'")
|
|
->toContain("arrowLeft: '\\x1b[D'")
|
|
->toContain("tab: '\\t'")
|
|
->toContain("escape: '\\x1b'")
|
|
->toContain("ctrlC: '\\x03'")
|
|
->toContain('navigator.clipboard.readText()')
|
|
->toContain('navigator.clipboard.writeText(selection)');
|
|
});
|
|
|
|
it('uses terminal host dimensions when resizing so mobile controls do not cover terminal rows', function () {
|
|
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->toContain("document.getElementById('terminal')")
|
|
->toContain('this.fitAddon.fit()')
|
|
->toContain('terminalElement.clientHeight')
|
|
->not->toContain('const wrapperHeight = this.$refs.terminalWrapper.clientHeight;');
|
|
});
|
|
|
|
it('uses simple fullscreen bottom margin based on mobile toolbar visibility', function () {
|
|
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
|
|
expect($terminalClient)
|
|
->not->toContain('updateFullscreenLayout()')
|
|
->not->toContain('terminalFullscreenHeight')
|
|
->not->toContain('window.visualViewport?.height')
|
|
->and($terminalView)
|
|
->toContain("mobileToolbarCollapsed\n ? 'terminal-host relative z-[1] min-h-0 flex-1 overflow-hidden px-1 py-[5px] bg-transparent max-sm:pb-14'\n : 'terminal-host relative z-[1] min-h-0 flex-1 overflow-hidden px-1 py-[5px] bg-transparent max-sm:pb-24'")
|
|
->toContain("fullscreen ? 'absolute inset-x-0 bottom-0 z-[2] px-2 pb-2'");
|
|
});
|
|
|
|
it('resizes after toggling the mobile terminal toolbar', function () {
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
|
|
expect($terminalView)
|
|
->toContain('$nextTick(() => resizeTerminal())');
|
|
});
|
|
|
|
it('uses fixed viewport positioning for fullscreen terminal instead of inherited container size', function () {
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
$styles = file_get_contents(resource_path('css/app.css'));
|
|
|
|
expect($terminalView)
|
|
->toContain('terminal-fullscreen-shell fixed inset-0')
|
|
->toContain('z-[100000]')
|
|
->toContain('w-screen')
|
|
->toContain('max-w-none')
|
|
->toContain('overflow-hidden')
|
|
->toContain(':data-console-theme="fullscreen ? selectedTheme : null"')
|
|
->not->toContain('h-[100dvh]')
|
|
->and($styles)
|
|
->toContain('height: auto !important;');
|
|
});
|
|
|
|
it('constrains normal terminal height after leaving fullscreen', function () {
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
|
|
expect($terminalView)
|
|
->toContain('h-[510px] max-h-[calc(100dvh-10rem)] overflow-hidden');
|
|
});
|
|
|
|
it('keeps enter and exit fullscreen controls the same size and chrome', function () {
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
$appCss = file_get_contents(resource_path('css/app.css'));
|
|
|
|
expect($terminalView)
|
|
->toContain('class="terminal-fullscreen-btn fixed top-3 right-3 z-[100001]"')
|
|
->toContain("'terminal-fullscreen-btn absolute z-20'")
|
|
->and($appCss)
|
|
->toContain('.terminal-fullscreen-btn')
|
|
->toContain('width: 1.75rem')
|
|
->toContain('height: 1.75rem')
|
|
->toContain('color: var(--terminal-scrollbar')
|
|
->toContain('background: transparent;')
|
|
->toContain('color-mix(in srgb, var(--terminal-scrollbar');
|
|
});
|
|
|
|
it('lets the selected theme show through the active terminal panel', function () {
|
|
$appCss = file_get_contents(resource_path('css/app.css'));
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
|
|
expect($appCss)
|
|
->toMatch('/\.terminal-session-panel\s*\{[^}]*background:\s*transparent;/s')
|
|
->toMatch('/\.terminal-session-panel\s*\{[^}]*border:\s*0;/s')
|
|
->toMatch('/\.terminal-session-panel\s*\{[^}]*box-shadow:\s*none;/s')
|
|
->not->toContain('.application-console-block::before')
|
|
->not->toMatch('/\.application-console-block\s*\{[^}]*\bbackdrop-filter\s*:/s')
|
|
->and($terminalView)
|
|
->toContain('items-center justify-center bg-transparent')
|
|
->not->toContain('items-center justify-center bg-black/35');
|
|
});
|
|
|
|
it('keeps the terminal in the Livewire tree and unlocks ancestor stacking for fullscreen', function () {
|
|
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
$appCss = file_get_contents(resource_path('css/app.css'));
|
|
|
|
expect($terminalClient)
|
|
->toContain('enterFullscreen()')
|
|
->toContain('exitFullscreen()')
|
|
->toContain('patchAncestorsForFullscreen(wrapper)')
|
|
->toContain('restoreAncestorsAfterFullscreen()')
|
|
->toContain('salvageStrayFullscreenNodes()')
|
|
->toContain("node.style.setProperty('isolation', 'auto', 'important')")
|
|
->toContain("node.style.setProperty('transform', 'none', 'important')")
|
|
->toContain("node.style.setProperty('z-index', 'auto', 'important')")
|
|
->toContain("main.style.setProperty('z-index', '100001', 'important')")
|
|
->toContain("fromEl.closest('main')")
|
|
->toContain('scheduleTerminalResize()')
|
|
->not->toContain('document.body.appendChild(wrapper)')
|
|
->not->toContain('enterFullscreenPortal')
|
|
->and($terminalView)
|
|
->toContain('wire:ignore')
|
|
->toContain('terminal-fullscreen-shell fixed inset-0')
|
|
->and($appCss)
|
|
->toContain('body.terminal-is-fullscreen .terminal-fullscreen-shell')
|
|
->toContain('z-index: 100000 !important');
|
|
});
|
|
|
|
it('locks page scroll while the terminal is fullscreen and unlocks on exit', function () {
|
|
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
|
$appCss = file_get_contents(resource_path('css/app.css'));
|
|
|
|
expect($terminalClient)
|
|
->toContain('lockPageScroll()')
|
|
->toContain('unlockPageScroll()')
|
|
->toContain("document.body.style.setProperty('position', 'fixed', 'important')")
|
|
->toContain("window.addEventListener('wheel', this.preventPageScrollHandler")
|
|
->toContain("window.addEventListener('touchmove', this.preventPageScrollHandler")
|
|
->toContain("target.closest('.xterm-viewport')")
|
|
->toContain("document.documentElement.classList.add('terminal-is-fullscreen')")
|
|
->toContain("document.documentElement.classList.remove('terminal-is-fullscreen')")
|
|
->and($appCss)
|
|
->toContain('html.terminal-is-fullscreen')
|
|
->toContain('overscroll-behavior: none !important')
|
|
->toContain('touch-action: none');
|
|
});
|
|
|
|
it('applies the selected console theme to the fullscreen shell', function () {
|
|
$terminalView = file_get_contents(resource_path('views/livewire/project/shared/terminal.blade.php'));
|
|
$appCss = file_get_contents(resource_path('css/app.css'));
|
|
|
|
expect($terminalView)
|
|
->toContain('terminal-fullscreen-shell')
|
|
->toContain(':data-console-theme="fullscreen ? selectedTheme : null"')
|
|
->not->toContain('bg-[#141414]')
|
|
->and($appCss)
|
|
->toContain('.terminal-fullscreen-shell')
|
|
->toContain('.terminal-fullscreen-shell[data-console-theme="shadows-cosmic-purple"]')
|
|
->toContain('#terminal.terminal-host .xterm-viewport');
|
|
});
|
|
|
|
it('fits the terminal with FitAddon and keeps xterm within the host after resize', function () {
|
|
$terminalClient = file_get_contents(resource_path('js/terminal.js'));
|
|
|
|
expect($terminalClient)
|
|
->toContain('this.fitAddon.fit()')
|
|
->toContain("this.term.element.style.maxHeight = '100%'")
|
|
->toContain('scrollback: 5000')
|
|
->not->toContain('Math.floor(height / charSize.height) - 1');
|
|
});
|