Skip to content

Commit 9a943ee

Browse files
committed
test(web): add coverage for terminal session container display
1 parent 11a102c commit 9a943ee

File tree

4 files changed

+194
-2
lines changed

4 files changed

+194
-2
lines changed

packages/web/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"dev": "concurrently -k \"next dev\" \"node scripts/terminal-ws.mjs\"",
77
"build": "next build",
88
"start": "next start",
9-
"lint": "eslint"
9+
"lint": "eslint",
10+
"test": "vitest run"
1011
},
1112
"dependencies": {
1213
"@effect-template/lib": "workspace:*",
@@ -29,6 +30,7 @@
2930
"eslint": "^9",
3031
"eslint-config-next": "16.1.6",
3132
"tailwindcss": "^4",
32-
"typescript": "^5"
33+
"typescript": "^5",
34+
"vitest": "^4.0.17"
3335
}
3436
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import fs from "node:fs"
2+
3+
import { afterEach, beforeEach, describe, expect, it } from "vitest"
4+
5+
import { GET } from "../../src/app/api/terminal-sessions/route"
6+
7+
const sessionsFile = "/tmp/docker-git-terminal-sessions.json"
8+
9+
let previousSessionsFileContent: string | null = null
10+
11+
beforeEach(() => {
12+
previousSessionsFileContent = fs.existsSync(sessionsFile)
13+
? fs.readFileSync(sessionsFile, "utf8")
14+
: null
15+
})
16+
17+
afterEach(() => {
18+
if (previousSessionsFileContent === null) {
19+
if (fs.existsSync(sessionsFile)) {
20+
fs.unlinkSync(sessionsFile)
21+
}
22+
return
23+
}
24+
fs.writeFileSync(sessionsFile, previousSessionsFileContent, "utf8")
25+
})
26+
27+
describe("GET /api/terminal-sessions", () => {
28+
it("returns sessions with containerName", async () => {
29+
fs.writeFileSync(
30+
sessionsFile,
31+
JSON.stringify({
32+
sessions: [
33+
{
34+
id: "session-1",
35+
projectId: "/tmp/project",
36+
displayName: "org/repo",
37+
containerName: "dg-repo-issue-47",
38+
mode: "default",
39+
source: "web",
40+
status: "connected",
41+
connectedAt: "2026-02-16T15:00:00.000Z",
42+
updatedAt: "2026-02-16T15:00:01.000Z"
43+
}
44+
]
45+
}),
46+
"utf8"
47+
)
48+
49+
const response = GET()
50+
const body = await response.json()
51+
const sessions = Reflect.get(body as object, "sessions")
52+
expect(Array.isArray(sessions)).toBe(true)
53+
const first = Array.isArray(sessions) ? sessions[0] : null
54+
expect(first).toMatchObject({
55+
id: "session-1",
56+
containerName: "dg-repo-issue-47",
57+
status: "connected"
58+
})
59+
})
60+
61+
it("returns an empty list when sessions file is missing", async () => {
62+
if (fs.existsSync(sessionsFile)) {
63+
fs.unlinkSync(sessionsFile)
64+
}
65+
const response = GET()
66+
const body = await response.json()
67+
expect(body).toEqual({ sessions: [] })
68+
})
69+
})
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Either } from "effect"
2+
import * as Schema from "effect/Schema"
3+
import { describe, expect, it } from "vitest"
4+
5+
import { ApiSchema } from "../../src/lib/api-schema"
6+
7+
const decodeTerminalSessions = Schema.decodeUnknownEither(ApiSchema.TerminalSessions)
8+
9+
describe("ApiSchema.TerminalSessions", () => {
10+
it("decodes sessions with containerName", () => {
11+
const payload = {
12+
sessions: [
13+
{
14+
id: "session-1",
15+
projectId: "/tmp/project",
16+
displayName: "org/repo",
17+
containerName: "dg-repo-issue-47",
18+
mode: "default",
19+
source: "web",
20+
status: "connected",
21+
connectedAt: "2026-02-16T15:00:00.000Z",
22+
updatedAt: "2026-02-16T15:00:01.000Z"
23+
}
24+
]
25+
}
26+
27+
const decoded = decodeTerminalSessions(payload)
28+
expect(Either.isRight(decoded)).toBe(true)
29+
if (Either.isLeft(decoded)) {
30+
return
31+
}
32+
expect(decoded.right.sessions[0]?.containerName).toBe("dg-repo-issue-47")
33+
})
34+
35+
it("keeps backward compatibility when containerName is absent", () => {
36+
const payload = {
37+
sessions: [
38+
{
39+
id: "session-legacy",
40+
projectId: "/tmp/project-legacy",
41+
displayName: "org/repo",
42+
mode: "default",
43+
source: "web",
44+
status: "connected",
45+
connectedAt: "2026-02-16T15:00:00.000Z",
46+
updatedAt: "2026-02-16T15:00:01.000Z"
47+
}
48+
]
49+
}
50+
51+
const decoded = decodeTerminalSessions(payload)
52+
expect(Either.isRight(decoded)).toBe(true)
53+
if (Either.isLeft(decoded)) {
54+
return
55+
}
56+
expect(decoded.right.sessions[0]?.containerName).toBeUndefined()
57+
})
58+
})

pnpm-lock.yaml

Lines changed: 63 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)