Guides
Testing Sidetrack

Testing Sidetrack

Sidetrack provides multiple test utilities function under the SidetrackTest class.

The SidetrackTest class extends all the functions under Sidetrack, but also exposes these helpful utils:

  1. runJob
  2. runJobs
  3. listJobs
  4. listJobStatuses

Here's some common scenarios when testing your background jobs.

Running a job

In your tests, if you don't run sidetrack.start(), then Sidetrack won't poll your database for new jobs. You can manually run a job with the runJob function.

ts
import { SidetrackTest } from "sidetrack";
import { expect, it } from "vitest";
 
it("job runs", async () => {
const sidetrack = new SidetrackTest<{
userOnboarding: { email: string };
}>({
databaseOptions: {
connectionString: process.env["DATABASE_URL"]!,
},
queues: {
userOnboarding: {
handler: async (job) => {
console.log("ran job");
},
},
},
});
 
const job = await sidetrack.insertJob("userOnboarding", {
email: "a@example.com",
});
// this job stays in scheduled and won't be run because we haven't run sidetrack.start()
expect((await sidetrack.getJob(job.id)).status).toBe("scheduled");
 
// You decide when to run the job
await sidetrack.runJob(job.id);
expect((await sidetrack.getJob(job.id)).status).toBe("completed");
});
ts
import { SidetrackTest } from "sidetrack";
import { expect, it } from "vitest";
 
it("job runs", async () => {
const sidetrack = new SidetrackTest<{
userOnboarding: { email: string };
}>({
databaseOptions: {
connectionString: process.env["DATABASE_URL"]!,
},
queues: {
userOnboarding: {
handler: async (job) => {
console.log("ran job");
},
},
},
});
 
const job = await sidetrack.insertJob("userOnboarding", {
email: "a@example.com",
});
// this job stays in scheduled and won't be run because we haven't run sidetrack.start()
expect((await sidetrack.getJob(job.id)).status).toBe("scheduled");
 
// You decide when to run the job
await sidetrack.runJob(job.id);
expect((await sidetrack.getJob(job.id)).status).toBe("completed");
});

Running jobs in a queue

While runJob only allows you to run a single job, often you may want to run all the jobs on a queue.

ts
// You can run jobs on a single queue
await sidetrack.runJobs({ queue: "userOnboarding" });
ts
// You can run jobs on a single queue
await sidetrack.runJobs({ queue: "userOnboarding" });

By default, runJobs runs jobs that are scheduled in the past or present. If you want to include future jobs you may pass an option for {includeFutureJobs: true}

ts
// Will run all jobs on this queue, including ones with scheduledAt in the future
await sidetrack.runJobs(
{ queue: "userOnboarding" },
{ includeFutureJobs: true },
);
ts
// Will run all jobs on this queue, including ones with scheduledAt in the future
await sidetrack.runJobs(
{ queue: "userOnboarding" },
{ includeFutureJobs: true },
);

Listing jobs

You may want to assert that certain jobs exist on a queue(s). listJob accepts a single queue or list of queues, and returns a list of jobs.

ts
await sidetrack.insert("userOnboarding", { email: "a@example.com" });
await sidetrack.insert("userOnboarding", { email: "b@example.com" });
// You can run jobs on a single queue
const jobs = await sidetrack.listJobs({ queue: "userOnboarding" });
expect(jobs.length).toBe(2);
ts
await sidetrack.insert("userOnboarding", { email: "a@example.com" });
await sidetrack.insert("userOnboarding", { email: "b@example.com" });
// You can run jobs on a single queue
const jobs = await sidetrack.listJobs({ queue: "userOnboarding" });
expect(jobs.length).toBe(2);

Listing job statuses

listJobStatuses provides a convenient way to know the breakdown of all the jobs and their statuses.

ts
const job1 = await sidetrack.insert("userOnboarding", {
email: "a@example.com",
});
await sidetrack.insert("userOnboarding", { email: "b@example.com" });
await sidetrack.runJob(job1.id);
// since we only ran job 1
// we should expect 1 job to be completed, 1 job to be in scheduled
const jobs = await sidetrack.listJobsStatuses("userOnboarding");
expect(jobs).toBeObject({ scheduled: 1, completed: 1 });
ts
const job1 = await sidetrack.insert("userOnboarding", {
email: "a@example.com",
});
await sidetrack.insert("userOnboarding", { email: "b@example.com" });
await sidetrack.runJob(job1.id);
// since we only ran job 1
// we should expect 1 job to be completed, 1 job to be in scheduled
const jobs = await sidetrack.listJobsStatuses("userOnboarding");
expect(jobs).toBeObject({ scheduled: 1, completed: 1 });