Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/src/stories/RemoteControlSection.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ export const SetupPhoneQr: Story = {
// The one setup-panel story that settles on the QR's accessible name rather
// than on text, so it cannot use {@link setupPanel}.
play: async (context) => {
// The QR is a lazily-imported chunk. Fetched cold after the click, it can
// outlast `findByRole`'s 1 s on a loaded WebKit runner; loaded here first,
// the panel's own import resolves from the module cache.
await import('../components/QrCode');
const canvas = within(context.canvasElement);
await userEvent.click(await canvas.findByRole('button', { name: 'Set up a phone' }));
await canvas.findByRole('img', { name: 'Setup code for this machine' });
Expand Down
5 changes: 2 additions & 3 deletions lib/src/stories/TerminalPaneHeader.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { flattenScenario, SCENARIO_SHELL_PROMPT } from '../lib/platform';
import { removeMouseSelectionState, setMouseReporting, setOverride } from '../lib/mouse-selection';
import { addPlainNote, clearAllNotepads } from '../lib/notepad/notepad-store';
import { recordToolDirty, resetToolDirty } from '../lib/tool-dirty-store';
import { requireElement, settleTerminals, waitForCondition, waitForPrimedState } from './settle-terminals';
import { requireElement, settleTerminalContext, waitForCondition, waitForPrimedState } from './settle-terminals';

const SESSION_ID = 'tab-story';

Expand Down Expand Up @@ -230,8 +230,7 @@ async function openHeaderRightClickDialog() {
clientX: rect.left + rect.width / 2,
clientY: rect.top + rect.height / 2,
}));
await requireElement('[data-terminal-context]', 'terminal context');
await settleTerminals();
await settleTerminalContext();
}

/**
Expand Down
12 changes: 3 additions & 9 deletions lib/src/stories/Wall.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
SCENARIO_LS_OUTPUT,
} from '../lib/platform';
import type { ActivityState } from '../lib/terminal-registry';
import { requireElement, settleTerminals, waitForCondition } from './settle-terminals';
import { requireElement, settleTerminalContext, settleTerminals, waitForCondition } from './settle-terminals';

const meta: Meta<typeof Wall> = {
title: 'App/Wall',
Expand Down Expand Up @@ -101,8 +101,7 @@ async function minimizeFirstVisiblePane() {
async function openAlertDialog() {
const header = await requireElement<HTMLElement>('[data-pane-header-for]', 'pane header');
header.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true, button: 2 }));
await requireElement('[data-terminal-context]', 'terminal context');
await settleTerminals();
await settleTerminalContext();
}

export const Default: Story = {
Expand Down Expand Up @@ -219,11 +218,6 @@ export const TerminalContext: Story = {
await settleTerminals();
const header = await requireElement('[data-pane-header-for="context-live"]', 'terminal header');
header.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true, button: 2 }));
await waitForCondition(() => !!document.querySelector('[data-helper-terminal]'));
// Hold until autorun has finished and the helper has painted, so the capture
// is never the "Waiting for shell…" or "Running …" frame on the way there.
await waitForCondition(() =>
document.querySelector('[aria-label="Helper terminal status"]')?.textContent?.includes('autoran') ?? false);
await settleTerminals();
await settleTerminalContext();
},
};
18 changes: 18 additions & 0 deletions lib/src/stories/settle-terminals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ export async function settleTerminals(opts?: { timeoutMs?: number }): Promise<vo
}
}

/**
* Hold until an open terminal context has settled: its helper's autorun has
* finished (the status row's spinner is gone) and every terminal, the helper's
* included, has painted. The helper steps through "Waiting for shell…" and
* "Running …" on timers, so a capture without this lands on whichever step a
* loaded runner happened to reach.
*/
export async function settleTerminalContext(opts?: { timeoutMs?: number }): Promise<void> {
await requireElement('[data-terminal-context]', 'terminal context');
const settled = () => {
const status = document.querySelector('[data-terminal-context] [aria-label$="terminal status"]');
return !!status && !status.querySelector('.animate-spin');
};
await waitForCondition(settled, opts);
if (!settled()) throw new Error('terminal context autorun never finished');
await settleTerminals(opts);
}

/**
* Hold until the preview's primed-state decorator has applied.
*
Expand Down
Loading