LibreChat/e2e
Danny Avila 8f712259ea
💬 refactor: Anchor In-Flight Steers Above the Composer (#14308)
* 💬 refactor: Anchor In-Flight Steers Above the Composer

Mid-run steers were rendered in-thread at the tail of the streaming
assistant message, at a guessed injection point, then swapped to the
persisted STEER part at its real index once the server applied them.

In-flight steers now render as message bubbles anchored above the
composer, so the thread only ever shows what the server committed:

- InFlightSteers: sending/pending steers as left-aligned bubbles with
  image previews and a cancel affordance, anchored above the composer box
- PendingSteerChips: unchanged, still owns the failed/queued control rows
- SteerPart: drops the pending/onCancel props, now only ever the
  server-applied part
- useSteerCancel: the optimistic cancel + restore-on-error, lifted out of
  the deleted PendingSteers slot

The steer state machine is untouched: the 202 ACK reconciliation,
reconnect reseeding, and queue conversion all key off status, not render
location.

* 🎨 fix: Match In-Flight Steer Presentation to the Applied Part

Codex review on 6a5f36f7ef. All three findings were real, and all three
were the same underlying mistake: the anchored bubble hand-rolled
presentation instead of reusing the leaves the applied SteerPart uses,
so a steer visibly changed on apply.

- Images: the message `Image` sets an inline height from the file's
  dimensions and centers with object-contain, so clipping it into a 56px
  wrapper showed the blank top of a large element. Use ImagePreview, the
  composer's fixed-size thumbnail path (also gives click-to-enlarge).
- Non-image files: FileContainer always renders a button, so without an
  onClick the chip was dead. Wire FilePreviewDialog, as SteerPart does.
- Markdown: honor enableUserMsgMarkdown so text does not reflow the
  moment the server injects it.

Splits files in a single pass rather than two filters.

* 🎨 style: Outline the In-Flight Steer Bubble and Move the Bolt Inline

The filled bubble read as a settled message. An outline reads as
provisional, which is what an in-flight steer is, and separates it from
the composer surface behind it.

- Border + bubble keeps the composer's rounded-3xl radius so it reads as
  anchored to the input rather than floating over it. Border stays
  NEUTRAL: the failed-steer row already owns a colored (red) border, so
  a colored outline on the happy path would read as a warning.
- The Zap moves inside the bubble, left of the text, where it prefixes
  the words as a status label instead of competing with cancel for the
  right edge. items-start pins it to the first line when text wraps.
- Cancel drops plain `opacity-0` for `[@media(hover:hover)]:opacity-0`,
  matching SteerPart's info affordance: a hover-revealed control is
  unreachable on touch until a first tap (the #14272 pattern).
2026-07-16 10:27:59 -04:00
..
config 🧵 feat: Background Tool Calls for Agents & Model Specs (#14197) 2026-07-13 12:51:36 -04:00
fixtures/deployment-skills/e2e-deployment-skill 🗂️ feat: Add Deployment Skill Directory (#13523) 2026-06-05 10:24:28 -04:00
recordings 🎭 feat: Add Credential-Free Playwright Smoke Suite with a Local Mock LLM (#13472) 2026-06-02 16:36:39 -04:00
setup 🧭 feat: Mid-Run Steering and Queued Messages for Agent Runs (#14220) 2026-07-14 10:11:10 -04:00
specs 💬 refactor: Anchor In-Flight Steers Above the Composer (#14308) 2026-07-16 10:27:59 -04:00
config.local.example.ts 🤲 feat(a11y): Initial a11y improvements, added linters, tests; fix: close sidebars in mobile view (#3536) 2024-08-04 20:39:52 -04:00
jestSetup.js v0.8.7 (#13907) 2026-06-24 14:49:32 -04:00
playwright.config.a11y.ts ⚖️ feat: Add Violation Scores (#8304) 2025-07-07 17:08:40 -04:00
playwright.config.local.ts 🛟 test: Restore Playwright Smoke E2E (#13020) 2026-05-14 09:49:26 -04:00
playwright.config.mock.ts 🔐 fix: Honor Admin-Panel MCP Allowlist Overrides Without Restart (#13814) 2026-06-17 20:14:53 -04:00
playwright.config.real.ts 📊 feat: Real-Time Context Window & Token Usage Tracking (#13670) 2026-06-13 19:38:28 -04:00
playwright.config.ts 🎭 feat: Add Credential-Free Playwright Smoke Suite with a Local Mock LLM (#13472) 2026-06-02 16:36:39 -04:00
README.md 🎭 test: Run Mock E2E Suite Through createRun With In-Process Fake Model (#13508) 2026-06-04 08:33:28 -04:00
types.ts 🤲 feat(a11y): Initial a11y improvements, added linters, tests; fix: close sidebars in mobile view (#3536) 2024-08-04 20:39:52 -04:00

LibreChat e2e

The mock e2e profile is the safest default for generated tests. It starts LibreChat with e2e/config/librechat.e2e.yaml, injects an in-process fake LLM (via LIBRECHAT_TEST_RUN_HOOK), creates an authenticated e2e user, and avoids real provider credentials.

Recording Tests

Use Playwright codegen when you want to turn an exploratory browser session into a draft test:

npm run e2e:record

That command builds the app, starts the LibreChat test server (with an in-process fake LLM) when needed, writes e2e/storageState.json, and opens Playwright codegen at /c/new. The npm script uses http://localhost:3333 so it does not collide with a normal dev server on 3080. Raw recordings are written to e2e/recordings/ and ignored by git.

For a real local LibreChat config instead of the mock profile:

npm run e2e:record:local

Useful direct options:

node e2e/setup/record.js --url=http://localhost:3080/c/new
node e2e/setup/record.js --profile=local --no-output
node e2e/setup/record.js --auth-only
node e2e/setup/record.js --output=e2e/recordings/settings-draft.spec.ts

LLM-Assisted Loop

  1. Start npm run e2e:record.
  2. Let the LLM use Computer Use to operate the headed Playwright browser.
  3. Stop codegen after the workflow is captured.
  4. Move the useful parts from e2e/recordings/ into a committed spec under e2e/specs/mock/.
  5. Replace brittle generated selectors with role, label, text, or data-testid locators.
  6. Add assertions that prove the behavior, not just the clicked path.
  7. Run the finished spec with npm run e2e:mock -- <spec name>.

Generated recordings are a draft, not the final test. The committed version should use the shared helpers in e2e/specs/mock/helpers.ts where possible, wait on network or visible UI state instead of fixed sleeps, and keep test data deterministic.