11import { describe , expect , test } from "vitest" ;
22import { RAG } from "./index.js" ;
3- import type { DataModelFromSchemaDefinition } from "convex/server" ;
4- import {
5- anyApi ,
6- queryGeneric ,
7- mutationGeneric ,
8- actionGeneric ,
9- } from "convex/server" ;
10- import type {
11- ApiFromModules ,
12- ActionBuilder ,
13- MutationBuilder ,
14- QueryBuilder ,
15- } from "convex/server" ;
163import { v } from "convex/values" ;
174import { defineSchema } from "convex/server" ;
18- import { components , initConvexTest } from "./setup.test.js" ;
5+ import { defineTestApp } from "convex-test" ;
6+ import componentTest from "../test.js" ;
197import { openai } from "@ai-sdk/openai" ;
208import { MockLanguageModelV4 } from "ai/test" ;
219
2210// The schema for the tests
2311const schema = defineSchema ( { } ) ;
24- type DataModel = DataModelFromSchemaDefinition < typeof schema > ;
25- // type DatabaseReader = GenericDatabaseReader<DataModel>;
26- const query = queryGeneric as QueryBuilder < DataModel , "public" > ;
27- const mutation = mutationGeneric as MutationBuilder < DataModel , "public" > ;
28- const action = actionGeneric as ActionBuilder < DataModel , "public" > ;
12+ const app = defineTestApp ( {
13+ schema,
14+ components : {
15+ rag : componentTest ,
16+ } ,
17+ } ) ;
2918
30- const rag = new RAG ( components . rag , {
19+ const rag = new RAG ( app . components . rag , {
3120 embeddingDimension : 1536 ,
3221 textEmbeddingModel : openai . embedding ( "text-embedding-3-small" ) ,
3322 filterNames : [ "simpleString" , "arrayOfStrings" , "customObject" ] ,
3423} ) ;
3524
36- export const findEntryByContentHash = query ( {
25+ const findEntryByContentHash = app . query ( {
3726 args : { namespace : v . string ( ) , key : v . string ( ) , contentHash : v . string ( ) } ,
3827 handler : async ( ctx , args ) => {
3928 return rag . findEntryByContentHash ( ctx , {
@@ -44,7 +33,7 @@ export const findEntryByContentHash = query({
4433 } ,
4534} ) ;
4635
47- export const add = mutation ( {
36+ const add = app . mutation ( {
4837 args : {
4938 key : v . string ( ) ,
5039 chunks : v . array (
@@ -82,7 +71,7 @@ export const add = mutation({
8271 } ,
8372} ) ;
8473
85- export const search = action ( {
74+ const search = app . action ( {
8675 args : {
8776 embedding : v . array ( v . number ( ) ) ,
8877 namespace : v . string ( ) ,
@@ -123,7 +112,7 @@ const mockModel = new MockLanguageModelV4({
123112 } ,
124113} ) ;
125114
126- export const generate = action ( {
115+ const generate = app . action ( {
127116 args : {
128117 embedding : v . array ( v . number ( ) ) ,
129118 namespace : v . string ( ) ,
@@ -147,14 +136,14 @@ export const generate = action({
147136 } ,
148137} ) ;
149138
150- const testApi : ApiFromModules < {
139+ const { api , createTest } = app . defineModules ( {
151140 fns : {
152- findEntryByContentHash : typeof findEntryByContentHash ;
153- add : typeof add ;
154- search : typeof search ;
155- generate : typeof generate ;
156- } ;
157- } > [ "fns" ] = anyApi [ "index.test" ] as any ;
141+ findEntryByContentHash,
142+ add,
143+ search,
144+ generate,
145+ } ,
146+ } ) ;
158147
159148function dummyEmbeddings ( text : string ) {
160149 return Array . from ( { length : 1536 } , ( _ , i ) =>
@@ -164,8 +153,8 @@ function dummyEmbeddings(text: string) {
164153
165154describe ( "RAG thick client" , ( ) => {
166155 test ( "should add a entry and be able to list it" , async ( ) => {
167- const t = initConvexTest ( schema ) ;
168- const { entryId, status, usage } = await t . mutation ( testApi . add , {
156+ const t = createTest ( ) ;
157+ const { entryId, status, usage } = await t . mutation ( api . fns . add , {
169158 key : "test" ,
170159 chunks : [
171160 { text : "A" , metadata : { } , embedding : dummyEmbeddings ( "A" ) } ,
@@ -191,8 +180,8 @@ describe("RAG thick client", () => {
191180 } ) ;
192181
193182 test ( "should work from a test function" , async ( ) => {
194- const t = initConvexTest ( schema ) ;
195- await t . mutation ( testApi . add , {
183+ const t = createTest ( ) ;
184+ await t . mutation ( api . fns . add , {
196185 key : "test" ,
197186 chunks : [
198187 { text : "A" , metadata : { } , embedding : dummyEmbeddings ( "A" ) } ,
@@ -205,8 +194,8 @@ describe("RAG thick client", () => {
205194 } ) ;
206195
207196 test ( "should be able to re-add an entry with the same key" , async ( ) => {
208- const t = initConvexTest ( schema ) ;
209- const { entryId, status, usage } = await t . mutation ( testApi . add , {
197+ const t = createTest ( ) ;
198+ const { entryId, status, usage } = await t . mutation ( api . fns . add , {
210199 key : "test" ,
211200 chunks : [ { text : "A" , metadata : { } , embedding : dummyEmbeddings ( "A" ) } ] ,
212201 namespace : "test" ,
@@ -218,15 +207,15 @@ describe("RAG thick client", () => {
218207 entryId : entryId2 ,
219208 status : status2 ,
220209 usage : usage2 ,
221- } = await t . mutation ( testApi . add , {
210+ } = await t . mutation ( api . fns . add , {
222211 key : "test" ,
223212 chunks : [ { text : "A" , metadata : { } , embedding : dummyEmbeddings ( "A" ) } ] ,
224213 namespace : "test" ,
225214 } ) ;
226215 expect ( entryId2 ) . toBeDefined ( ) ;
227216 expect ( status2 ) . toBe ( "ready" ) ;
228217 expect ( usage2 ) . toEqual ( { tokens : 0 } ) ;
229- const { page } = await t . query ( components . rag . chunks . list , {
218+ const { page } = await t . query ( app . components . rag . chunks . list , {
230219 entryId : entryId2 ,
231220 paginationOpts : { numItems : 10 , cursor : null } ,
232221 order : "asc" ,
@@ -239,10 +228,10 @@ describe("RAG thick client", () => {
239228
240229 describe ( "text formatting validation" , ( ) => {
241230 test ( "should format single entry with sequential chunks correctly" , async ( ) => {
242- const t = initConvexTest ( schema ) ;
231+ const t = createTest ( ) ;
243232
244233 // Add entry with sequential chunks
245- await t . mutation ( testApi . add , {
234+ await t . mutation ( api . fns . add , {
246235 key : "sequential-test" ,
247236 chunks : [
248237 {
@@ -266,7 +255,7 @@ describe("RAG thick client", () => {
266255 } ) ;
267256
268257 // Search and verify text format
269- const { text, entries, usage } = await t . action ( testApi . search , {
258+ const { text, entries, usage } = await t . action ( api . fns . search , {
270259 embedding : dummyEmbeddings ( "content" ) ,
271260 namespace : "format-test" ,
272261 limit : 10 ,
@@ -287,10 +276,10 @@ describe("RAG thick client", () => {
287276 } ) ;
288277
289278 test ( "should format single entry without title correctly" , async ( ) => {
290- const t = initConvexTest ( schema ) ;
279+ const t = createTest ( ) ;
291280
292281 // Add entry without title
293- await t . mutation ( testApi . add , {
282+ await t . mutation ( api . fns . add , {
294283 key : "no-title-test" ,
295284 chunks : [
296285 {
@@ -302,7 +291,7 @@ describe("RAG thick client", () => {
302291 namespace : "format-test-notitle" ,
303292 } ) ;
304293
305- const { text, entries, usage } = await t . action ( testApi . search , {
294+ const { text, entries, usage } = await t . action ( api . fns . search , {
306295 embedding : dummyEmbeddings ( "content" ) ,
307296 namespace : "format-test-notitle" ,
308297 limit : 10 ,
@@ -317,10 +306,10 @@ describe("RAG thick client", () => {
317306 } ) ;
318307
319308 test ( "should format non-sequential chunks with ellipsis separator" , async ( ) => {
320- const t = initConvexTest ( schema ) ;
309+ const t = createTest ( ) ;
321310
322311 // Add multiple entries to create potential non-sequential results
323- await t . mutation ( testApi . add , {
312+ await t . mutation ( api . fns . add , {
324313 key : "doc1" ,
325314 chunks : [
326315 {
@@ -355,7 +344,7 @@ describe("RAG thick client", () => {
355344 } ) ;
356345
357346 // Search with chunk context to potentially get non-sequential results
358- const { text, entries } = await t . action ( testApi . search , {
347+ const { text, entries } = await t . action ( api . fns . search , {
359348 embedding : dummyEmbeddings ( "A important chunk" ) ,
360349 namespace : "ellipsis-test" ,
361350 limit : 2 ,
@@ -374,10 +363,10 @@ describe("RAG thick client", () => {
374363 } ) ;
375364
376365 test ( "should format multiple entries with separators" , async ( ) => {
377- const t = initConvexTest ( schema ) ;
366+ const t = createTest ( ) ;
378367
379368 // Add two separate entries
380- await t . mutation ( testApi . add , {
369+ await t . mutation ( api . fns . add , {
381370 key : "first-doc" ,
382371 chunks : [
383372 {
@@ -390,7 +379,7 @@ describe("RAG thick client", () => {
390379 title : "First Document" ,
391380 } ) ;
392381
393- await t . mutation ( testApi . add , {
382+ await t . mutation ( api . fns . add , {
394383 key : "second-doc" ,
395384 chunks : [
396385 {
@@ -403,7 +392,7 @@ describe("RAG thick client", () => {
403392 title : "Second Document" ,
404393 } ) ;
405394
406- const { text, entries } = await t . action ( testApi . search , {
395+ const { text, entries } = await t . action ( api . fns . search , {
407396 embedding : dummyEmbeddings ( "document" ) ,
408397 namespace : "multi-entry-test" ,
409398 limit : 10 ,
@@ -421,10 +410,10 @@ describe("RAG thick client", () => {
421410 } ) ;
422411
423412 test ( "should format mixed entries (with and without titles)" , async ( ) => {
424- const t = initConvexTest ( schema ) ;
413+ const t = createTest ( ) ;
425414
426415 // Add entry with title
427- await t . mutation ( testApi . add , {
416+ await t . mutation ( api . fns . add , {
428417 key : "titled-doc" ,
429418 chunks : [
430419 {
@@ -438,7 +427,7 @@ describe("RAG thick client", () => {
438427 } ) ;
439428
440429 // Add entry without title
441- await t . mutation ( testApi . add , {
430+ await t . mutation ( api . fns . add , {
442431 key : "untitled-doc" ,
443432 chunks : [
444433 {
@@ -450,7 +439,7 @@ describe("RAG thick client", () => {
450439 namespace : "mixed-test" ,
451440 } ) ;
452441
453- const { text, entries } = await t . action ( testApi . search , {
442+ const { text, entries } = await t . action ( api . fns . search , {
454443 embedding : dummyEmbeddings ( "content" ) ,
455444 namespace : "mixed-test" ,
456445 limit : 10 ,
@@ -473,10 +462,10 @@ describe("RAG thick client", () => {
473462 } ) ;
474463
475464 test ( "should match exact README format specification" , async ( ) => {
476- const t = initConvexTest ( schema ) ;
465+ const t = createTest ( ) ;
477466
478467 // Create the exact scenario from README example
479- await t . mutation ( testApi . add , {
468+ await t . mutation ( api . fns . add , {
480469 key : "title1-doc" ,
481470 chunks : [
482471 {
@@ -494,7 +483,7 @@ describe("RAG thick client", () => {
494483 title : "Title 1" ,
495484 } ) ;
496485
497- await t . mutation ( testApi . add , {
486+ await t . mutation ( api . fns . add , {
498487 key : "title2-doc" ,
499488 chunks : [
500489 {
@@ -512,7 +501,7 @@ describe("RAG thick client", () => {
512501 title : "Title 2" ,
513502 } ) ;
514503
515- const { text, entries } = await t . action ( testApi . search , {
504+ const { text, entries } = await t . action ( api . fns . search , {
516505 embedding : dummyEmbeddings ( "contents" ) ,
517506 namespace : "readme-format-test" ,
518507 limit : 10 ,
@@ -555,8 +544,8 @@ Chunk 4 contents`,
555544 async function generateAndGetInstructions (
556545 args : { instructions ?: string ; system ?: string } = { } ,
557546 ) {
558- const t = initConvexTest ( schema ) ;
559- await t . mutation ( testApi . add , {
547+ const t = createTest ( ) ;
548+ await t . mutation ( api . fns . add , {
560549 key : "generate-test" ,
561550 chunks : [
562551 {
@@ -568,7 +557,7 @@ Chunk 4 contents`,
568557 namespace : "generate-test" ,
569558 } ) ;
570559 mockModel . doGenerateCalls . length = 0 ;
571- const text = await t . action ( testApi . generate , {
560+ const text = await t . action ( api . fns . generate , {
572561 embedding : dummyEmbeddings ( "contents" ) ,
573562 namespace : "generate-test" ,
574563 prompt : "What is in chunk 1?" ,
0 commit comments