Jonathan
Jonathan2w ago

How to Test TRPC

I am trying to setup testing TRPC My Init looks like this:
import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";

import { auth, clerkClient } from "@clerk/nextjs/server";

// export const createTRPCContext = async (opts: { headers: Headers }) => {
export const createTRPCContext = async () => {
// This is where you would do things like verify the user's session, etc.
const authResult = await auth();

return {
clerk: authResult,
};
};

const t = initTRPC.context<typeof createTRPCContext>().create({
transformer: superjson,
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError:
error.cause instanceof ZodError ? error.cause.flatten() : null,
},
};
},
});

export const createCallerFactory = t.createCallerFactory;

export const createTRPCRouter = t.router;

export const publicProcedure = t.procedure;

const isAuthed = t.middleware(async ({ next, ctx }) => {
if (!ctx.clerk.userId) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Not logged in" });
}

const client = await clerkClient();

const memberships = await client.users.getOrganizationMembershipList({
userId: ctx.clerk.userId,
});

const activeMembership = memberships.data.find(
(mem) => mem.organization.id === ctx.clerk.orgId,
);

return next({
ctx: {
user: ctx.clerk.userId,
CustomerId: activeMembership?.organization.publicMetadata?.customerId as string,
UserId: activeMembership?.publicMetadata?.userId as string,
},
});
});

/** Reusable middleware that enforces users are logged in before running the procedure. */
export const protectedProcedure = t.procedure.use(isAuthed);
import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";

import { auth, clerkClient } from "@clerk/nextjs/server";

// export const createTRPCContext = async (opts: { headers: Headers }) => {
export const createTRPCContext = async () => {
// This is where you would do things like verify the user's session, etc.
const authResult = await auth();

return {
clerk: authResult,
};
};

const t = initTRPC.context<typeof createTRPCContext>().create({
transformer: superjson,
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError:
error.cause instanceof ZodError ? error.cause.flatten() : null,
},
};
},
});

export const createCallerFactory = t.createCallerFactory;

export const createTRPCRouter = t.router;

export const publicProcedure = t.procedure;

const isAuthed = t.middleware(async ({ next, ctx }) => {
if (!ctx.clerk.userId) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Not logged in" });
}

const client = await clerkClient();

const memberships = await client.users.getOrganizationMembershipList({
userId: ctx.clerk.userId,
});

const activeMembership = memberships.data.find(
(mem) => mem.organization.id === ctx.clerk.orgId,
);

return next({
ctx: {
user: ctx.clerk.userId,
CustomerId: activeMembership?.organization.publicMetadata?.customerId as string,
UserId: activeMembership?.publicMetadata?.userId as string,
},
});
});

/** Reusable middleware that enforces users are logged in before running the procedure. */
export const protectedProcedure = t.procedure.use(isAuthed);
My test looks like this
import { type inferProcedureInput } from "@trpc/server";
import { expect, test } from "vitest";

import { appRouter, type AppRouter } from "@/server/routers/_app";
import { createTRPCContext } from "@/server/init";


test("example router", async () => {
const ctx = await createTRPCContext();
const caller = appRouter.createCaller(ctx);

type Input = inferProcedureInput<AppRouter["entities"]["get"]>;
const input: Input = {
entityType: "test",
Id: "test",
};

const example = await caller.entities.get(input);

expect(example).toMatchObject({ greeting: "Hello test" });
});
import { type inferProcedureInput } from "@trpc/server";
import { expect, test } from "vitest";

import { appRouter, type AppRouter } from "@/server/routers/_app";
import { createTRPCContext } from "@/server/init";


test("example router", async () => {
const ctx = await createTRPCContext();
const caller = appRouter.createCaller(ctx);

type Input = inferProcedureInput<AppRouter["entities"]["get"]>;
const input: Input = {
entityType: "test",
Id: "test",
};

const example = await caller.entities.get(input);

expect(example).toMatchObject({ greeting: "Hello test" });
});
All I really need in the context to test with is CustomerId and UserId but how do I build a test context that has this information?
2 Replies

Did you find this page helpful?