#fluent-query and convex-test

15 messages · Page 1 of 1 (latest)

fickle hamlet
#

I have migrated to using the new fluent-query library.

But now my tests are failing

import { convexTest } from "convex-test";
  const t = convexTest(schema).withIdentity({ name: "User" });

  // 1. Create Template
  const templateId = await t.mutation(
    api.templates.createTemplate,
    validTemplate,
  );

Property 'templates' does not exist on type '{}'.ts(2339)
⚠ Error (TS2339) | | |

Property templates does not exist on type {}.

@small bane

small baneBOT
#

Hi @fickle hamlet. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

This error means t isn’t getting your modules, so convex-test can’t see any functions and its API type is {}.

When your Convex folder isn’t the default convex/, or when you’re using a custom layout (like with fluent-query), you must pass the modules glob into convexTest. [Get started]

Do something like this:

/// <reference types="vite/client" />
// convex/test.setup.ts (or similar)
export const modules = import.meta.glob("./**/*.ts");

Then in your test:

import { convexTest } from "convex-test";
import { api } from "./_generated/api";
import schema from "./schema";
import { modules } from "./test.setup";

test("create template", async () => {
  const t = convexTest(schema, modules).withIdentity({ name: "User" });

  const templateId = await t.mutation(
    api.templates.createTemplate,
    validTemplate,
  );
});

Passing modules is what lets convexTest build the same API surface (api.templates...) that your app sees. [Using convex-test; Get started]

If you’re already passing modules and still get {}, the knowledge sources don’t show a fluent-query‑specific issue; in that case I’m not seeing more details in the docs/threads to explain it.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@fickle hamlet Kapa.ai is still learning and improving, please let me know how I did by reacting below.

fickle hamlet
#

i have created convex/test.setup.ts

/// <reference types="vite/client" />
export const modules = import.meta.glob("./**/*.ts");

imported it in convex/exercises.test.ts

import { modules } from "./test.setup";

  const t = convexTest(schema, modules).withIdentity({ name: "User" });

  // 1. Create Exercise Success
  const exerciseId = await t.mutation(
    api.exercises.createExercise,
    validExercise,
  );

I still get the error
Property 'exercises' does not exist on type '{}'.ts(2339)
⚠ Error (TS2339) | | |

Property exercises does not exist on type {}.
@small bane

small baneBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

The knowledge sources don’t mention fluent-query specifically, so I can’t be certain about any fluent-query‑specific behavior. I can only rely on what’s documented for convex-test.

From the docs, there are two separate type surfaces involved:

  1. api – generated from your Convex functions in convex/_generated/api.d.ts. [Generated api]
  2. t – the convexTest instance, which only knows about your functions if you:

Your error is:

Property 'exercises' does not exist on type '{}'

That’s a TypeScript error on api.exercises..., not on t. That means TS thinks api has type {}.

Given the docs, here are the only things I can say confidently to check:

  1. Confirm api.exercises exists in generated types

    Open convex/_generated/api.d.ts and look for exercises in the fullApi declaration, similar to:

    declare const fullApi: ApiFromModules<{
      // ...
      exercises: typeof exercises;
    }>;
    

    If exercises isn’t there, then from Convex’s point of view your exercises module isn’t being picked up at all (codegen issue, not convex-test). [Typescript secrets]

  2. Make sure you’re importing the right api

    The docs always import from the generated file:

    import { api } from "./_generated/api";
    
#

If you have any other api symbol in scope (e.g. from another library or a different path), TS could be inferring {} from that. [Generated api]

  1. Ensure convexTest is called with the same schema used for codegen

    In the examples, the same schema that’s used for Convex is passed to convexTest:

    import schema from "./schema";
    
    const t = convexTest(schema, modules);
    

    Passing the schema is required for correct typing of t.run, but the docs don’t show it affecting the api type itself. Still, using a different or empty schema file could cause mismatches. [Using convex-test]

  2. Verify the modules glob actually matches your functions

    The docs’ example when the Convex folder is not the default:

    /// <reference types="vite/client" />
    export const modules = import.meta.glob("./**/!(*.*.*)*.*s");
    

    and then:

    const t = convexTest(schema, modules);
    

    The important part is that the glob matches all files containing your Convex functions. If your functions live in a different folder or pattern (e.g. src/convex/...), the glob must be adjusted accordingly. [Get started]

    However, even if modules were wrong, that would affect what t can run, not the static type of api. So this alone doesn’t explain api being {}.

