@@ -24,7 +24,7 @@ You can see more examples in the
2424[ test suite] ( https://github.com/get-convex/convex-test/tree/main/convex ) of the
2525convex-test library.
2626
27- ## Get Started
27+ ## Get started
2828
2929<StepByStep >
3030
@@ -54,11 +54,71 @@ convex-test library.
5454
5555 <Step title = " Configure Vitest" >
5656
57- Add <JSDialectFileName name = " vitest.config.mts " /> file to configure the test
57+ Add <JSDialectFileName name = " vitest.config.ts " /> file to configure the test
5858 environment to better match the Convex runtime, and to inline the test library
5959 for better dependency tracking.
6060
61- ``` ts title="vitest.config.mts"
61+ <Details summary = { <>If your Convex functions are in a directory other than <code >convex</code ></>} >
62+ If your project has a
63+ [ different name or location configured] ( /production/project-configuration.mdx#changing-the-convex-folder-name-or-location )
64+ for the ` convex/ ` folder in ` convex.json ` , you need to call
65+ [ ` import.meta.glob ` ] ( https://vitejs.dev/guide/features#glob-import ) and pass the
66+ result as the second argument to ` convexTest ` .
67+
68+ The argument to ` import.meta.glob ` must be a glob pattern matching all the files
69+ containing your Convex functions. The paths are relative to the test file in
70+ which ` import.meta.glob ` is called. It's best to do this in one place in your
71+ custom functions folder:
72+
73+ ``` ts title="src/convex/test.setup.ts"
74+ // / <reference types="vite/client" />
75+ export const modules = import .meta .glob (
76+ " ./**/!(*.*.*)*.*s"
77+ );
78+ ```
79+
80+ This example glob pattern includes all files with a single extension ending in
81+ ` s ` (like ` js ` or ` ts ` ) in the ` src/convex ` folder and any of its children.
82+
83+ Use the result in your tests:
84+
85+ ``` ts title="src/convex/messages.test.ts"
86+ import { convexTest } from " convex-test" ;
87+ import { test } from " vitest" ;
88+ import schema from " ./schema" ;
89+ import { modules } from " ./test.setup" ;
90+
91+ test (" some behavior" , async () => {
92+ const t = convexTest (schema , modules );
93+ // use `t`...
94+ });
95+ ```
96+ </Details >
97+
98+ <Details summary = " Set up multiple test environments (e.g. Convex + frontend)" >
99+ If you want to use Vitest to test both your Convex functions and your React
100+ frontend, you might want to use multiple Vitest environments depending on the
101+ test file location via
102+ [ environmentMatchGlobs] ( https://vitest.dev/config/#environmentmatchglobs ) :
103+
104+ ``` ts title="vitest.config.ts"
105+ import { defineConfig } from " vitest/config" ;
106+
107+ export default defineConfig ({
108+ test: {
109+ environmentMatchGlobs: [
110+ // all tests in convex/ will run in edge-runtime
111+ [" convex/**" , " edge-runtime" ],
112+ // all other tests use jsdom
113+ [" **" , " jsdom" ],
114+ ],
115+ server: { deps: { inline: [" convex-test" ] } },
116+ },
117+ });
118+ ```
119+ </Details >
120+
121+ ``` ts title="vitest.config.ts"
62122 import { defineConfig } from " vitest/config" ;
63123
64124 export default defineConfig ({
@@ -112,10 +172,12 @@ convex-test library.
112172
113173</StepByStep >
114174
115- If you're not familiar with Vitest or Jest read the
175+ If you're not familiar with Vitest, read the
116176[ Vitest Getting Started docs] ( https://vitest.dev/guide ) first.
117177
118- ## ` convexTest `
178+ ## Using convex-test
179+
180+ ### Initialize ` convexTest `
119181
120182The library exports a ` convexTest ` function which should be called at the start
121183of each of your tests. The function returns an object which is by convention
@@ -142,7 +204,7 @@ validation and for correct typing of
142204
143205If you don't have a schema, call ` convexTest() ` with no argument.
144206
145- ## Calling functions with ` t.query ` , ` t.mutation ` and ` t.action `
207+ ### Call functions
146208
147209Your test can call public and internal Convex [ functions] ( /functions.mdx ) in
148210your project:
@@ -163,7 +225,7 @@ test("functions", async () => {
163225});
164226```
165227
166- ## Setting up and inspecting data and storage with ` t.run `
228+ ### Modify data outside of functions
167229
168230Sometimes you might want to directly [ write] ( /database/writing-data.mdx ) to the
169231mock database or [ file storage] ( /file-storage.mdx ) from your test, without
@@ -185,7 +247,7 @@ test("functions", async () => {
185247});
186248```
187249
188- ## Testing HTTP actions with ` t.fetch `
250+ ### HTTP actions
189251
190252Your test can call [ HTTP actions] ( /functions/http-actions.mdx ) registered by
191253your router:
@@ -203,7 +265,7 @@ test("functions", async () => {
203265Mocking the global ` fetch ` function doesn't affect ` t.fetch ` , but you can use
204266` t.fetch ` in a ` fetch ` mock to route to your HTTP actions.
205267
206- ## Testing scheduled functions
268+ ### Scheduled functions
207269
208270One advantage of using a mock implementation running purely in JavaScript is
209271that you can control time in the Vitest test environment. To test
@@ -293,7 +355,7 @@ test("mutation scheduling action scheduling action", async () => {
293355Check out more examples in
294356[ this file] ( https://github.com/get-convex/convex-test/blob/main/convex/scheduler.test.ts ) .
295357
296- ## Testing authentication with ` t.withIdentity `
358+ ### Authentication
297359
298360To test functions which depend on the current [ authenticated] ( /auth.mdx ) user
299361identity you can create a version of the ` t ` accessor with given
@@ -322,33 +384,9 @@ test("authenticated functions", async () => {
322384});
323385```
324386
325- ## Mocking ` fetch ` calls
326-
327- You can use Vitest's
328- [ vi.stubGlobal] ( https://vitest.dev/guide/mocking.html#globals ) method:
329-
330- ``` ts title="convex/ai.test.ts"
331- import { expect , test , vi } from " vitest" ;
332- import { convexTest } from " ../index" ;
333- import { api } from " ./_generated/api" ;
334- import schema from " ./schema" ;
335-
336- test (" ai" , async () => {
337- const t = convexTest (schema );
338-
339- vi .stubGlobal (
340- " fetch" ,
341- vi .fn (async () => ({ text : async () => " I am the overlord" }) as Response ),
342- );
343-
344- const reply = await t .action (api .messages .sendAIMessage , { prompt: " hello" });
345- expect (reply ).toEqual (" I am the overlord" );
387+ ## Vitest tips
346388
347- vi .unstubAllGlobals ();
348- });
349- ```
350-
351- ## Asserting results
389+ ### Asserting results
352390
353391See Vitest's [ Expect] ( https://vitest.dev/api/expect.html ) reference.
354392
@@ -375,7 +413,33 @@ test("messages validation", async () => {
375413});
376414```
377415
378- ## Measuring test coverage
416+ ### Mocking ` fetch ` calls
417+
418+ You can use Vitest's
419+ [ vi.stubGlobal] ( https://vitest.dev/guide/mocking.html#globals ) method:
420+
421+ ``` ts title="convex/ai.test.ts"
422+ import { expect , test , vi } from " vitest" ;
423+ import { convexTest } from " ../index" ;
424+ import { api } from " ./_generated/api" ;
425+ import schema from " ./schema" ;
426+
427+ test (" ai" , async () => {
428+ const t = convexTest (schema );
429+
430+ vi .stubGlobal (
431+ " fetch" ,
432+ vi .fn (async () => ({ text : async () => " I am the overlord" }) as Response ),
433+ );
434+
435+ const reply = await t .action (api .messages .sendAIMessage , { prompt: " hello" });
436+ expect (reply ).toEqual (" I am the overlord" );
437+
438+ vi .unstubAllGlobals ();
439+ });
440+ ```
441+
442+ ### Measuring test coverage
379443
380444You can get a printout of the code coverage provided by your tests. Besides
381445answering the question "how much of my code is covered by tests" it is also
@@ -393,69 +457,12 @@ install a required dependency the first time you run it.
393457 />
394458</p >
395459
396- ## Debugging tests
460+ ### Debugging tests
397461
398462You can attach a debugger to the running tests. Read the Vitest
399- [ Debugging docs] ( https://vitest.dev/guide/debugging.html ) and then
400- use  ; <CodeWithCopyButton text = " npm run test:debug" />.
401-
402- ## Multiple environments
403-
404- If you want to use Vitest to test both your Convex functions and your React
405- frontend, you might want to use multiple Vitest environments depending on the
406- test file location via
407- [ environmentMatchGlobs] ( https://vitest.dev/config/#environmentmatchglobs ) :
408-
409- ``` ts title="vitest.config.mts"
410- import { defineConfig } from " vitest/config" ;
411-
412- export default defineConfig ({
413- test: {
414- environmentMatchGlobs: [
415- // all tests in convex/ will run in edge-runtime
416- [" convex/**" , " edge-runtime" ],
417- // all other tests use jsdom
418- [" **" , " jsdom" ],
419- ],
420- server: { deps: { inline: [" convex-test" ] } },
421- },
422- });
423- ```
424-
425- ## Custom ` convex/ ` folder name or location
426-
427- If your project has a
428- [ different name or location configured] ( /production/project-configuration.mdx#changing-the-convex-folder-name-or-location )
429- for the ` convex/ ` folder in ` convex.json ` , you need to call
430- [ ` import.meta.glob ` ] ( https://vitejs.dev/guide/features#glob-import ) and pass the
431- result as the second argument to ` convexTest ` .
432-
433- The argument to ` import.meta.glob ` must be a glob pattern matching all the files
434- containing your Convex functions. The paths are relative to the test file in
435- which ` import.meta.glob ` is called. It's best to do this in one place in your
436- custom functions folder:
437-
438- ``` ts title="src/convex/test.setup.ts"
439- /// <reference types = " vite/client" />
440- export const modules = import .meta .glob (" ./**/!(*.*.*)*.*s" );
441- ```
442-
443- This example glob pattern includes all files with a single extension ending in
444- ` s ` (like ` js ` or ` ts ` ) in the ` src/convex ` folder and any of its children.
445-
446- Use the result in your tests:
463+ [ Debugging docs] ( https://vitest.dev/guide/debugging.html ) and then use
447464
448- ``` ts title="src/convex/messages.test.ts"
449- import { convexTest } from " convex-test" ;
450- import { test } from " vitest" ;
451- import schema from " ./schema" ;
452- import { modules } from " ./test.setup" ;
453-
454- test (" some behavior" , async () => {
455- const t = convexTest (schema , modules );
456- // use `t`...
457- });
458- ```
465+ <CodeWithCopyButton text = " npm run test:debug" />.
459466
460467## Limitations
461468
0 commit comments