reigncode-app 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +30 -0
- package/Dockerfile +21 -0
- package/README.md +51 -0
- package/bunfig.toml +3 -0
- package/create-effect-simplification-spec.md +515 -0
- package/e2e/AGENTS.md +226 -0
- package/e2e/actions.ts +1018 -0
- package/e2e/app/home.spec.ts +24 -0
- package/e2e/app/navigation.spec.ts +10 -0
- package/e2e/app/palette.spec.ts +20 -0
- package/e2e/app/server-default.spec.ts +58 -0
- package/e2e/app/session.spec.ts +16 -0
- package/e2e/app/titlebar-history.spec.ts +120 -0
- package/e2e/commands/input-focus.spec.ts +15 -0
- package/e2e/commands/panels.spec.ts +33 -0
- package/e2e/commands/tab-close.spec.ts +32 -0
- package/e2e/files/file-open.spec.ts +31 -0
- package/e2e/files/file-tree.spec.ts +56 -0
- package/e2e/files/file-viewer.spec.ts +156 -0
- package/e2e/fixtures.ts +154 -0
- package/e2e/models/model-picker.spec.ts +48 -0
- package/e2e/models/models-visibility.spec.ts +61 -0
- package/e2e/projects/project-edit.spec.ts +43 -0
- package/e2e/projects/projects-close.spec.ts +54 -0
- package/e2e/projects/projects-switch.spec.ts +116 -0
- package/e2e/projects/workspace-new-session.spec.ts +94 -0
- package/e2e/projects/workspaces.spec.ts +375 -0
- package/e2e/prompt/context.spec.ts +95 -0
- package/e2e/prompt/prompt-async.spec.ts +76 -0
- package/e2e/prompt/prompt-drop-file-uri.spec.ts +22 -0
- package/e2e/prompt/prompt-drop-file.spec.ts +30 -0
- package/e2e/prompt/prompt-history.spec.ts +184 -0
- package/e2e/prompt/prompt-mention.spec.ts +26 -0
- package/e2e/prompt/prompt-multiline.spec.ts +24 -0
- package/e2e/prompt/prompt-shell.spec.ts +62 -0
- package/e2e/prompt/prompt-slash-open.spec.ts +22 -0
- package/e2e/prompt/prompt-slash-share.spec.ts +64 -0
- package/e2e/prompt/prompt-slash-terminal.spec.ts +18 -0
- package/e2e/prompt/prompt.spec.ts +55 -0
- package/e2e/selectors.ts +75 -0
- package/e2e/session/session-child-navigation.spec.ts +37 -0
- package/e2e/session/session-composer-dock.spec.ts +530 -0
- package/e2e/session/session-model-persistence.spec.ts +359 -0
- package/e2e/session/session-review.spec.ts +426 -0
- package/e2e/session/session-undo-redo.spec.ts +233 -0
- package/e2e/session/session.spec.ts +174 -0
- package/e2e/settings/settings-keybinds.spec.ts +389 -0
- package/e2e/settings/settings-models.spec.ts +122 -0
- package/e2e/settings/settings-providers.spec.ts +136 -0
- package/e2e/settings/settings.spec.ts +519 -0
- package/e2e/sidebar/sidebar-popover-actions.spec.ts +118 -0
- package/e2e/sidebar/sidebar-session-links.spec.ts +30 -0
- package/e2e/sidebar/sidebar.spec.ts +40 -0
- package/e2e/status/status-popover.spec.ts +94 -0
- package/e2e/terminal/terminal-init.spec.ts +28 -0
- package/e2e/terminal/terminal-reconnect.spec.ts +46 -0
- package/e2e/terminal/terminal-tabs.spec.ts +168 -0
- package/e2e/terminal/terminal.spec.ts +18 -0
- package/e2e/thinking-level.spec.ts +25 -0
- package/e2e/tsconfig.json +9 -0
- package/e2e/utils.ts +63 -0
- package/happydom.ts +75 -0
- package/index.html +23 -0
- package/package.json +77 -0
- package/playwright.config.ts +45 -0
- package/public/_headers +17 -0
- package/public/oc-theme-preload.js +35 -0
- package/script/e2e-local.ts +180 -0
- package/src/addons/serialize.test.ts +319 -0
- package/src/addons/serialize.ts +634 -0
- package/src/app.tsx +308 -0
- package/src/components/debug-bar.tsx +443 -0
- package/src/components/dialog-connect-provider.tsx +617 -0
- package/src/components/dialog-custom-provider-form.ts +158 -0
- package/src/components/dialog-custom-provider.test.ts +80 -0
- package/src/components/dialog-custom-provider.tsx +329 -0
- package/src/components/dialog-edit-project.tsx +255 -0
- package/src/components/dialog-fork.tsx +108 -0
- package/src/components/dialog-manage-models.tsx +101 -0
- package/src/components/dialog-release-notes.tsx +144 -0
- package/src/components/dialog-select-directory.tsx +392 -0
- package/src/components/dialog-select-file.tsx +466 -0
- package/src/components/dialog-select-mcp.tsx +107 -0
- package/src/components/dialog-select-model-unpaid.tsx +137 -0
- package/src/components/dialog-select-model.tsx +220 -0
- package/src/components/dialog-select-provider.tsx +86 -0
- package/src/components/dialog-select-server.tsx +649 -0
- package/src/components/dialog-settings.tsx +73 -0
- package/src/components/file-tree.test.ts +78 -0
- package/src/components/file-tree.tsx +507 -0
- package/src/components/link.tsx +26 -0
- package/src/components/model-tooltip.tsx +91 -0
- package/src/components/prompt-input/attachments.test.ts +44 -0
- package/src/components/prompt-input/attachments.ts +201 -0
- package/src/components/prompt-input/build-request-parts.test.ts +312 -0
- package/src/components/prompt-input/build-request-parts.ts +175 -0
- package/src/components/prompt-input/context-items.tsx +88 -0
- package/src/components/prompt-input/drag-overlay.tsx +25 -0
- package/src/components/prompt-input/editor-dom.test.ts +99 -0
- package/src/components/prompt-input/editor-dom.ts +148 -0
- package/src/components/prompt-input/files.ts +66 -0
- package/src/components/prompt-input/history.test.ts +153 -0
- package/src/components/prompt-input/history.ts +256 -0
- package/src/components/prompt-input/image-attachments.tsx +58 -0
- package/src/components/prompt-input/paste.ts +24 -0
- package/src/components/prompt-input/placeholder.test.ts +48 -0
- package/src/components/prompt-input/placeholder.ts +15 -0
- package/src/components/prompt-input/slash-popover.tsx +141 -0
- package/src/components/prompt-input/submit.test.ts +346 -0
- package/src/components/prompt-input/submit.ts +579 -0
- package/src/components/prompt-input.tsx +1595 -0
- package/src/components/server/server-row.tsx +130 -0
- package/src/components/session/index.ts +5 -0
- package/src/components/session/session-context-breakdown.test.ts +61 -0
- package/src/components/session/session-context-breakdown.ts +132 -0
- package/src/components/session/session-context-format.ts +20 -0
- package/src/components/session/session-context-metrics.test.ts +101 -0
- package/src/components/session/session-context-metrics.ts +82 -0
- package/src/components/session/session-context-tab.tsx +339 -0
- package/src/components/session/session-header.tsx +486 -0
- package/src/components/session/session-new-view.tsx +91 -0
- package/src/components/session/session-sortable-tab.tsx +70 -0
- package/src/components/session/session-sortable-terminal-tab.tsx +193 -0
- package/src/components/session-context-usage.tsx +122 -0
- package/src/components/settings-general.tsx +585 -0
- package/src/components/settings-keybinds.tsx +453 -0
- package/src/components/settings-list.tsx +5 -0
- package/src/components/settings-models.tsx +137 -0
- package/src/components/settings-providers.tsx +251 -0
- package/src/components/status-popover.tsx +419 -0
- package/src/components/terminal.tsx +653 -0
- package/src/components/titlebar-history.test.ts +63 -0
- package/src/components/titlebar-history.ts +57 -0
- package/src/components/titlebar.tsx +312 -0
- package/src/constants/file-picker.ts +89 -0
- package/src/context/command-keybind.test.ts +69 -0
- package/src/context/command.test.ts +25 -0
- package/src/context/command.tsx +437 -0
- package/src/context/comments.test.ts +186 -0
- package/src/context/comments.tsx +243 -0
- package/src/context/file/content-cache.ts +88 -0
- package/src/context/file/path.test.ts +360 -0
- package/src/context/file/path.ts +151 -0
- package/src/context/file/tree-store.ts +170 -0
- package/src/context/file/types.ts +41 -0
- package/src/context/file/view-cache.ts +146 -0
- package/src/context/file/watcher.test.ts +149 -0
- package/src/context/file/watcher.ts +53 -0
- package/src/context/file-content-eviction-accounting.test.ts +65 -0
- package/src/context/file.tsx +280 -0
- package/src/context/global-sdk.tsx +232 -0
- package/src/context/global-sync/bootstrap.ts +206 -0
- package/src/context/global-sync/child-store.test.ts +38 -0
- package/src/context/global-sync/child-store.ts +281 -0
- package/src/context/global-sync/event-reducer.test.ts +552 -0
- package/src/context/global-sync/event-reducer.ts +359 -0
- package/src/context/global-sync/eviction.ts +28 -0
- package/src/context/global-sync/queue.ts +83 -0
- package/src/context/global-sync/session-cache.test.ts +102 -0
- package/src/context/global-sync/session-cache.ts +62 -0
- package/src/context/global-sync/session-load.ts +25 -0
- package/src/context/global-sync/session-prefetch.test.ts +96 -0
- package/src/context/global-sync/session-prefetch.ts +100 -0
- package/src/context/global-sync/session-trim.test.ts +59 -0
- package/src/context/global-sync/session-trim.ts +56 -0
- package/src/context/global-sync/types.ts +133 -0
- package/src/context/global-sync/utils.ts +25 -0
- package/src/context/global-sync.test.ts +122 -0
- package/src/context/global-sync.tsx +408 -0
- package/src/context/highlights.tsx +233 -0
- package/src/context/language.tsx +248 -0
- package/src/context/layout-scroll.test.ts +64 -0
- package/src/context/layout-scroll.ts +126 -0
- package/src/context/layout.test.ts +69 -0
- package/src/context/layout.tsx +937 -0
- package/src/context/local.tsx +422 -0
- package/src/context/model-variant.test.ts +86 -0
- package/src/context/model-variant.ts +52 -0
- package/src/context/models.tsx +163 -0
- package/src/context/notification.tsx +373 -0
- package/src/context/permission-auto-respond.test.ts +102 -0
- package/src/context/permission-auto-respond.ts +51 -0
- package/src/context/permission.tsx +277 -0
- package/src/context/platform.tsx +99 -0
- package/src/context/prompt.tsx +297 -0
- package/src/context/sdk.tsx +49 -0
- package/src/context/server.tsx +295 -0
- package/src/context/settings.tsx +241 -0
- package/src/context/sync-optimistic.test.ts +123 -0
- package/src/context/sync.tsx +618 -0
- package/src/context/terminal-title.ts +51 -0
- package/src/context/terminal.test.ts +82 -0
- package/src/context/terminal.tsx +437 -0
- package/src/entry.tsx +144 -0
- package/src/env.d.ts +18 -0
- package/src/hooks/use-providers.ts +44 -0
- package/src/i18n/ar.ts +855 -0
- package/src/i18n/br.ts +867 -0
- package/src/i18n/bs.ts +943 -0
- package/src/i18n/da.ts +937 -0
- package/src/i18n/de.ts +879 -0
- package/src/i18n/en.ts +948 -0
- package/src/i18n/es.ts +950 -0
- package/src/i18n/fr.ts +878 -0
- package/src/i18n/ja.ts +861 -0
- package/src/i18n/ko.ts +860 -0
- package/src/i18n/no.ts +944 -0
- package/src/i18n/parity.test.ts +32 -0
- package/src/i18n/pl.ts +865 -0
- package/src/i18n/ru.ts +946 -0
- package/src/i18n/th.ts +933 -0
- package/src/i18n/tr.ts +952 -0
- package/src/i18n/zh.ts +930 -0
- package/src/i18n/zht.ts +925 -0
- package/src/index.css +29 -0
- package/src/index.ts +6 -0
- package/src/pages/directory-layout.tsx +88 -0
- package/src/pages/error.tsx +327 -0
- package/src/pages/home.tsx +131 -0
- package/src/pages/layout/deep-links.ts +50 -0
- package/src/pages/layout/helpers.test.ts +211 -0
- package/src/pages/layout/helpers.ts +98 -0
- package/src/pages/layout/inline-editor.tsx +126 -0
- package/src/pages/layout/sidebar-items.tsx +437 -0
- package/src/pages/layout/sidebar-project.tsx +384 -0
- package/src/pages/layout/sidebar-shell.tsx +125 -0
- package/src/pages/layout/sidebar-workspace.tsx +504 -0
- package/src/pages/layout.tsx +2509 -0
- package/src/pages/session/composer/index.ts +2 -0
- package/src/pages/session/composer/session-composer-region.tsx +255 -0
- package/src/pages/session/composer/session-composer-state.test.ts +128 -0
- package/src/pages/session/composer/session-composer-state.ts +249 -0
- package/src/pages/session/composer/session-followup-dock.tsx +109 -0
- package/src/pages/session/composer/session-permission-dock.tsx +74 -0
- package/src/pages/session/composer/session-question-dock.tsx +449 -0
- package/src/pages/session/composer/session-request-tree.ts +52 -0
- package/src/pages/session/composer/session-revert-dock.tsx +99 -0
- package/src/pages/session/composer/session-todo-dock.tsx +330 -0
- package/src/pages/session/file-tab-scroll.test.ts +40 -0
- package/src/pages/session/file-tab-scroll.ts +67 -0
- package/src/pages/session/file-tabs.tsx +456 -0
- package/src/pages/session/handoff.ts +36 -0
- package/src/pages/session/helpers.test.ts +181 -0
- package/src/pages/session/helpers.ts +198 -0
- package/src/pages/session/message-gesture.test.ts +62 -0
- package/src/pages/session/message-gesture.ts +21 -0
- package/src/pages/session/message-id-from-hash.ts +6 -0
- package/src/pages/session/message-timeline.tsx +1013 -0
- package/src/pages/session/review-tab.tsx +170 -0
- package/src/pages/session/session-layout.ts +20 -0
- package/src/pages/session/session-model-helpers.test.ts +51 -0
- package/src/pages/session/session-model-helpers.ts +16 -0
- package/src/pages/session/session-side-panel.tsx +453 -0
- package/src/pages/session/terminal-label.ts +16 -0
- package/src/pages/session/terminal-panel.test.ts +25 -0
- package/src/pages/session/terminal-panel.tsx +326 -0
- package/src/pages/session/use-session-commands.tsx +495 -0
- package/src/pages/session/use-session-hash-scroll.test.ts +16 -0
- package/src/pages/session/use-session-hash-scroll.ts +197 -0
- package/src/pages/session.tsx +1841 -0
- package/src/sst-env.d.ts +12 -0
- package/src/testing/model-selection.ts +80 -0
- package/src/testing/prompt.ts +56 -0
- package/src/testing/session-composer.ts +84 -0
- package/src/testing/terminal.ts +118 -0
- package/src/theme-preload.test.ts +46 -0
- package/src/utils/agent.ts +23 -0
- package/src/utils/aim.ts +138 -0
- package/src/utils/base64.ts +10 -0
- package/src/utils/comment-note.ts +88 -0
- package/src/utils/id.ts +99 -0
- package/src/utils/notification-click.test.ts +27 -0
- package/src/utils/notification-click.ts +13 -0
- package/src/utils/persist.test.ts +115 -0
- package/src/utils/persist.ts +476 -0
- package/src/utils/prompt.test.ts +44 -0
- package/src/utils/prompt.ts +203 -0
- package/src/utils/runtime-adapters.test.ts +62 -0
- package/src/utils/runtime-adapters.ts +39 -0
- package/src/utils/same.ts +6 -0
- package/src/utils/scoped-cache.test.ts +69 -0
- package/src/utils/scoped-cache.ts +104 -0
- package/src/utils/server-errors.test.ts +131 -0
- package/src/utils/server-errors.ts +80 -0
- package/src/utils/server-health.test.ts +123 -0
- package/src/utils/server-health.ts +91 -0
- package/src/utils/server.ts +22 -0
- package/src/utils/solid-dnd.tsx +49 -0
- package/src/utils/sound.ts +117 -0
- package/src/utils/terminal-writer.test.ts +64 -0
- package/src/utils/terminal-writer.ts +65 -0
- package/src/utils/time.ts +22 -0
- package/src/utils/uuid.test.ts +78 -0
- package/src/utils/uuid.ts +12 -0
- package/src/utils/worktree.test.ts +46 -0
- package/src/utils/worktree.ts +73 -0
- package/sst-env.d.ts +10 -0
- package/tsconfig.json +26 -0
- package/vite.config.ts +15 -0
- package/vite.js +26 -0
package/e2e/AGENTS.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# E2E Testing Guide
|
|
2
|
+
|
|
3
|
+
## Build/Lint/Test Commands
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Run all e2e tests
|
|
7
|
+
bun test:e2e
|
|
8
|
+
|
|
9
|
+
# Run specific test file
|
|
10
|
+
bun test:e2e -- app/home.spec.ts
|
|
11
|
+
|
|
12
|
+
# Run single test by title
|
|
13
|
+
bun test:e2e -- -g "home renders and shows core entrypoints"
|
|
14
|
+
|
|
15
|
+
# Run tests with UI mode (for debugging)
|
|
16
|
+
bun test:e2e:ui
|
|
17
|
+
|
|
18
|
+
# Run tests locally with full server setup
|
|
19
|
+
bun test:e2e:local
|
|
20
|
+
|
|
21
|
+
# View test report
|
|
22
|
+
bun test:e2e:report
|
|
23
|
+
|
|
24
|
+
# Typecheck
|
|
25
|
+
bun typecheck
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Test Structure
|
|
29
|
+
|
|
30
|
+
All tests live in `packages/app/e2e/`:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
e2e/
|
|
34
|
+
├── fixtures.ts # Test fixtures (test, expect, gotoSession, sdk)
|
|
35
|
+
├── actions.ts # Reusable action helpers
|
|
36
|
+
├── selectors.ts # DOM selectors
|
|
37
|
+
├── utils.ts # Utilities (serverUrl, modKey, path helpers)
|
|
38
|
+
└── [feature]/
|
|
39
|
+
└── *.spec.ts # Test files
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Test Patterns
|
|
43
|
+
|
|
44
|
+
### Basic Test Structure
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { test, expect } from "../fixtures"
|
|
48
|
+
import { promptSelector } from "../selectors"
|
|
49
|
+
import { withSession } from "../actions"
|
|
50
|
+
|
|
51
|
+
test("test description", async ({ page, sdk, gotoSession }) => {
|
|
52
|
+
await gotoSession() // or gotoSession(sessionID)
|
|
53
|
+
|
|
54
|
+
// Your test code
|
|
55
|
+
await expect(page.locator(promptSelector)).toBeVisible()
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Using Fixtures
|
|
60
|
+
|
|
61
|
+
- `page` - Playwright page
|
|
62
|
+
- `sdk` - OpenCode SDK client for API calls
|
|
63
|
+
- `gotoSession(sessionID?)` - Navigate to session
|
|
64
|
+
|
|
65
|
+
### Helper Functions
|
|
66
|
+
|
|
67
|
+
**Actions** (`actions.ts`):
|
|
68
|
+
|
|
69
|
+
- `openPalette(page)` - Open command palette
|
|
70
|
+
- `openSettings(page)` - Open settings dialog
|
|
71
|
+
- `closeDialog(page, dialog)` - Close any dialog
|
|
72
|
+
- `openSidebar(page)` / `closeSidebar(page)` - Toggle sidebar
|
|
73
|
+
- `waitTerminalReady(page, { term? })` - Wait for a mounted terminal to connect and finish rendering output
|
|
74
|
+
- `runTerminal(page, { cmd, token, term?, timeout? })` - Type into the terminal via the browser and wait for rendered output
|
|
75
|
+
- `withSession(sdk, title, callback)` - Create temp session
|
|
76
|
+
- `withProject(...)` - Create temp project/workspace
|
|
77
|
+
- `sessionIDFromUrl(url)` - Read session ID from URL
|
|
78
|
+
- `slugFromUrl(url)` - Read workspace slug from URL
|
|
79
|
+
- `waitSlug(page, skip?)` - Wait for resolved workspace slug
|
|
80
|
+
- `trackSession(sessionID, directory?)` - Register session for fixture cleanup
|
|
81
|
+
- `trackDirectory(directory)` - Register directory for fixture cleanup
|
|
82
|
+
- `clickListItem(container, filter)` - Click list item by key/text
|
|
83
|
+
|
|
84
|
+
**Selectors** (`selectors.ts`):
|
|
85
|
+
|
|
86
|
+
- `promptSelector` - Prompt input
|
|
87
|
+
- `terminalSelector` - Terminal panel
|
|
88
|
+
- `sessionItemSelector(id)` - Session in sidebar
|
|
89
|
+
- `listItemSelector` - Generic list items
|
|
90
|
+
|
|
91
|
+
**Utils** (`utils.ts`):
|
|
92
|
+
|
|
93
|
+
- `modKey` - Meta (Mac) or Control (Linux/Win)
|
|
94
|
+
- `serverUrl` - Backend server URL
|
|
95
|
+
- `sessionPath(dir, id?)` - Build session URL
|
|
96
|
+
|
|
97
|
+
## Code Style Guidelines
|
|
98
|
+
|
|
99
|
+
### Imports
|
|
100
|
+
|
|
101
|
+
Always import from `../fixtures`, not `@playwright/test`:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// ✅ Good
|
|
105
|
+
import { test, expect } from "../fixtures"
|
|
106
|
+
|
|
107
|
+
// ❌ Bad
|
|
108
|
+
import { test, expect } from "@playwright/test"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Naming Conventions
|
|
112
|
+
|
|
113
|
+
- Test files: `feature-name.spec.ts`
|
|
114
|
+
- Test names: lowercase, descriptive: `"sidebar can be toggled"`
|
|
115
|
+
- Variables: camelCase
|
|
116
|
+
- Constants: SCREAMING_SNAKE_CASE
|
|
117
|
+
|
|
118
|
+
### Error Handling
|
|
119
|
+
|
|
120
|
+
Tests should clean up after themselves. Prefer fixture-managed cleanup:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
test("test with cleanup", async ({ page, sdk, gotoSession }) => {
|
|
124
|
+
await withSession(sdk, "test session", async (session) => {
|
|
125
|
+
await gotoSession(session.id)
|
|
126
|
+
// Test code...
|
|
127
|
+
}) // Auto-deletes session
|
|
128
|
+
})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- Prefer `withSession(...)` for temp sessions
|
|
132
|
+
- In `withProject(...)` tests that create sessions or extra workspaces, call `trackSession(sessionID, directory?)` and `trackDirectory(directory)`
|
|
133
|
+
- This lets fixture teardown abort, wait for idle, and clean up safely under CI concurrency
|
|
134
|
+
- Avoid calling `sdk.session.delete(...)` directly
|
|
135
|
+
|
|
136
|
+
### Timeouts
|
|
137
|
+
|
|
138
|
+
Default: 60s per test, 10s per assertion. Override when needed:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
test.setTimeout(120_000) // For long LLM operations
|
|
142
|
+
test("slow test", async () => {
|
|
143
|
+
await expect.poll(() => check(), { timeout: 90_000 }).toBe(true)
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Selectors
|
|
148
|
+
|
|
149
|
+
Use `data-component`, `data-action`, or semantic roles:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// ✅ Good
|
|
153
|
+
await page.locator('[data-component="prompt-input"]').click()
|
|
154
|
+
await page.getByRole("button", { name: "Open settings" }).click()
|
|
155
|
+
|
|
156
|
+
// ❌ Bad
|
|
157
|
+
await page.locator(".css-class-name").click()
|
|
158
|
+
await page.locator("#id-name").click()
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Keyboard Shortcuts
|
|
162
|
+
|
|
163
|
+
Use `modKey` for cross-platform compatibility:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { modKey } from "../utils"
|
|
167
|
+
|
|
168
|
+
await page.keyboard.press(`${modKey}+B`) // Toggle sidebar
|
|
169
|
+
await page.keyboard.press(`${modKey}+Comma`) // Open settings
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Terminal Tests
|
|
173
|
+
|
|
174
|
+
- In terminal tests, type through the browser. Do not write to the PTY through the SDK.
|
|
175
|
+
- Use `waitTerminalReady(page, { term? })` and `runTerminal(page, { cmd, token, term?, timeout? })` from `actions.ts`.
|
|
176
|
+
- These helpers use the fixture-enabled test-only terminal driver and wait for output after the terminal writer settles.
|
|
177
|
+
- After opening the terminal, use `waitTerminalFocusIdle(...)` before the next keyboard action when prompt focus or keyboard routing matters.
|
|
178
|
+
- This avoids racing terminal mount, focus handoff, and prompt readiness when the next step types or sends shortcuts.
|
|
179
|
+
- Avoid `waitForTimeout` and custom DOM or `data-*` readiness checks.
|
|
180
|
+
|
|
181
|
+
### Wait on state
|
|
182
|
+
|
|
183
|
+
- Never use wall-clock waits like `page.waitForTimeout(...)` to make a test pass
|
|
184
|
+
- Avoid race-prone flows that assume work is finished after an action
|
|
185
|
+
- Wait or poll on observable state with `expect(...)`, `expect.poll(...)`, or existing helpers
|
|
186
|
+
- Prefer locator assertions like `toBeVisible()`, `toHaveCount(0)`, and `toHaveAttribute(...)` for normal UI state, and reserve `expect.poll(...)` for probe, mock, or backend state
|
|
187
|
+
- Prefer semantic app state over transient DOM visibility when behavior depends on active selection, focus ownership, or async retry loops
|
|
188
|
+
- Do not treat a visible element as proof that the app will route the next action to it
|
|
189
|
+
- When fixing a flake, validate with `--repeat-each` and multiple workers when practical
|
|
190
|
+
|
|
191
|
+
### Add hooks
|
|
192
|
+
|
|
193
|
+
- If required state is not observable from the UI, add a small test-only driver or probe in app code instead of sleeps or fragile DOM checks
|
|
194
|
+
- Keep these hooks minimal and purpose-built, following the style of `packages/app/src/testing/terminal.ts`
|
|
195
|
+
- Test-only hooks must be inert unless explicitly enabled; do not add normal-runtime listeners, reactive subscriptions, or per-update allocations for e2e ceremony
|
|
196
|
+
- When mocking routes or APIs, expose explicit mock state and wait on that before asserting post-action UI
|
|
197
|
+
- Add minimal test-only probes for semantic state like the active list item or selected command when DOM intermediates are unstable
|
|
198
|
+
- Prefer probing committed app state over asserting on transient highlight, visibility, or animation states
|
|
199
|
+
|
|
200
|
+
### Prefer helpers
|
|
201
|
+
|
|
202
|
+
- Prefer fluent helpers and drivers when they make intent obvious and reduce locator-heavy noise
|
|
203
|
+
- Use direct locators when the interaction is simple and a helper would not add clarity
|
|
204
|
+
- Prefer helpers that both perform an action and verify the app consumed it
|
|
205
|
+
- Avoid composing helpers redundantly when one already includes the other or already waits for the resulting state
|
|
206
|
+
- If a helper already covers the required wait or verification, use it directly instead of layering extra clicks, keypresses, or assertions
|
|
207
|
+
|
|
208
|
+
## Writing New Tests
|
|
209
|
+
|
|
210
|
+
1. Choose appropriate folder or create new one
|
|
211
|
+
2. Import from `../fixtures`
|
|
212
|
+
3. Use helper functions from `../actions` and `../selectors`
|
|
213
|
+
4. When validating routing, use shared helpers from `../actions`. Workspace URL slugs can be canonicalized on Windows, so assert against canonical or resolved workspace slugs.
|
|
214
|
+
5. Clean up any created resources
|
|
215
|
+
6. Use specific selectors (avoid CSS classes)
|
|
216
|
+
7. Test one feature per test file
|
|
217
|
+
|
|
218
|
+
## Local Development
|
|
219
|
+
|
|
220
|
+
For UI debugging, use:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
bun test:e2e:ui
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
This opens Playwright's interactive UI for step-through debugging.
|