Skip to content

Commit cfb0fad

Browse files
seefeldbclaude
andcommitted
fix(tests): add sinks to keep charms reactive in pull mode
In pull mode, charms need an effect (sink) pulling from them to stay reactive when inputs change. Tests that set values externally and expect UI updates need to create a sink on the result cell. This is the correct approach rather than adding a blanket sink to all recipes - the test explicitly declares its intent to observe reactivity. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 1120e91 commit cfb0fad

File tree

4 files changed

+21
-0
lines changed

4 files changed

+21
-0
lines changed

packages/generated-patterns/integration/pattern-harness.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ export async function runPatternScenario(scenario: PatternIntegrationScenario) {
8888
const result = runtime.run(tx, patternFactory, argument, resultCell);
8989
tx.commit();
9090

91+
// Sink to keep the result reactive
92+
result.sink(() => {});
9193
await runtime.idle();
9294

9395
let stepIndex = 0;

packages/patterns/integration/counter.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ describe("counter direct operations test", () => {
1616
let identity: Identity;
1717
let cc: CharmsController;
1818
let charm: CharmController;
19+
let charmSinkCancel: (() => void) | undefined;
1920

2021
beforeAll(async () => {
2122
identity = await Identity.generate({ implementation: "noble" });
@@ -33,9 +34,15 @@ describe("counter direct operations test", () => {
3334
program, // We operate on the charm in this thread
3435
{ start: true },
3536
);
37+
38+
// In pull mode, create a sink to keep the charm reactive when inputs change.
39+
// Without this, setting values won't trigger recipe re-computation.
40+
const resultCell = cc.manager().getResult(charm.getCell());
41+
charmSinkCancel = resultCell.sink(() => {});
3642
});
3743

3844
afterAll(async () => {
45+
charmSinkCancel?.();
3946
if (cc) await cc.dispose();
4047
});
4148

packages/patterns/integration/ct-render.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ describe("ct-render integration test", () => {
1515
let identity: Identity;
1616
let cc: CharmsController;
1717
let charm: CharmController;
18+
let charmSinkCancel: (() => void) | undefined;
1819

1920
beforeAll(async () => {
2021
identity = await Identity.generate({ implementation: "noble" });
@@ -34,9 +35,14 @@ describe("ct-render integration test", () => {
3435
// We operate on the charm in this thread
3536
{ start: true },
3637
);
38+
39+
// In pull mode, create a sink to keep the charm reactive when inputs change.
40+
const resultCell = cc.manager().getResult(charm.getCell());
41+
charmSinkCancel = resultCell.sink(() => {});
3742
});
3843

3944
afterAll(async () => {
45+
charmSinkCancel?.();
4046
if (cc) await cc.dispose();
4147
});
4248

packages/patterns/integration/nested-counter.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ describe("nested counter integration test", () => {
1616
let identity: Identity;
1717
let cc: CharmsController;
1818
let charm: CharmController;
19+
let charmSinkCancel: (() => void) | undefined;
1920

2021
beforeAll(async () => {
2122
identity = await Identity.generate({ implementation: "noble" });
@@ -34,9 +35,14 @@ describe("nested counter integration test", () => {
3435
program, // We operate on the charm in this thread
3536
{ start: true },
3637
);
38+
39+
// In pull mode, create a sink to keep the charm reactive when inputs change.
40+
const resultCell = cc.manager().getResult(charm.getCell());
41+
charmSinkCancel = resultCell.sink(() => {});
3742
});
3843

3944
afterAll(async () => {
45+
charmSinkCancel?.();
4046
if (cc) await cc.dispose();
4147
});
4248

0 commit comments

Comments
 (0)