mit einem Klick
add-e2e-test
// When the user asks to add a new e2e test to the restate-e2e-services package
// When the user asks to add a new e2e test to the restate-e2e-services package
| name | add-e2e-test |
| description | When the user asks to add a new e2e test to the restate-e2e-services package |
| user-invocable | true |
All e2e test infrastructure lives under packages/tests/restate-e2e-services/. These tests are NOT run directly — they are executed by the Java e2e test runner which spins up Restate, deploys services, and injects RESTATE_INGRESS_URL and RESTATE_ADMIN_URL environment variables.
src/): Restate service definitions (the SUT). Registered via REGISTRY and imported in app.ts.test/): Vitest test files that call services through the ingress client.custom_tests.yaml): YAML config read by the Java e2e test runner to know which commands to execute.test/utils.ts): Provides ingressClient(), getIngressUrl(), getAdminUrl() — reads from env vars injected by the test runner.src/Create src/<service_name>.ts following this pattern:
import * as restate from "@restatedev/restate-sdk";
import { REGISTRY } from "./services.js";
const myService = restate.service({
name: "MyService",
handlers: {
myHandler: async (ctx: restate.Context, input: string): Promise<string> => {
// handler logic
return `result: ${input}`;
},
},
});
REGISTRY.addService(myService);
// Use REGISTRY.addObject() for virtual objects, REGISTRY.addWorkflow() for workflows
export type MyService = typeof myService;
Key points:
REGISTRY so the service is discoverableexport type MyService = typeof myService) so tests can import it for typed client callssrc/app.tsAdd an import line alongside the other service imports:
import "./my_service.js";
test/Create test/<service_name>.test.ts:
import { describe, it, expect } from "vitest";
import { ingressClient } from "./utils.js";
import type { MyService } from "../src/my_service.js";
const MyService: MyService = { name: "MyService" };
describe("MyService", () => {
it("should do something", async () => {
const ingress = ingressClient();
const client = ingress.serviceClient(MyService);
const result = await client.myHandler("input");
expect(result).toBe("result: input");
});
});
Key points:
../src/ for typed ingress client calls{ name: "ServiceName" } matching the service's registered nameingressClient() from ./utils.js — never hardcode URLsingress.objectClient(MyObject, "key")ingress.workflowClient(MyWorkflow, "workflowId")Run from repo root:
pnpm --filter @restatedev/restate-e2e-services run _check:types
From @restatedev/restate-sdk-clients:
const ingress = ingressClient();
// Service call
const svc = ingress.serviceClient(MyService);
await svc.handler(input);
// Virtual object call
const obj = ingress.objectClient(MyObject, "key");
await obj.handler(input);
// Workflow
const wf = ingress.workflowClient(MyWorkflow, "wfId");
await wf.workflowSubmit(input);
await wf.workflowAttach();
// Send (fire and forget)
const send = ingress.serviceSendClient(MyService);
await send.handler(input);
// Idempotent call
await svc.handler(input, restate.rpc.opts({ idempotencyKey: "key" }));
Run the Restate SDK conformance test suite locally against this SDK's Docker image. Use when the user wants to run sdk tests, run conformance tests, verify an implementation, or test against the test suite.
Update the SDK test service implementations to match a new version of the e2e conformance contracts. Use when the user says "update sdk tests", "update test contracts", or gives a specific e2e release tag to update to.
When the user asks to add a new option/field/config to service, handler, endpoint, ServiceOptions, HandlerOpts, ObjectOptions, WorkflowOptions, or the discovery schema