Skip to content

Commit 8514a44

Browse files
authored
Add more tests for CellStateManager.ts (#143)
1 parent 4deb344 commit 8514a44

File tree

4 files changed

+161
-6
lines changed

4 files changed

+161
-6
lines changed

extension/src/__mocks__/TestVsCode.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class NotebookCellOutputItem implements NotebookCellOutputItem {
117117
}
118118
}
119119

120-
class NotebookRange implements vscode.NotebookRange {
120+
export class NotebookRange implements vscode.NotebookRange {
121121
readonly start: number;
122122
readonly end: number;
123123
get isEmpty(): boolean {
@@ -1139,7 +1139,7 @@ export class TestVsCode extends Data.TaggedClass("TestVsCode")<{
11391139
return Ref.get(this.statusBarProviders);
11401140
}
11411141

1142-
fireNotebookDocumentChange(event: vscode.NotebookDocumentChangeEvent) {
1142+
notebookChange(event: vscode.NotebookDocumentChangeEvent) {
11431143
return PubSub.publish(this.documentChangesPubSub, event);
11441144
}
11451145
static make = Effect.fnUntraced(function* (

extension/src/services/VsCode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ export class Workspace extends Effect.Service<Workspace>()("Workspace", {
271271
return Stream.asyncPush<vscode.NotebookDocumentChangeEvent>((emit) =>
272272
Effect.acquireRelease(
273273
Effect.sync(() =>
274-
api.onDidChangeNotebookDocument((evt) => emit.single(evt)),
274+
api.onDidChangeNotebookDocument((event) => emit.single(event)),
275275
),
276276
(disposable) => Effect.sync(() => disposable.dispose()),
277277
),

extension/src/services/__tests__/CellStateManager.test.ts

Lines changed: 157 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,40 @@
11
import { describe, expect, it } from "@effect/vitest";
2-
import { Effect } from "effect";
2+
import { Effect, Layer, Option, Ref, Stream, TestClock } from "effect";
33
import {
44
createTestNotebookDocument,
5+
NotebookRange,
56
TestVsCode,
67
} from "../../__mocks__/TestVsCode.ts";
8+
import type { MarimoCommand } from "../../types.ts";
79
import { getNotebookCellId } from "../../utils/notebook.ts";
10+
import { CellStateManager } from "../CellStateManager.ts";
11+
import { LanguageClient } from "../LanguageClient.ts";
812
import { VsCode } from "../VsCode.ts";
913

1014
const withTestCtx = Effect.fnUntraced(function* () {
1115
const vscode = yield* TestVsCode.make();
12-
return { vscode, layer: vscode.layer };
16+
const executions = yield* Ref.make<ReadonlyArray<MarimoCommand>>([]);
17+
const layer = Layer.empty.pipe(
18+
Layer.merge(CellStateManager.Default),
19+
Layer.provideMerge(vscode.layer),
20+
Layer.provide(
21+
Layer.succeed(
22+
LanguageClient,
23+
LanguageClient.make({
24+
manage() {
25+
return Effect.void;
26+
},
27+
executeCommand(cmd) {
28+
return Ref.update(executions, (arr) => [...arr, cmd]);
29+
},
30+
streamOf() {
31+
return Stream.never;
32+
},
33+
}),
34+
),
35+
),
36+
);
37+
return { vscode, layer, executions };
1338
});
1439

1540
describe("CellStateManager", () => {
@@ -56,4 +81,134 @@ describe("CellStateManager", () => {
5681
}).pipe(Effect.provide(ctx.layer));
5782
}),
5883
);
84+
85+
it.effect(
86+
"deleting cell from notebook sends delete_cell command",
87+
Effect.fnUntraced(function* () {
88+
const ctx = yield* withTestCtx();
89+
90+
yield* Effect.gen(function* () {
91+
const code = yield* VsCode;
92+
93+
const notebook = createTestNotebookDocument(
94+
"/test/notebook.py",
95+
new code.NotebookData([
96+
new code.NotebookCellData(
97+
code.NotebookCellKind.Code,
98+
"x = 1",
99+
"python",
100+
),
101+
new code.NotebookCellData(
102+
code.NotebookCellKind.Code,
103+
"y = 2",
104+
"python",
105+
),
106+
new code.NotebookCellData(
107+
code.NotebookCellKind.Code,
108+
"z = 3",
109+
"python",
110+
),
111+
]),
112+
);
113+
114+
yield* ctx.vscode.addNotebookDocument(notebook);
115+
yield* TestClock.adjust("10 millis");
116+
117+
const cellToDelete = notebook.cellAt(1);
118+
119+
yield* ctx.vscode.notebookChange({
120+
notebook,
121+
metadata: undefined,
122+
cellChanges: [],
123+
contentChanges: [
124+
{
125+
range: new NotebookRange(1, 2), // Delete cell at index 1
126+
removedCells: [cellToDelete],
127+
addedCells: [],
128+
},
129+
],
130+
});
131+
132+
yield* TestClock.adjust("10 millis");
133+
134+
const commands = yield* Ref.get(ctx.executions);
135+
expect(commands).toMatchInlineSnapshot(`
136+
[
137+
{
138+
"command": "marimo.api",
139+
"params": {
140+
"method": "delete_cell",
141+
"params": {
142+
"inner": {
143+
"cellId": "file:///test/notebook.py#cell-1",
144+
},
145+
"notebookUri": "file:///test/notebook.py",
146+
},
147+
},
148+
},
149+
]
150+
`);
151+
}).pipe(Effect.provide(ctx.layer));
152+
}),
153+
);
154+
155+
it.effect(
156+
"updates marimo.notebook.hasStaleCells context when cells become stale",
157+
Effect.fnUntraced(function* () {
158+
const ctx = yield* withTestCtx();
159+
160+
yield* Effect.gen(function* () {
161+
const code = yield* VsCode;
162+
163+
const editor = TestVsCode.makeNotebookEditor(
164+
"/test/notebook.py",
165+
new code.NotebookData([
166+
new code.NotebookCellData(
167+
code.NotebookCellKind.Code,
168+
"x = 1",
169+
"python",
170+
),
171+
new code.NotebookCellData(
172+
code.NotebookCellKind.Code,
173+
"y = 2",
174+
"python",
175+
),
176+
]),
177+
);
178+
179+
yield* ctx.vscode.addNotebookDocument(editor.notebook);
180+
yield* ctx.vscode.setActiveNotebookEditor(Option.some(editor));
181+
yield* TestClock.adjust("10 millis");
182+
183+
// Clear all previous executions
184+
yield* Ref.update(ctx.vscode.executions, () => []);
185+
186+
// Trigger a cell content change to mark it as stale
187+
const cell0 = editor.notebook.cellAt(0);
188+
yield* ctx.vscode.notebookChange({
189+
notebook: editor.notebook,
190+
metadata: undefined,
191+
cellChanges: [
192+
{
193+
cell: cell0,
194+
document: cell0.document,
195+
metadata: undefined,
196+
outputs: [],
197+
executionSummary: undefined,
198+
},
199+
],
200+
contentChanges: [],
201+
});
202+
203+
yield* TestClock.adjust("10 millis");
204+
}).pipe(Effect.provide(ctx.layer));
205+
206+
expect(yield* Ref.get(ctx.vscode.executions)).toEqual([
207+
{
208+
command: "setContext",
209+
args: ["marimo.notebook.hasStaleCells", true],
210+
},
211+
]);
212+
}),
213+
);
59214
});

extension/src/services/__tests__/ExecutionRegistry.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ const withTestCtx = Effect.fnUntraced(function* (
2828
const layer = Layer.empty.pipe(
2929
Layer.merge(ExecutionRegistry.Default),
3030
Layer.merge(CellStateManager.Default),
31-
Layer.provideMerge(vscode.layer),
3231
Layer.provide(TestLanguageClientLive),
32+
Layer.provideMerge(vscode.layer),
3333
);
3434
return { vscode, layer };
3535
});

0 commit comments

Comments
 (0)