Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.context/
18 changes: 15 additions & 3 deletions example/convex/test/scenarios/enqueueOcc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,25 @@ export const storm = internalAction({
blockerMs = 60_000,
},
) => {
if (!Number.isInteger(durationMs) || durationMs < 1_000 || durationMs > 120_000) {
if (
!Number.isInteger(durationMs) ||
durationMs < 1_000 ||
durationMs > 120_000
) {
throw new Error("durationMs must be an integer from 1,000 to 120,000");
}
if (!Number.isInteger(concurrency) || concurrency < 1 || concurrency > 100) {
if (
!Number.isInteger(concurrency) ||
concurrency < 1 ||
concurrency > 100
) {
throw new Error("concurrency must be an integer from 1 to 100");
}
if (!Number.isInteger(payloadBytes) || payloadBytes < 0 || payloadBytes > 500_000) {
if (
!Number.isInteger(payloadBytes) ||
payloadBytes < 0 ||
payloadBytes > 500_000
) {
throw new Error("payloadBytes must be an integer from 0 to 500,000");
}

Expand Down
69 changes: 69 additions & 0 deletions src/client/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import {
makeFunctionReference,
type GenericDataModel,
type GenericMutationCtx,
} from "convex/server";
import { type Infer, v } from "convex/values";
import { expectTypeOf, test } from "vitest";
import {
type EnqueueOptions,
type OnCompleteArgs,
type WorkId,
type Workpool,
vOnCompleteArgs,
} from "./index.js";

type MutationCtx = GenericMutationCtx<GenericDataModel>;
const action = makeFunctionReference<"action", { value: number }, number>(
"work:action",
);
const onComplete = makeFunctionReference<
"mutation",
OnCompleteArgs<{ label: string }, number>
>("work:onComplete");

test("onComplete retains context and return value types", () => {
// tsc checks these call sites; the function is never invoked at runtime.
expectTypeOf((pool: Workpool, ctx: MutationCtx) => {
void pool.enqueueAction(
ctx,
action,
{ value: 1 },
// @ts-expect-error The callback requires a string label.
{ onComplete, context: { label: 1 } },
);
const stringAction = makeFunctionReference<
"action",
{ value: number },
string
>("work:stringAction");
void pool.enqueueAction(
ctx,
// @ts-expect-error The callback requires a number result.
stringAction,
{ value: 1 },
{ onComplete, context: { label: "job" } },
);
return pool.enqueueAction(
ctx,
action,
{ value: 1 },
{ onComplete, context: { label: "job" } },
);
}).returns.toEqualTypeOf<Promise<WorkId>>();
});

test("completion validators preserve the declared context and result", () => {
const _args = vOnCompleteArgs(v.object({ label: v.string() }), v.number());
type Args = Infer<typeof _args>;
expectTypeOf<Args["context"]>().toEqualTypeOf<{ label: string }>();
expectTypeOf<
Extract<Args["result"], { kind: "success" }>["returnValue"]
>().toEqualTypeOf<number>();
});

test("runAt and runAfter are mutually exclusive", () => {
// @ts-expect-error Only one scheduling option can be specified.
const options: EnqueueOptions = { runAt: 1, runAfter: 2 };
expectTypeOf(options).toMatchTypeOf<EnqueueOptions>();
});
10 changes: 0 additions & 10 deletions vitest.config.js

This file was deleted.

3 changes: 1 addition & 2 deletions vitest.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "edge-runtime",
exclude: ["**/node_modules/**", "dist/**"],
// globals: true,
include: ["src/**/*.test.ts", "example/convex/**/*.test.ts"],
},
});
Loading