Skip to main content
Glama

Convex MCP server

Official
by get-convex
client.test.tsx6.13 kB
/** * @vitest-environment happy-dom */ import { test, expect, describe, vi } from "vitest"; import ws from "ws"; import { ConvexReactClient, createMutation, useQuery } from "./client.js"; import { ConvexProvider } from "./index.js"; import React from "react"; import { renderHook } from "@testing-library/react"; import { anyApi, makeFunctionReference } from "../server/api.js"; const address = "https://127.0.0.1:3001"; const testConvexReactClient = () => new ConvexReactClient(address, { webSocketConstructor: ws as unknown as typeof WebSocket, }); describe("ConvexReactClient", () => { test("can be constructed", () => { const client = testConvexReactClient(); expect(typeof client).not.toEqual("undefined"); }); }); describe("createMutation", () => { test("Optimistic updates can be created", () => { const client = testConvexReactClient(); createMutation(anyApi.myMutation.default, client).withOptimisticUpdate( () => { // no update }, ); }); test("Specifying an optimistic update twice produces an error", () => { const client = testConvexReactClient(); const mutation = createMutation( anyApi.myMutation.default, client, ).withOptimisticUpdate(() => { // no update }); expect(() => { mutation.withOptimisticUpdate(() => { // no update }); }).toThrow("Already specified optimistic update for mutation myMutation"); }); test("Using a mutation as an event handler directly throws a useful error", () => { const client = testConvexReactClient(); const fakeSyntheticEvent: any = { bubbles: false, cancelable: true, defaultPrevented: false, isTrusted: false, nativeEvent: {}, preventDefault: () => undefined, isDefaultPrevented: false, stopPropagation: () => undefined, isPropagationStopped: false, persist: () => undefined, timeStamp: 0, type: "something", }; const myMutation = createMutation(anyApi.myMutation.default, client); expect(() => myMutation(fakeSyntheticEvent)).toThrow( "Convex function called with SyntheticEvent object.", ); }); }); describe("useQuery", () => { function createClientWithQuery() { const client = testConvexReactClient(); // Use an optimistic update to set up a query to have a result. void client.mutation( anyApi.myMutation.default, {}, { optimisticUpdate: (localStore) => { localStore.setQuery(anyApi.myQuery.default, {}, "queryResult"); }, }, ); return client; } test("returns the result", () => { const client = createClientWithQuery(); const wrapper = ({ children }: any) => ( <ConvexProvider client={client}>{children}</ConvexProvider> ); const { result } = renderHook(() => useQuery(anyApi.myQuery.default), { wrapper, }); expect(result.current).toStrictEqual("queryResult"); }); test("returns undefined when skipped", () => { const client = createClientWithQuery(); const wrapper = ({ children }: any) => ( <ConvexProvider client={client}>{children}</ConvexProvider> ); const { result } = renderHook( () => useQuery(anyApi.myQuery.default, "skip"), { wrapper, }, ); expect(result.current).toStrictEqual(undefined); }); test("Optimistic update handlers can’t be async", () => { const client = testConvexReactClient(); const mutation = createMutation( anyApi.myMutation.default, client, // @ts-expect-error ).withOptimisticUpdate(async () => {}); // Calling the mutation should warn in the console const consoleWarnSpy = vi.spyOn(console, "warn"); void mutation(); expect(consoleWarnSpy).toHaveBeenCalledWith( "Optimistic update handler returned a Promise. Optimistic updates should be synchronous.", ); }); }); // Intentionally disabled because we're only testing types describe.skip("useQuery typing", () => { test("useQuery with no args query", () => { const queryWithNoArgs = makeFunctionReference< "query", Record<string, never> >("foo"); useQuery(queryWithNoArgs, {}); // @ts-expect-error This should be an error useQuery(queryWithNoArgs, { x: 3 }); useQuery(queryWithNoArgs, "skip"); const x: number | null = null; useQuery(queryWithNoArgs, x === null ? "skip" : {}); // This should be an error, but isn't :(, probably a bug in TypeScript useQuery(queryWithNoArgs, x === null ? "skip" : { x }); // @ts-expect-error This should be an error useQuery(queryWithNoArgs, x === null ? "skip" : { x: 3 }); }); test("useQuery with query taking args", () => { const queryWithArgs = makeFunctionReference<"query", { x: number }>("foo"); // @ts-expect-error This should be an error useQuery(queryWithArgs); // @ts-expect-error This should be an error useQuery(queryWithArgs, { x: "not a number" }); useQuery(queryWithArgs, { x: 42 }); useQuery(queryWithArgs, "skip"); const x: number | null = null; useQuery(queryWithArgs, x === null ? "skip" : { x }); // @ts-expect-error This should be an error useQuery(queryWithArgs, x === null ? null : { x: "not a number" }); }); }); describe("async query fetch", () => { const client = testConvexReactClient(); function optimisticUpdate() { // Use an optimistic update to set up a query to have a result. void client.mutation( anyApi.myMutation.default, {}, { optimisticUpdate: (localStore) => { localStore.setQuery(anyApi.myQuery.default, {}, "queryResult"); }, }, ); } test("returns after optimistic update", async () => { const queryResult = client.query(anyApi.myQuery.default, {}); optimisticUpdate(); expect(await queryResult).toStrictEqual("queryResult"); }); test("returns existing result", async () => { optimisticUpdate(); const queryResult = client.query(anyApi.myQuery.default, {}); expect(await queryResult).toStrictEqual("queryResult"); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server