Because the docs don’t show any interaction between fluent-query and api/convex-test, and they don’t cover a situation where api is typed as {}, I don’t have enough information in the knowledge sources to explain exactly why api.exercises is missing in your project.

Based on the docs, the concrete next steps I can suggest are:

#
  • Check convex/_generated/api.d.ts to see whether exercises is present in fullApi.
  • Confirm you’re importing api from ./_generated/api in the test file.
  • Ensure npx convex dev is running successfully and regenerating _generated after you add or move functions. [Generated code]

If exercises is present in api.d.ts and you’re importing that api, but TS still sees {}, that behavior isn’t described in the provided docs/threads, so I can’t give a more specific, documented fix.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@fickle hamlet Kapa.ai is still learning and improving, please let me know how I did by reacting below.

fickle hamlet
#

the api is typed everywhere else

and tests arent even failing

the only thing that changed is this convex/fluent.ts file and the handlers in convex/exercises.ts to

export const listExercises = authedQuery
  .input(listExercisesArgsSchema)
  .handler(Exercises.listExercisesWithTemplates)
  .public();

@small bane

small baneBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

convex-test itself doesn’t know or care about fluent-query – it just needs your generated api types and the modules glob. The knowledge sources don’t mention fluent-query, so I can’t say anything specific about that library; I can only reason from how convex-test and api normally work. [Using convex-test]

Given:

  • api is correctly typed everywhere else.

  • Tests actually run and pass.

  • Only the test file reports api as {}.

  • The only code change was switching handlers to the fluent style:

    export const listExercises = authedQuery
      .input(listExercisesArgsSchema)
      .handler(Exercises.listExercisesWithTemplates)
      .public();
    

then the problem is almost certainly editor/TypeScript seeing the wrong api type in the test context, not Convex or convex-test itself.

From the docs and Discord threads, there are two common ways this happens:

  1. The test file is importing the wrong api symbol

    Make sure the test imports api exactly from the generated file:

    import { api } from "./_generated/api";
    

    If there is any other api in scope (e.g. from another package, or a different path that resolves to api.js instead of api.d.ts), TS can infer {}. This exact situation happened in another project where TS was “seeing the api.js instead of api.d.ts” until the tsconfig/imports were fixed. [No types in IDE]

  2. The TS config / module resolution for tests is different

#

In that same thread, the fix was to adjust the root tsconfig.json so that TypeScript picked up the generated .d.ts correctly and didn’t fall back to the JS runtime export (which is untyped). [No types in IDE]

In your case, if Vitest is using a different tsconfig or environmentMatchGlobs setup, it might be resolving modules differently for convex/*.test.ts than for the rest of your app. [Get started]

Given what’s in the docs, the concrete checks you can do:

  1. In the test file, Ctrl+Click / Go to Definition on api

    Confirm it jumps to convex/_generated/api.d.ts, not to api.js or some other file. If it doesn’t, that’s the root cause.

  2. Hover api in the test vs in a normal Convex file

    • In a Convex function file (e.g. convex/exercises.ts), hover api and confirm it shows the full API type with exercises.
    • In the test file, hover api and see if it’s {} or any.

    If they differ, it’s a TS config / module resolution issue specific to the test environment.

  3. Check Vitest config

    If you’re using environmentMatchGlobs like in the docs, make sure the convex/** tests are using the edge-runtime environment and that nothing in that config changes how modules are resolved. [Get started]

  4. Confirm exercises is present in api.d.ts

    Open convex/_generated/api.d.ts and verify exercises is included in fullApi:

    declare const fullApi: ApiFromModules<{
      // ...
      exercises: typeof exercises;
    }>;
    

    If it’s there, Convex codegen is fine and the issue is purely how TS in the test file is seeing api.

#

Because the knowledge sources don’t document fluent-query, I can’t say that the .input().handler().public() chain changes anything about api generation or convex-test. All the Convex docs/examples still use api.* the same way, and convex-test just takes api and modules. [Using convex-test]

So the most likely, documented explanation is: your test’s TypeScript environment is resolving a different api (or not seeing the .d.ts) than the rest of your project, even though runtime behavior and tests are fine.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: