1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
import type { WorkspaceEntry } from "@dispatch/wire";
import { render, screen } from "@testing-library/svelte";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import type { WorkspaceResult } from "../adapter/http";
import type { WorkspaceStore } from "../store.svelte";
import WorkspaceCard from "./WorkspaceCard.svelte";
function fakeEntry(overrides: Partial<WorkspaceEntry> = {}): WorkspaceEntry {
return {
id: "my-ws",
title: "My Workspace",
defaultCwd: null,
defaultComputerId: null,
createdAt: 1,
lastActivityAt: 2,
conversationCount: 3,
...overrides,
};
}
/** A fake store that records calls + resolves ok. */
function fakeStore() {
return {
rename: vi.fn(
async (id: string, _title: string): Promise<WorkspaceResult<WorkspaceEntry>> => ({
ok: true,
value: fakeEntry({ id, title: _title }),
}),
),
setDefaultCwd: vi.fn(
async (id: string, defaultCwd: string | null): Promise<WorkspaceResult<WorkspaceEntry>> => ({
ok: true,
value: fakeEntry({ id, defaultCwd }),
}),
),
setDefaultComputer: vi.fn(
async (id: string, computerId: string | null): Promise<WorkspaceResult<WorkspaceEntry>> => ({
ok: true,
value: fakeEntry({ id, defaultComputerId: computerId }),
}),
),
remove: vi.fn(
async (): Promise<WorkspaceResult<{ closedCount: number }>> => ({
ok: true,
value: { closedCount: 0 },
}),
),
};
}
describe("WorkspaceCard", () => {
it("renders the title, slug, and an Open link", () => {
const store = fakeStore() as unknown as WorkspaceStore;
render(WorkspaceCard, {
props: { ws: fakeEntry(), store, onNavigate: vi.fn(), computers: [] },
});
expect(screen.getByText("My Workspace")).toBeInTheDocument();
expect(screen.getByText("/my-ws")).toBeInTheDocument();
expect(screen.getByRole("link", { name: "Open" })).toHaveAttribute("href", "/my-ws");
});
it("double-clicking the title reveals an edit input", async () => {
const user = userEvent.setup();
const store = fakeStore() as unknown as WorkspaceStore;
render(WorkspaceCard, {
props: { ws: fakeEntry(), store, onNavigate: vi.fn(), computers: [] },
});
await user.dblClick(screen.getByText("My Workspace"));
expect(screen.getByLabelText("Workspace title")).toHaveValue("My Workspace");
});
it("renames via the store on Enter", async () => {
const user = userEvent.setup();
const store = fakeStore() as unknown as WorkspaceStore;
render(WorkspaceCard, {
props: { ws: fakeEntry(), store, onNavigate: vi.fn(), computers: [] },
});
await user.dblClick(screen.getByText("My Workspace"));
const input = screen.getByLabelText("Workspace title");
await user.clear(input);
await user.type(input, "Renamed{Enter}");
expect(store.rename).toHaveBeenCalledWith("my-ws", "Renamed");
});
it("enables Set only when the cwd differs, then saves it", async () => {
const user = userEvent.setup();
const store = fakeStore() as unknown as WorkspaceStore;
render(WorkspaceCard, {
props: { ws: fakeEntry({ defaultCwd: "/old" }), store, onNavigate: vi.fn(), computers: [] },
});
const input = screen.getByLabelText("Default working directory");
expect(input).toHaveValue("/old");
expect(screen.getByRole("button", { name: "Set" })).toBeDisabled();
await user.clear(input);
await user.type(input, "/new/path");
expect(screen.getByRole("button", { name: "Set" })).toBeEnabled();
await user.click(screen.getByRole("button", { name: "Set" }));
expect(store.setDefaultCwd).toHaveBeenCalledWith("my-ws", "/new/path");
});
it("clears the cwd to null when saved empty (inherits the server default)", async () => {
const user = userEvent.setup();
const store = fakeStore() as unknown as WorkspaceStore;
render(WorkspaceCard, {
props: { ws: fakeEntry({ defaultCwd: "/old" }), store, onNavigate: vi.fn(), computers: [] },
});
const input = screen.getByLabelText("Default working directory");
await user.clear(input);
await user.click(screen.getByRole("button", { name: "Set" }));
expect(store.setDefaultCwd).toHaveBeenCalledWith("my-ws", null);
});
it("the Open link navigates to the workspace in the same tab (SPA navigation, no new tab)", async () => {
const user = userEvent.setup();
const store = fakeStore() as unknown as WorkspaceStore;
const onNavigate = vi.fn();
render(WorkspaceCard, { props: { ws: fakeEntry(), store, onNavigate, computers: [] } });
const open = screen.getByRole("link", { name: "Open" });
// Still a real link (progressive enhancement): href points at the workspace.
expect(open).toHaveAttribute("href", "/my-ws");
// But it no longer opens a new browser tab.
expect(open).not.toHaveAttribute("target", "_blank");
// Clicking navigates in-place via the SPA callback.
await user.click(open);
expect(onNavigate).toHaveBeenCalledTimes(1);
expect(onNavigate).toHaveBeenCalledWith("/my-ws");
});
});
|