Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions packages/client-runtime/src/state/pullRequests.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { EnvironmentId, ProjectId, WS_METHODS } from "@t3tools/contracts";
import { expect, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import * as Stream from "effect/Stream";
import * as SubscriptionRef from "effect/SubscriptionRef";
import { AsyncResult, Atom, AtomRegistry } from "effect/unstable/reactivity";

import {
AVAILABLE_CONNECTION_STATE,
PrimaryConnectionTarget,
type PreparedConnection,
type SupervisorConnectionState,
} from "../connection/model.ts";
import * as EnvironmentRegistry from "../connection/registry.ts";
import * as EnvironmentSupervisor from "../connection/supervisor.ts";
import type { WsRpcProtocolClient } from "../rpc/protocol.ts";
import type { RpcSession } from "../rpc/session.ts";
import { createPullRequestEnvironmentAtoms } from "./pullRequests.ts";
import { PullRequestDiffLoader } from "./pullRequestDiffHttp.ts";
import { executeAtomQuery } from "./runtime.ts";

const TARGET = new PrimaryConnectionTarget({
environmentId: EnvironmentId.make("environment-1"),
label: "Test environment",
httpBaseUrl: "https://environment.example.test",
wsBaseUrl: "wss://environment.example.test",
});

function session(client: WsRpcProtocolClient): RpcSession {
return {
client,
initialConfig: Effect.never,
ready: Effect.void,
probe: Effect.void,
closed: Effect.never,
};
}

it.effect("refreshes pull request activity after a comment is updated", () =>
Effect.scoped(
Effect.gen(function* () {
let commentBody = "old comment";
const client = {
[WS_METHODS.pullRequestsActivity]: () =>
Effect.succeed({
author: null,
reviewers: [],
comments: [
{
id: "comment-1",
kind: "issue-comment",
author: null,
body: commentBody,
createdAt: "2026-08-24T00:00:00Z",
url: null,
path: null,
reviewState: null,
reactions: [],
},
],
commentCount: 1,
commentsTruncated: false,
reviewThreads: [],
commits: [],
reactions: [],
}),
[WS_METHODS.pullRequestsUpdateComment]: (input: { readonly body: string }) =>
Effect.sync(() => {
commentBody = input.body;
}),
} as unknown as WsRpcProtocolClient;
const connectionState: SupervisorConnectionState = {
...AVAILABLE_CONNECTION_STATE,
desired: true,
network: "online",
phase: "connected",
attempt: 1,
generation: 1,
};
const supervisor = EnvironmentSupervisor.EnvironmentSupervisor.of({
target: TARGET,
state: yield* SubscriptionRef.make(connectionState),
session: yield* SubscriptionRef.make(Option.some(session(client))),
prepared: yield* SubscriptionRef.make(Option.none<PreparedConnection>()),
connect: Effect.void,
disconnect: Effect.void,
retryNow: Effect.void,
} satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
const environmentRegistry = EnvironmentRegistry.EnvironmentRegistry.of({
run: (_environmentId, effect) =>
Effect.provideService(effect, EnvironmentSupervisor.EnvironmentSupervisor, supervisor),
runStream: (_environmentId, stream) =>
Stream.provideService(stream, EnvironmentSupervisor.EnvironmentSupervisor, supervisor),
followStream: (_environmentId, stream) =>
Stream.provideService(stream, EnvironmentSupervisor.EnvironmentSupervisor, supervisor),
} as EnvironmentRegistry.EnvironmentRegistry["Service"]);
const runtime = Atom.runtime(
Layer.merge(
Layer.succeed(EnvironmentRegistry.EnvironmentRegistry, environmentRegistry),
Layer.succeed(
PullRequestDiffLoader,
PullRequestDiffLoader.of({ load: () => Effect.die("unused") }),
),
),
);
const atoms = createPullRequestEnvironmentAtoms(runtime);
const registry = yield* Effect.acquireRelease(Effect.sync(AtomRegistry.make), (registry) =>
Effect.sync(() => registry.dispose()),
);
const reference = {
projectId: ProjectId.make("project-1"),
repository: "acme/web",
number: 1,
} as const;
const activity = atoms.activity({ environmentId: TARGET.environmentId, input: reference });
const unmount = registry.mount(activity);
yield* Effect.addFinalizer(() => Effect.sync(unmount));

const initial = yield* Effect.promise(() => executeAtomQuery(registry, activity));
expect(AsyncResult.isSuccess(initial)).toBe(true);
if (!AsyncResult.isSuccess(initial)) {
return yield* Effect.die("activity did not load");
}
expect(initial.value.comments[0]?.body).toBe("old comment");

const update = yield* Effect.promise(() =>
atoms.updateComment.run(registry, {
environmentId: TARGET.environmentId,
input: { ...reference, commentId: "comment-1", kind: "issue-comment", body: "updated" },
}),
);

expect(AsyncResult.isSuccess(update)).toBe(true);
expect(
(yield* AtomRegistry.getResult(registry, activity, { suspendOnWaiting: true })).comments[0]
?.body,
).toBe("updated");
}),
),
);
15 changes: 10 additions & 5 deletions packages/client-runtime/src/state/pullRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ export function createPullRequestEnvironmentAtoms<R, E>(
mode: "serial",
key: ({ environmentId }: { readonly environmentId: string }) => environmentId,
} as const;
const activity = createEnvironmentRpcQueryAtomFamily(runtime, {
label: "environment-data:pull-requests:activity",
tag: WS_METHODS.pullRequestsActivity,
staleTimeMs: 15_000,
});
return {
list: createEnvironmentRpcQueryAtomFamily(runtime, {
label: "environment-data:pull-requests:list",
Expand All @@ -56,11 +61,7 @@ export function createPullRequestEnvironmentAtoms<R, E>(
tag: WS_METHODS.pullRequestsDetail,
staleTimeMs: 15_000,
}),
activity: createEnvironmentRpcQueryAtomFamily(runtime, {
label: "environment-data:pull-requests:activity",
tag: WS_METHODS.pullRequestsActivity,
staleTimeMs: 15_000,
}),
activity,
threadComments: createEnvironmentRpcCommand(runtime, {
label: "environment-data:pull-requests:thread-comments",
tag: WS_METHODS.pullRequestsThreadComments,
Expand Down Expand Up @@ -129,6 +130,10 @@ export function createPullRequestEnvironmentAtoms<R, E>(
tag: WS_METHODS.pullRequestsUpdateComment,
scheduler: commandScheduler,
concurrency: serialPerEnvironment,
onSuccess: ({ environmentId, input: { projectId, repository, number } }, registry) =>
Effect.sync(() =>
registry.refresh(activity({ environmentId, input: { projectId, repository, number } })),
),
}),
submitReview: createEnvironmentRpcCommand(runtime, {
label: "environment-data:pull-requests:submit-review",
Expand Down
Loading