Skip to content

Instantly share code, notes, and snippets.

@igalshilman
Last active April 11, 2025 15:09
Show Gist options
  • Save igalshilman/800b91db355126dcb5c31f4b8e4f3574 to your computer and use it in GitHub Desktop.
Save igalshilman/800b91db355126dcb5c31f4b8e4f3574 to your computer and use it in GitHub Desktop.
import { service, type Context } from "@restatedev/restate-sdk";
interface ServiceB {
greet: (ctx: Context, name: string) => Promise<string>;
}
const realServiceB = service({
name: "realServiceB",
handlers: {
greet: async (ctx: Context, name: string) => {
return `Hello ${name}`;
},
} satisfies ServiceB,
});
const makeServiceA = (serviceB: ServiceB) =>
service({
name: "serviceA",
handlers: {
greet: async (ctx: Context, name: string) => {
const greeting = await serviceB.greet(ctx, name);
return `Hello ${greeting}`;
},
},
});
const serviceA = makeServiceA({
greet: (ctx: Context, name: string): Promise<string> => {
//
// you can mock the behavior however you want here, as if you are serviceB
// or you can even forward the call to service B (or the mock one)
//
return Promise.resolve(`a mock greeting for ${name}`);
},
});
const realServiceA = makeServiceA({
greet: (ctx: Context, name: string): Promise<string> =>
ctx.serviceClient<ServiceB>({ name: "realServiceB" }).greet(name),
});
@igalshilman
Copy link
Author

import { RestateTestEnvironment } from "@restatedev/restate-sdk-testcontainers";
import { makeServiceA } from "../src/example_service";
import { setTimeout } from "node:timers/promises";
import * as clients from "@restatedev/restate-sdk-clients";

describe("ExampleService", () => {
    let restateTestEnvironment: RestateTestEnvironment;
    let restateIngress: clients.Ingress;

    beforeAll(async () => {
         const service = makeServiceA({
                       
                             ....
       });

        restateTestEnvironment = await RestateTestEnvironment.start(
            (restateServer) => restateServer.bind(service)
        );
        restateIngress = clients.connect({ url: restateTestEnvironment.baseUrl() });
    }, 20_000);

    afterAll(async () => {
        if (restateTestEnvironment !== undefined) {
            await restateTestEnvironment.stop();
        }
    });

    it("works", async () => {
        const greet = await restateIngress.serviceClient(exampleService)
            .greet("Sarah");

        // Assert the result
        expect(greet).toBe("Hello Sarah!");
    });
});

describe("ExampleObject", () => {
    let restateTestEnvironment: RestateTestEnvironment;
    let restateIngress: clients.Ingress;

    beforeAll(async () => {
        restateTestEnvironment = await RestateTestEnvironment.start(
            (restateServer) => restateServer.bind(exampleObject)
        );
        restateIngress = clients.connect({ url: restateTestEnvironment.baseUrl() });
    }, 20_000);

    afterAll(async () => {
        if (restateTestEnvironment !== undefined) {
            await restateTestEnvironment.stop();
        }
    });

    it("works", async () => {
        const state = restateTestEnvironment.stateOf(exampleObject, "Sarah");
        expect(await state.getAll()).toStrictEqual({})
        expect(await state.get("count")).toBeNull();

        // Setting state is an eventually consistent operation, so retrying might be needed
        let retry = 0;
        while(true) {
            try {
                await state.set("count", 123)
                break
            } catch (e) {
                await setTimeout(1000)
                retry++
                if (retry > 10) {
                    throw new Error("Unable to set state 'count'")
                }
            }
        }
        const greet = await restateIngress.objectClient(exampleObject, "Sarah")
            .greet();

        // Assert the result
        expect(greet).toBe("Hello Sarah! Counter: 123");
        expect(await state.get("count")).toStrictEqual(124)
    });
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment