Skip to content

Commit c52aca0

Browse files
authored
Use convex-test defineTestApp instead of anyApi testApi cast (#114)
Install convex-test 0.0.61. convex was already at 1.46.0, which satisfies its peer dependency.
1 parent 7c9fb69 commit c52aca0

7 files changed

Lines changed: 91 additions & 124 deletions

File tree

‎package-lock.json‎

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
"chokidar-cli": "3.0.0",
101101
"convex": "1.46.0",
102102
"convex-helpers": "0.1.127",
103-
"convex-test": "0.0.49",
103+
"convex-test": "0.0.61",
104104
"eslint": "9.39.2",
105105
"eslint-plugin-react": "7.37.5",
106106
"eslint-plugin-react-hooks": "7.0.1",

‎src/client/_generated/_ignore.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎src/client/index.test.ts‎

Lines changed: 52 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,28 @@
11
import { describe, expect, test } from "vitest";
22
import { 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";
163
import { v } from "convex/values";
174
import { defineSchema } from "convex/server";
18-
import { components, initConvexTest } from "./setup.test.js";
5+
import { defineTestApp } from "convex-test";
6+
import componentTest from "../test.js";
197
import { openai } from "@ai-sdk/openai";
208
import { MockLanguageModelV4 } from "ai/test";
219

2210
// The schema for the tests
2311
const 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

159148
function dummyEmbeddings(text: string) {
160149
return Array.from({ length: 1536 }, (_, i) =>
@@ -164,8 +153,8 @@ function dummyEmbeddings(text: string) {
164153

165154
describe("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?",

‎src/client/setup.test.ts‎

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)