Files
buzz/desktop/playwright.config.ts
T
2c0ac24674 fix(desktop): stop the create-agent provider config probe from erasing keystrokes (#4411)
## What

Fixes the create-agent dialog's "Run on" provider config fields eating
keystrokes — reported by Tyler in buzz-remote-agents (channel
`29414326`, thread `db76677a`): the Kubernetes **Kubeconfig context**
field would not accept typing.

## Why it happened (the Typewriter Eraser, shipped in #4289)

`WhereToRunSection`'s probe `useEffect` depended on the whole `draft`:

1. every keystroke changed the draft → effect re-fired → provider binary
re-probed;
2. each probe result is a fresh object written into the draft → the
effect re-triggered **itself**, respawning the provider binary in a loop
for as long as the dialog sat on a provider;
3. every probe resolution reset `providerConfig` to schema defaults —
erasing whatever was typed. A field with no schema default (`context`)
snapped back to empty, i.e. "won't let me type". Unrelated to how many
kubeconfig contexts you have.

## Fix

- **Probe once per provider selection**, keyed on the provider's stable
`binaryPath` — not the draft, not the provider object (a
`useBackendProvidersQuery` refresh must not reprobe an unchanged
selection).
- **Latest-state resolution** via `React.useEffectEvent` + a new pure
`applyProbeResult` helper: schema defaults merge **beneath** the current
`providerConfig`, so a probe landing after the user typed can never
clobber in-flight input (per Wren's pre-patch red-team: changing deps
alone leaves a stale closure).

Existing `cancelled` cleanup keeps provider-switch/unmount safe;
selection reset (`emptyWhereToRunDraft`) and the fail-closed probe-error
path are unchanged.

## Tests

- **Unit** (`whereToRunIntent.test.mjs`): `applyProbeResult` merge
semantics — defaults under typed values, user-cleared fields stay
cleared, schema-less results, unrelated fields preserved.
- **E2E** (new `where-to-run-config.spec.ts`, added to the smoke
project, **red-first verified**: all 3 fail against the unfixed
component):
- typing into a defaultless provider field sticks, and
`probe_backend_provider` fires exactly once per selection;
- the config form is gated on probe resolution (slow probe: no
half-rendered form, defaults prefill once);
  - provider → local → provider re-probes and resets cleanly.
- Mock bridge gains `backendProviders` / `backendProviderProbeResult` /
`backendProviderProbeDelayMs` seams (defaults preserve prior behavior).

## Verification at 8eb7680

- `pnpm check` + `tsc` clean, `pnpm test` 3926/3926;
- new spec 3/3 green (and 3/3 red on the unfixed component);
- pre-push lefthook: desktop-test, desktop-check, desktop-tauri-checks,
rust-tests, mobile-test all green.

---------

Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
2026-08-03 07:36:13 -04:00

177 lines
6.3 KiB
TypeScript

import { defineConfig, devices } from "@playwright/test";
export default defineConfig({
testDir: "./tests/e2e",
timeout: 30_000,
retries: process.env.CI ? 2 : 0,
workers: 1,
reporter: [
["list"],
["html", { open: "never", outputFolder: "playwright-report" }],
],
use: {
baseURL: "http://127.0.0.1:4173",
screenshot: "only-on-failure",
trace: "on-first-retry",
video: "retain-on-failure",
},
projects: [
{
name: "smoke",
testMatch: [
"**/smoke.spec.ts",
"**/onboarding-docked-cta-screenshots.spec.ts",
"**/identity-key-help.spec.ts",
"**/key-import-reveal.spec.ts",
"**/navigation.spec.ts",
"**/channels.spec.ts",
"**/channel-shared-header-backdrop.spec.ts",
"**/channel-composer-overflow.spec.ts",
"**/badge.spec.ts",
"**/channel-browser.spec.ts",
"**/channel-add-screenshots.spec.ts",
"**/add-community-screenshots.spec.ts",
"**/hosted-communities-settings-screenshots.spec.ts",
"**/invites-settings-screenshots.spec.ts",
"**/messaging.spec.ts",
"**/message-feedback-snapshots.spec.ts",
"**/custom-emoji.spec.ts",
"**/profile-custom-emoji-status.spec.ts",
"**/custom-emoji-ui.spec.ts",
"**/channel-mute.spec.ts",
"**/channel-star.spec.ts",
"**/channel-controls.spec.ts",
"**/active-turn-resilience.spec.ts",
"**/profile-active-turn.spec.ts",
"**/config-bridge-screenshots.spec.ts",
"**/observer-feed-screenshots.spec.ts",
"**/core-memory-screenshots.spec.ts",
"**/activity-scope-label-screenshots.spec.ts",
"**/welcome-agent-modal-screenshots.spec.ts",
"**/local-archive-screenshots.spec.ts",
"**/voice-settings.spec.ts",
"**/agent-readiness-screenshots.spec.ts",
"**/agent-error-state-screenshots.spec.ts",
"**/edit-agent.spec.ts",
"**/doctor-cta-screenshots.spec.ts",
"**/pubkey-display-screenshots.spec.ts",
"**/file-attachment.spec.ts",
"**/image-attachment-gallery.spec.ts",
"**/composer-image-draw.spec.ts",
"**/video-attachment.spec.ts",
"**/spoiler.spec.ts",
"**/composer-link-shortcut.spec.ts",
"**/composer-selection-formatting.spec.ts",
"**/composer-tooltip-dismiss.spec.ts",
"**/mentions.spec.ts",
"**/team-mentions.spec.ts",
"**/persistent-agent-audience.spec.ts",
"**/relay-reconnect.spec.ts",
"**/relay-reconnect-affordance.spec.ts",
"**/workflows.spec.ts",
"**/identity-archive.spec.ts",
"**/identity-archive-hide.spec.ts",
"**/relay-connectivity.spec.ts",
"**/unread-pill.spec.ts",
"**/sidebar-more-unread-overlap.spec.ts",
"**/home-collapsed-top-chrome.spec.ts",
"**/top-chrome-zoom-clearance.spec.ts",
"**/thread-unread.spec.ts",
"**/workspace-rail.spec.ts",
"**/community-rail.spec.ts",
"**/boot-splash.spec.ts",
"**/thread-reply-anchor-roleplay.spec.ts",
"**/threadpane-ultrawide.spec.ts",
"**/thread-focus-mode.spec.ts",
"**/animated-avatar.spec.ts",
"**/reminders.spec.ts",
"**/reminder-click-repro.spec.ts",
"**/virtualization.spec.ts",
"**/scroll-history.spec.ts",
"**/channel-dense-second-reach.spec.ts",
"**/channel-window-mock-paging.spec.ts",
"**/live-broadcast-reply-timeline.spec.ts",
"**/markdown-parse-cache.spec.ts",
"**/overscroll-boundary.spec.ts",
"**/cold-switch-longtask.perf.ts",
"**/timeline-no-shift.spec.ts",
"**/human-edit-agent-content.spec.ts",
"**/empty-edit-delete.spec.ts",
"**/reaction-order.spec.ts",
"**/reaction-names.spec.ts",
"**/inbox-reactions.spec.ts",
"**/send-channel-binding.spec.ts",
"**/project-commit-detail.spec.ts",
"**/project-inbox.spec.ts",
"**/project-pr-review.spec.ts",
"**/persona-model-combobox-screenshots.spec.ts",
"**/drafts-screenshots.spec.ts",
"**/drafts-all-fix-screenshots.spec.ts",
"**/inbox-refactor-screenshots.spec.ts",
"**/buzz-theme-screenshots.spec.ts",
"**/channel-sort.spec.ts",
"**/identity-lost.spec.ts",
"**/deep-link-invite.spec.ts",
"**/invite-link-copy.spec.ts",
"**/global-agent-config-screenshots.spec.ts",
"**/doctor-states.spec.ts",
"**/onboarding-avatar-skip.spec.ts",
"**/onboarding-backup.spec.ts",
"**/onboarding-agent-defaults.spec.ts",
"**/nostr-bind.spec.ts",
"**/mobile-pairing-qr.spec.ts",
"**/profile-nsec-reveal.spec.ts",
"**/profile-backup-settings.spec.ts",
"**/signout-confirmation.spec.ts",
"**/agent-provider-dropdowns.spec.ts",
"**/agent-lifecycle-feedback.spec.ts",
"**/agent-access-warning.spec.ts",
"**/inbox-live-update.spec.ts",
"**/mesh-compute.spec.ts",
"**/observer-archive-policy.spec.ts",
"**/harness-management.spec.ts",
"**/harness-catalog-screenshots.spec.ts",
"**/inline-custom-harness.spec.ts",
"**/where-to-run-config.spec.ts",
"**/huddle-transcription.spec.ts",
],
use: {
...devices["Desktop Chrome"],
},
},
{
name: "integration",
testMatch: [
"**/agents.spec.ts",
"**/agent-snapshot-recipient.spec.ts",
"**/onboarding.spec.ts",
"**/stream.spec.ts",
"**/integration.spec.ts",
"**/dm-double-notification.spec.ts",
"**/profile.spec.ts",
"**/sidebar.spec.ts",
"**/sidebar-relay-card.spec.ts",
"**/tokens.spec.ts",
"**/persona-env-vars.spec.ts",
"**/persona-sync.spec.ts",
"**/team-snapshot.spec.ts",
"**/agents-everywhere.live.spec.ts",
"**/relay-restart.live.spec.ts",
"**/parity-ancestor-island.spec.ts",
],
use: {
...devices["Desktop Chrome"],
},
expect: {
timeout: process.env.CI ? 15_000 : 10_000,
},
},
],
webServer: {
command: "python3 -m http.server 4173 -d dist",
cwd: ".",
reuseExistingServer: !process.env.CI,
url: "http://127.0.0.1:4173",
},
});