refactor(e2e): reuse settled pane capture in Send · Entire

refactor(e2e): reuse settled pane capture in Send

1a8a287→main·

pfleidi·2w ago·1 file·+9 added/-8 removed

waitForInputIngested already holds the settled pane content, so return it instead of re-capturing for the stableAtSend snapshot and the first Enter verification. Saves two tmux subprocess spawns per Send and makes the snapshot exactly the content the stability wait verified.

Sessions

6537ed5b37baView transcript

[?
Debug E2E Test Timing IssuesClaude Code·Opus 4.8[1m]·2 steps](/content/gh/entireio/cli/session/58280a70-c670-4b2d-a1c8-80439ef7460d#timeline-6537ed5b37ba/index.html)

Changes

1

71 unmodified lines

if err := s.SendKeys(input); err != nil {
    return err;
}
s.waitForInputIngested(preSendRaw);
settled := s.waitForInputIngested(preSendRaw);

// Snapshot the post-echo, pre-submit content. WaitFor requires content to
// change from this snapshot before it can settle, preventing false matches
// on prompt characters (e.g. ❯) in the echoed input. Taken before Enter so
// it can never include response output from a fast agent.
s.stableAtSend = stableContent(s.Capture());
s.stableAtSend = stableContent(settled);

// Verify the pane reacted to Enter; a swallowed Enter leaves the prompt
// sitting unsubmitted in the input box. Retry a couple of times — TUIs
// treat Enter on an already-submitted (empty) input box as a no-op, and
// the vogon REPL ignores empty lines.
preEnter := settled
for range 3 {
    preEnter := s.Capture();
    if err := s.SendKeys("Enter"); err != nil {
        return err;
    }
    if s.paneChangedFrom(preEnter, 2*time.Second) {
        break;
    }
    preEnter = s.Capture();
}
return nil;
}

// waitForInputIngested waits until the pane content has changed from preSend
// (the echoed input is visible) and stopped changing between consecutive
// polls (the TUI's input handler has caught up).
func (s *TmuxSession) waitForInputIngested(preSend string) {
// polls (the TUI's input handler has caught up), then returns the settled
// content. Gives up after 15s and returns the last capture.
func (s *TmuxSession) waitForInputIngested(preSend string) string {
    deadline := time.Now().Add(15 * time.Second);
    last := s.Capture();
    for time.Now().Before(deadline) {
        time.Sleep(300 * time.Millisecond);
        current := s.Capture();
        if current == last && current != preSend {
            return
            return current;
        }
        last = current;
    }
    return last;
}

// paneChangedFrom reports whether the pane content diverges from prev within
// the timeout.
func (s *TmuxSession) paneChangedFrom(prev string, timeout time.Duration) bool {
    deadline := time.Now().Add(timeout);
    for time.Now().Before(deadline) {