saeeol 1.4.0 → 1.4.1
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/package.json +1 -1
- package/src/server/routes/instance/httpapi/groups/ltm.ts +93 -0
- package/src/server/routes/instance/httpapi/handlers/ltm.ts +118 -0
- package/src/server/routes/instance/index.ts +96 -1
- package/test/smoke/.tui-input-report.txt +110 -0
- package/test/smoke/.tui-leader-report.txt +70 -0
- package/test/smoke/.tui-scroll-report.txt +66 -0
- package/test/smoke/.tui-slash-report.txt +146 -0
- package/test/smoke/.tui-system-report.txt +62 -0
- package/test/smoke/tui-walkthrough-driver.ts +232 -0
- package/test/smoke/tui-walkthrough-input.test.ts +286 -0
- package/test/smoke/tui-walkthrough-leader.test.ts +175 -0
- package/test/smoke/tui-walkthrough-scroll.test.ts +177 -0
- package/test/smoke/tui-walkthrough-slash.test.ts +302 -0
- package/test/smoke/tui-walkthrough-system.test.ts +210 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tui-walkthrough-slash.test.ts — 슬래시 명령어 전체 검증
|
|
3
|
+
*
|
|
4
|
+
* /help, /status, /models, /agents, /themes, /sessions, /new, /exit,
|
|
5
|
+
* /restart, /connect, /mcps, /mcp-refresh, /variants, /logs,
|
|
6
|
+
* /editor, /skills, /pointing, /timestamps, /thinking, /rename,
|
|
7
|
+
* /timeline, /fork, /compact, /copy, /export, /share, /unshare,
|
|
8
|
+
* /undo, /redo, /org, /quit, /q 등 전부.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, expect, test, beforeAll, afterAll } from "bun:test"
|
|
12
|
+
import { tmpdir, disposeAllInstances } from "../fixture/fixture"
|
|
13
|
+
import * as Log from "@saeeol/core/util/log"
|
|
14
|
+
import { Flag } from "@saeeol/core/flag/flag"
|
|
15
|
+
import { TuiDriver } from "./tui-walkthrough-driver"
|
|
16
|
+
|
|
17
|
+
void Log.init({ print: false })
|
|
18
|
+
|
|
19
|
+
describe("TUI walkthrough: slash commands", () => {
|
|
20
|
+
let driver: TuiDriver
|
|
21
|
+
let tmp: Awaited<ReturnType<typeof tmpdir>>
|
|
22
|
+
|
|
23
|
+
beforeAll(async () => {
|
|
24
|
+
tmp = await tmpdir({ git: true, config: {} })
|
|
25
|
+
Flag.SAEEOL_EXPERIMENTAL_HTTPAPI = false
|
|
26
|
+
driver = new TuiDriver(tmp.path)
|
|
27
|
+
await driver.wait(6000)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
afterAll(async () => {
|
|
31
|
+
await driver.saveReport(".tui-slash-report.txt")
|
|
32
|
+
await driver.kill()
|
|
33
|
+
await disposeAllInstances()
|
|
34
|
+
Flag.SAEEOL_EXPERIMENTAL_HTTPAPI = true
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// ── 시스템 슬래시 명령 ──
|
|
38
|
+
|
|
39
|
+
test("/help → help dialog", async () => {
|
|
40
|
+
await driver.slash("help")
|
|
41
|
+
driver.snapshot("slash-help")
|
|
42
|
+
expect(driver.errors()).toHaveLength(0)
|
|
43
|
+
await driver.dismiss()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test("/status → status dialog", async () => {
|
|
47
|
+
await driver.slash("status")
|
|
48
|
+
driver.snapshot("slash-status")
|
|
49
|
+
expect(driver.errors()).toHaveLength(0)
|
|
50
|
+
await driver.dismiss()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test("/themes → theme dialog", async () => {
|
|
54
|
+
await driver.slash("themes")
|
|
55
|
+
driver.snapshot("slash-themes")
|
|
56
|
+
expect(driver.errors()).toHaveLength(0)
|
|
57
|
+
await driver.dismiss()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test("/models → model dialog", async () => {
|
|
61
|
+
await driver.slash("models")
|
|
62
|
+
driver.snapshot("slash-models")
|
|
63
|
+
expect(driver.errors()).toHaveLength(0)
|
|
64
|
+
await driver.dismiss()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test("/agents → agent dialog", async () => {
|
|
68
|
+
await driver.slash("agents")
|
|
69
|
+
driver.snapshot("slash-agents")
|
|
70
|
+
expect(driver.errors()).toHaveLength(0)
|
|
71
|
+
await driver.dismiss()
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test("/variants → variant dialog", async () => {
|
|
75
|
+
await driver.slash("variants")
|
|
76
|
+
driver.snapshot("slash-variants")
|
|
77
|
+
expect(driver.errors()).toHaveLength(0)
|
|
78
|
+
await driver.dismiss()
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// ── 세션 슬래시 명령 ──
|
|
82
|
+
|
|
83
|
+
test("/sessions → session list", async () => {
|
|
84
|
+
await driver.slash("sessions")
|
|
85
|
+
driver.snapshot("slash-sessions")
|
|
86
|
+
expect(driver.errors()).toHaveLength(0)
|
|
87
|
+
await driver.dismiss()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test("/resume → session list alias", async () => {
|
|
91
|
+
await driver.slash("resume")
|
|
92
|
+
driver.snapshot("slash-resume")
|
|
93
|
+
expect(driver.errors()).toHaveLength(0)
|
|
94
|
+
await driver.dismiss()
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
test("/continue → session list alias", async () => {
|
|
98
|
+
await driver.slash("continue")
|
|
99
|
+
driver.snapshot("slash-continue")
|
|
100
|
+
expect(driver.errors()).toHaveLength(0)
|
|
101
|
+
await driver.dismiss()
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
test("/new → new session (home)", async () => {
|
|
105
|
+
await driver.slash("new")
|
|
106
|
+
driver.snapshot("slash-new")
|
|
107
|
+
expect(driver.errors()).toHaveLength(0)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test("/clear → alias for /new", async () => {
|
|
111
|
+
await driver.slash("clear")
|
|
112
|
+
driver.snapshot("slash-clear")
|
|
113
|
+
expect(driver.errors()).toHaveLength(0)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// ── 에이전트/MCP 슬래시 명령 ──
|
|
117
|
+
|
|
118
|
+
test("/mcps → MCP dialog", async () => {
|
|
119
|
+
await driver.slash("mcps")
|
|
120
|
+
driver.snapshot("slash-mcps")
|
|
121
|
+
expect(driver.errors()).toHaveLength(0)
|
|
122
|
+
await driver.dismiss()
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test("/mcp-refresh → refresh MCP servers", async () => {
|
|
126
|
+
await driver.slash("mcp-refresh")
|
|
127
|
+
driver.snapshot("slash-mcp-refresh")
|
|
128
|
+
expect(driver.errors()).toHaveLength(0)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
test("/connect → provider dialog", async () => {
|
|
132
|
+
await driver.slash("connect")
|
|
133
|
+
driver.snapshot("slash-connect")
|
|
134
|
+
expect(driver.errors()).toHaveLength(0)
|
|
135
|
+
await driver.dismiss()
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
// ── 세션 관리 슬래시 명령 ──
|
|
139
|
+
|
|
140
|
+
test("/timeline → timeline dialog", async () => {
|
|
141
|
+
await driver.slash("timeline")
|
|
142
|
+
driver.snapshot("slash-timeline")
|
|
143
|
+
expect(driver.errors()).toHaveLength(0)
|
|
144
|
+
await driver.dismiss()
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
test("/compact → compact session", async () => {
|
|
148
|
+
await driver.slash("compact")
|
|
149
|
+
driver.snapshot("slash-compact")
|
|
150
|
+
expect(driver.errors()).toHaveLength(0)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
test("/summarize → alias for compact", async () => {
|
|
154
|
+
await driver.slash("summarize")
|
|
155
|
+
driver.snapshot("slash-summarize")
|
|
156
|
+
expect(driver.errors()).toHaveLength(0)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
test("/rename → rename dialog", async () => {
|
|
160
|
+
await driver.slash("rename")
|
|
161
|
+
driver.snapshot("slash-rename")
|
|
162
|
+
expect(driver.errors()).toHaveLength(0)
|
|
163
|
+
await driver.dismiss()
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
test("/fork → fork dialog", async () => {
|
|
167
|
+
await driver.slash("fork")
|
|
168
|
+
driver.snapshot("slash-fork")
|
|
169
|
+
expect(driver.errors()).toHaveLength(0)
|
|
170
|
+
await driver.dismiss()
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
// ── 편집/내보내기 ──
|
|
174
|
+
|
|
175
|
+
test("/editor → open editor", async () => {
|
|
176
|
+
await driver.slash("editor")
|
|
177
|
+
driver.snapshot("slash-editor")
|
|
178
|
+
expect(driver.errors()).toHaveLength(0)
|
|
179
|
+
await driver.dismiss(1000)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test("/skills → skills dialog", async () => {
|
|
183
|
+
await driver.slash("skills")
|
|
184
|
+
driver.snapshot("slash-skills")
|
|
185
|
+
expect(driver.errors()).toHaveLength(0)
|
|
186
|
+
await driver.dismiss()
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
test("/copy → copy transcript", async () => {
|
|
190
|
+
await driver.slash("copy")
|
|
191
|
+
driver.snapshot("slash-copy")
|
|
192
|
+
expect(driver.errors()).toHaveLength(0)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
test("/export → export dialog", async () => {
|
|
196
|
+
await driver.slash("export")
|
|
197
|
+
driver.snapshot("slash-export")
|
|
198
|
+
expect(driver.errors()).toHaveLength(0)
|
|
199
|
+
await driver.dismiss()
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
// ── 토글 ──
|
|
203
|
+
|
|
204
|
+
test("/timestamps → toggle timestamps", async () => {
|
|
205
|
+
await driver.slash("timestamps")
|
|
206
|
+
driver.snapshot("slash-timestamps")
|
|
207
|
+
expect(driver.errors()).toHaveLength(0)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
test("/toggle-timestamps → alias", async () => {
|
|
211
|
+
await driver.slash("toggle-timestamps")
|
|
212
|
+
driver.snapshot("slash-toggle-timestamps")
|
|
213
|
+
expect(driver.errors()).toHaveLength(0)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
test("/thinking → toggle thinking", async () => {
|
|
217
|
+
await driver.slash("thinking")
|
|
218
|
+
driver.snapshot("slash-thinking")
|
|
219
|
+
expect(driver.errors()).toHaveLength(0)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
test("/toggle-thinking → alias", async () => {
|
|
223
|
+
await driver.slash("toggle-thinking")
|
|
224
|
+
driver.snapshot("slash-toggle-thinking")
|
|
225
|
+
expect(driver.errors()).toHaveLength(0)
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
// ── 포인팅 ──
|
|
229
|
+
|
|
230
|
+
test("/pointing → pointing dialog", async () => {
|
|
231
|
+
await driver.slash("pointing")
|
|
232
|
+
driver.snapshot("slash-pointing")
|
|
233
|
+
expect(driver.errors()).toHaveLength(0)
|
|
234
|
+
await driver.dismiss()
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
test("/point → alias for pointing", async () => {
|
|
238
|
+
await driver.slash("point")
|
|
239
|
+
driver.snapshot("slash-point")
|
|
240
|
+
expect(driver.errors()).toHaveLength(0)
|
|
241
|
+
await driver.dismiss()
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
test("/unpointing → clear pointing", async () => {
|
|
245
|
+
await driver.slash("unpointing")
|
|
246
|
+
driver.snapshot("slash-unpointing")
|
|
247
|
+
expect(driver.errors()).toHaveLength(0)
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
test("/unpoint → alias for unpointing", async () => {
|
|
251
|
+
await driver.slash("unpoint")
|
|
252
|
+
driver.snapshot("slash-unpoint")
|
|
253
|
+
expect(driver.errors()).toHaveLength(0)
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
// ── 공유 (share/unshare는 provider 없이 에러 처리만) ──
|
|
257
|
+
|
|
258
|
+
test("/share → share session", async () => {
|
|
259
|
+
await driver.slash("share")
|
|
260
|
+
driver.snapshot("slash-share")
|
|
261
|
+
expect(driver.errors()).toHaveLength(0)
|
|
262
|
+
await driver.dismiss()
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
test("/unshare → unshare session", async () => {
|
|
266
|
+
await driver.slash("unshare")
|
|
267
|
+
driver.snapshot("slash-unshare")
|
|
268
|
+
expect(driver.errors()).toHaveLength(0)
|
|
269
|
+
await driver.dismiss()
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
// ── undo/redo ──
|
|
273
|
+
|
|
274
|
+
test("/undo → undo message", async () => {
|
|
275
|
+
await driver.slash("undo")
|
|
276
|
+
driver.snapshot("slash-undo")
|
|
277
|
+
expect(driver.errors()).toHaveLength(0)
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
test("/redo → redo message", async () => {
|
|
281
|
+
await driver.slash("redo")
|
|
282
|
+
driver.snapshot("slash-redo")
|
|
283
|
+
expect(driver.errors()).toHaveLength(0)
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
// ── 로그 ──
|
|
287
|
+
|
|
288
|
+
test("/logs → open log file", async () => {
|
|
289
|
+
await driver.slash("logs")
|
|
290
|
+
driver.snapshot("slash-logs")
|
|
291
|
+
expect(driver.errors()).toHaveLength(0)
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
// ── 종료 (마지막) ──
|
|
295
|
+
|
|
296
|
+
test("/quit → exit alias", async () => {
|
|
297
|
+
await driver.slash("quit")
|
|
298
|
+
await driver.wait(2000)
|
|
299
|
+
driver.snapshot("slash-quit")
|
|
300
|
+
expect(driver.errors()).toHaveLength(0)
|
|
301
|
+
})
|
|
302
|
+
})
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tui-walkthrough-system.test.ts — 시스템 토글 + 부팅 + 종료 검증
|
|
3
|
+
*
|
|
4
|
+
* - TUI 부팅 (alternate screen 진입)
|
|
5
|
+
* - Home 화면 렌더링
|
|
6
|
+
* - 커맨드 팔레트에서 시스템 명령 선택
|
|
7
|
+
* - 모든 토글 명령: notifications, animations, file_context,
|
|
8
|
+
* paste_summary, diffwrap, terminal_title, session_directory_filter
|
|
9
|
+
* - debug overlay, console toggle
|
|
10
|
+
* - /restart, /exit, /quit, /q, /rs
|
|
11
|
+
* - 전체 스냅샷 에러 재검사
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, expect, test, beforeAll, afterAll } from "bun:test"
|
|
15
|
+
import { tmpdir, disposeAllInstances } from "../fixture/fixture"
|
|
16
|
+
import * as Log from "@saeeol/core/util/log"
|
|
17
|
+
import { Flag } from "@saeeol/core/flag/flag"
|
|
18
|
+
import { TuiDriver, Key, hasError } from "./tui-walkthrough-driver"
|
|
19
|
+
import path from "path"
|
|
20
|
+
|
|
21
|
+
void Log.init({ print: false })
|
|
22
|
+
|
|
23
|
+
describe("TUI walkthrough: system + boot + exit", () => {
|
|
24
|
+
let driver: TuiDriver
|
|
25
|
+
let tmp: Awaited<ReturnType<typeof tmpdir>>
|
|
26
|
+
|
|
27
|
+
beforeAll(async () => {
|
|
28
|
+
tmp = await tmpdir({ git: true, config: {} })
|
|
29
|
+
Flag.SAEEOL_EXPERIMENTAL_HTTPAPI = false
|
|
30
|
+
driver = new TuiDriver(tmp.path)
|
|
31
|
+
await driver.wait(6000)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
afterAll(async () => {
|
|
35
|
+
await driver.saveReport(".tui-system-report.txt")
|
|
36
|
+
await driver.kill()
|
|
37
|
+
await disposeAllInstances()
|
|
38
|
+
Flag.SAEEOL_EXPERIMENTAL_HTTPAPI = true
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// ── 부팅 검증 ──
|
|
42
|
+
|
|
43
|
+
test("boot: TUI enters alternate screen", async () => {
|
|
44
|
+
driver.snapshot("boot")
|
|
45
|
+
expect(driver.output).toMatch(/\x1b\[\?9001h|\x1b\[\?1004h/)
|
|
46
|
+
expect(driver.errors()).toHaveLength(0)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test("home: renders content", async () => {
|
|
50
|
+
const { plain } = driver.snapshot("home")
|
|
51
|
+
expect(plain.length).toBeGreaterThan(0)
|
|
52
|
+
expect(driver.errors()).toHaveLength(0)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// ── 시스템 슬래시 명령 ──
|
|
56
|
+
|
|
57
|
+
test("/restart → restart attempt", async () => {
|
|
58
|
+
await driver.slash("restart")
|
|
59
|
+
driver.snapshot("slash-restart")
|
|
60
|
+
expect(driver.errors()).toHaveLength(0)
|
|
61
|
+
// restart 후 재부팅 대기
|
|
62
|
+
await driver.wait(6000)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test("/rs → restart alias", async () => {
|
|
66
|
+
await driver.slash("rs")
|
|
67
|
+
driver.snapshot("slash-rs")
|
|
68
|
+
expect(driver.errors()).toHaveLength(0)
|
|
69
|
+
await driver.wait(6000)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// ── 시스템 토글 (커맨드 팔레트로 진입) ──
|
|
73
|
+
// 이들은 슬래시 명령이 아니라 커맨드 팔레트(ctrl+p)에서 검색으로 선택
|
|
74
|
+
|
|
75
|
+
test("toggle: notifications via palette", async () => {
|
|
76
|
+
// 커맨드 팔레트 열고 명령 검색
|
|
77
|
+
driver.write(Key.ctrlP)
|
|
78
|
+
await driver.wait(1000)
|
|
79
|
+
driver.write("notifications")
|
|
80
|
+
await driver.wait(500)
|
|
81
|
+
driver.write(Key.enter)
|
|
82
|
+
await driver.wait(500)
|
|
83
|
+
driver.snapshot("toggle-notifications")
|
|
84
|
+
expect(driver.errors()).toHaveLength(0)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test("toggle: animations via palette", async () => {
|
|
88
|
+
driver.write(Key.ctrlP)
|
|
89
|
+
await driver.wait(1000)
|
|
90
|
+
driver.write("animations")
|
|
91
|
+
await driver.wait(500)
|
|
92
|
+
driver.write(Key.enter)
|
|
93
|
+
await driver.wait(500)
|
|
94
|
+
driver.snapshot("toggle-animations")
|
|
95
|
+
expect(driver.errors()).toHaveLength(0)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test("toggle: file context via palette", async () => {
|
|
99
|
+
driver.write(Key.ctrlP)
|
|
100
|
+
await driver.wait(1000)
|
|
101
|
+
driver.write("file context")
|
|
102
|
+
await driver.wait(500)
|
|
103
|
+
driver.write(Key.enter)
|
|
104
|
+
await driver.wait(500)
|
|
105
|
+
driver.snapshot("toggle-file-context")
|
|
106
|
+
expect(driver.errors()).toHaveLength(0)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
test("toggle: paste summary via palette", async () => {
|
|
110
|
+
driver.write(Key.ctrlP)
|
|
111
|
+
await driver.wait(1000)
|
|
112
|
+
driver.write("paste summary")
|
|
113
|
+
await driver.wait(500)
|
|
114
|
+
driver.write(Key.enter)
|
|
115
|
+
await driver.wait(500)
|
|
116
|
+
driver.snapshot("toggle-paste-summary")
|
|
117
|
+
expect(driver.errors()).toHaveLength(0)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test("toggle: diffwrap via palette", async () => {
|
|
121
|
+
driver.write(Key.ctrlP)
|
|
122
|
+
await driver.wait(1000)
|
|
123
|
+
driver.write("diffwrap")
|
|
124
|
+
await driver.wait(500)
|
|
125
|
+
driver.write(Key.enter)
|
|
126
|
+
await driver.wait(500)
|
|
127
|
+
driver.snapshot("toggle-diffwrap")
|
|
128
|
+
expect(driver.errors()).toHaveLength(0)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
test("toggle: session directory filter via palette", async () => {
|
|
132
|
+
driver.write(Key.ctrlP)
|
|
133
|
+
await driver.wait(1000)
|
|
134
|
+
driver.write("session directory filter")
|
|
135
|
+
await driver.wait(500)
|
|
136
|
+
driver.write(Key.enter)
|
|
137
|
+
await driver.wait(500)
|
|
138
|
+
driver.snapshot("toggle-session-dir-filter")
|
|
139
|
+
expect(driver.errors()).toHaveLength(0)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
// ── 디버그/콘솔 ──
|
|
143
|
+
|
|
144
|
+
test("debug overlay via palette", async () => {
|
|
145
|
+
driver.write(Key.ctrlP)
|
|
146
|
+
await driver.wait(1000)
|
|
147
|
+
driver.write("debug")
|
|
148
|
+
await driver.wait(500)
|
|
149
|
+
driver.write(Key.enter)
|
|
150
|
+
await driver.wait(500)
|
|
151
|
+
driver.snapshot("debug-overlay")
|
|
152
|
+
expect(driver.errors()).toHaveLength(0)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
test("console toggle via palette", async () => {
|
|
156
|
+
driver.write(Key.ctrlP)
|
|
157
|
+
await driver.wait(1000)
|
|
158
|
+
driver.write("console")
|
|
159
|
+
await driver.wait(500)
|
|
160
|
+
driver.write(Key.enter)
|
|
161
|
+
await driver.wait(500)
|
|
162
|
+
driver.snapshot("console-toggle")
|
|
163
|
+
expect(driver.errors()).toHaveLength(0)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
// ── org 전환 (조건부) ──
|
|
167
|
+
|
|
168
|
+
test("/org → org switch dialog", async () => {
|
|
169
|
+
await driver.slash("org")
|
|
170
|
+
driver.snapshot("slash-org")
|
|
171
|
+
expect(driver.errors()).toHaveLength(0)
|
|
172
|
+
await driver.dismiss()
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
test("/orgs → alias", async () => {
|
|
176
|
+
await driver.slash("orgs")
|
|
177
|
+
driver.snapshot("slash-orgs")
|
|
178
|
+
expect(driver.errors()).toHaveLength(0)
|
|
179
|
+
await driver.dismiss()
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test("/switch-org → alias", async () => {
|
|
183
|
+
await driver.slash("switch-org")
|
|
184
|
+
driver.snapshot("slash-switch-org")
|
|
185
|
+
expect(driver.errors()).toHaveLength(0)
|
|
186
|
+
await driver.dismiss()
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
// ── 종료 ──
|
|
190
|
+
|
|
191
|
+
test("/q → exit alias", async () => {
|
|
192
|
+
await driver.slash("q")
|
|
193
|
+
await driver.wait(2000)
|
|
194
|
+
driver.snapshot("slash-q-exit")
|
|
195
|
+
expect(driver.errors()).toHaveLength(0)
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
// ── 전체 스냅샷 에러 재검사 ──
|
|
199
|
+
|
|
200
|
+
test("all snapshots: no errors in any screen", async () => {
|
|
201
|
+
const allErrors: string[] = []
|
|
202
|
+
for (const snap of driver.snapshots) {
|
|
203
|
+
const snapErrors = hasError(snap.plain)
|
|
204
|
+
if (snapErrors.length > 0) {
|
|
205
|
+
allErrors.push(`[${snap.name}]: ${snapErrors.join("; ")}`)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
expect(allErrors).toHaveLength(0)
|
|
209
|
+
})
|
|
210
|
+
})
|