diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e160118b..0a4c3a48 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -79,5 +79,9 @@ jobs: complete: runs-on: ubuntu-latest needs: [test, lint] + if: always() steps: + - name: Fail if any required job did not succeed + if: ${{ needs.test.result != 'success' || needs.lint.result != 'success' }} + run: exit 1 - run: echo "Done!" diff --git a/__tests__/core/connection.ts b/__tests__/core/connection.ts index d6f0e91e..bbc50abd 100644 --- a/__tests__/core/connection.ts +++ b/__tests__/core/connection.ts @@ -37,7 +37,7 @@ describe("connection", () => { let prefixedConnection: Connection; let prefixedRedis: Redis; beforeAll(async () => { - prefixedRedis = new Redis(null, null, { + prefixedRedis = new Redis({ keyPrefix: "customNamespace:", db: db, }); diff --git a/__tests__/core/queue.ts b/__tests__/core/queue.ts index 40227452..0c3499ef 100644 --- a/__tests__/core/queue.ts +++ b/__tests__/core/queue.ts @@ -41,9 +41,9 @@ describe("queue", () => { test("can add a normal job", async () => { await queue.enqueue(specHelper.queue, "someJob", [1, 2, 3]); - let obj = await specHelper.popFromQueue(); - expect(obj).toBeDefined(); - obj = JSON.parse(obj); + const raw = await specHelper.popFromQueue(); + expect(raw).toBeDefined(); + const obj = JSON.parse(raw!); expect(obj.class).toBe("someJob"); expect(obj.args).toEqual([1, 2, 3]); }); @@ -60,7 +60,7 @@ describe("queue", () => { specHelper.namespace + ":delayed:" + "10", ); expect(str).toBeDefined(); - const job = JSON.parse(str) as ParsedJob; + const job = JSON.parse(str!) as ParsedJob; expect(job.class).toBe("someJob"); expect(job.args).toEqual([1, 2, 3]); }); @@ -78,7 +78,7 @@ describe("queue", () => { specHelper.namespace + ":delayed:" + "10", ); expect(str).toBeDefined(); - const job = JSON.parse(str) as ParsedJob; + const job = JSON.parse(str!) as ParsedJob; expect(job.class).toBe("someJob"); expect(job.args).toEqual([1, 2, 3]); }); @@ -122,7 +122,7 @@ describe("queue", () => { specHelper.namespace + ":delayed:" + now, ); expect(str).toBeDefined(); - const job = JSON.parse(str) as ParsedJob; + const job = JSON.parse(str!) as ParsedJob; expect(job.class).toBe("someJob"); expect(job.args).toEqual([1, 2, 3]); }); @@ -142,7 +142,7 @@ describe("queue", () => { specHelper.namespace + ":delayed:" + now, ); expect(str).toBeDefined(); - const job = JSON.parse(str) as ParsedJob; + const job = JSON.parse(str!) as ParsedJob; expect(job.class).toBe("someJob"); expect(job.args).toEqual([1, 2, 3]); }); @@ -244,15 +244,15 @@ describe("queue", () => { // @ts-ignore await queue.enqueue(specHelper.queue, "someJob", 1); const obj = await specHelper.popFromQueue(); - expect(JSON.parse(obj).args).toEqual([1]); + expect(JSON.parse(obj!).args).toEqual([1]); }); test("allows omitting arguments when enqueuing", async () => { await queue.enqueue(specHelper.queue, "noParams"); const length = await queue.length(specHelper.queue); expect(length).toBe(1); - let obj = await specHelper.popFromQueue(); - obj = JSON.parse(obj); + const raw = await specHelper.popFromQueue(); + const obj = JSON.parse(raw!); expect(obj.class).toBe("noParams"); expect(Array.isArray(obj.args)).toBe(true); expect(obj.args).toHaveLength(0); @@ -608,7 +608,7 @@ describe("queue", () => { let str = await specHelper.redis.rpop( specHelper.namespace + ":" + "failed", ); - const failedData = JSON.parse(str) as ParsedFailedJobPayload; + const failedData = JSON.parse(str!) as ParsedFailedJobPayload; expect(failedData.queue).toBe(specHelper.queue); expect(failedData.exception).toBe( "Worker Timeout (killed manually)", @@ -660,16 +660,16 @@ describe("queue", () => { const errorPayload = await queue.forceCleanWorker(workerA.name); - expect(errorPayload.worker).toBe("workerA"); - expect(errorPayload.queue).toBe("test_queue"); - expect(errorPayload.payload.class).toBe("slowJob"); - expect(errorPayload.exception).toBe( + expect(errorPayload!.worker).toBe("workerA"); + expect(errorPayload!.queue).toBe("test_queue"); + expect(errorPayload!.payload.class).toBe("slowJob"); + expect(errorPayload!.exception).toBe( "Worker Timeout (killed manually)", ); - expect(errorPayload.backtrace[0]).toMatch(/killed by/); - expect(errorPayload.backtrace[1]).toBe("queue#forceCleanWorker"); - expect(errorPayload.backtrace[2]).toBe("node-resque"); - expect(errorPayload.failed_at).toBeTruthy(); + expect(errorPayload!.backtrace[0]).toMatch(/killed by/); + expect(errorPayload!.backtrace[1]).toBe("queue#forceCleanWorker"); + expect(errorPayload!.backtrace[2]).toBe("node-resque"); + expect(errorPayload!.failed_at).toBeTruthy(); return resolve(null); }); diff --git a/__tests__/core/scheduler.ts b/__tests__/core/scheduler.ts index c8efac44..f4fced0a 100644 --- a/__tests__/core/scheduler.ts +++ b/__tests__/core/scheduler.ts @@ -132,9 +132,9 @@ describe("scheduler", () => { [1, 2, 3], ); await scheduler.poll(); - let obj = await specHelper.popFromQueue(); - expect(obj).toBeDefined(); - obj = JSON.parse(obj); + const raw = await specHelper.popFromQueue(); + expect(raw).toBeDefined(); + const obj = JSON.parse(raw!); expect(obj.class).toBe("someJob"); expect(obj.args).toEqual([1, 2, 3]); await scheduler.end(); @@ -157,11 +157,11 @@ describe("scheduler", () => { let worker: Worker; const jobs = { stuck: { - perform: async function () { + perform: async function (this: Worker) { await new Promise((resolve) => { // stop the worker from checking in, like the process crashed // don't resolve - clearTimeout(this.pingTimer); + if (this.pingTimer) clearTimeout(this.pingTimer); }); }, } as Job, @@ -213,7 +213,7 @@ describe("scheduler", () => { const str = await specHelper.redis.rpop( specHelper.namespace + ":" + "failed", ); - const failed = JSON.parse(str) as ParsedFailedJobPayload; + const failed = JSON.parse(str!) as ParsedFailedJobPayload; expect(failed.queue).toBe("stuckJobs"); expect(failed.exception).toBe( "Worker Timeout (killed manually)", diff --git a/__tests__/core/worker.ts b/__tests__/core/worker.ts index 5f05fd3a..4bf58624 100644 --- a/__tests__/core/worker.ts +++ b/__tests__/core/worker.ts @@ -313,7 +313,7 @@ describe("worker", () => { let str = await specHelper.redis.rpop( specHelper.namespace + ":" + "failed", ); - const data = JSON.parse(str) as ParsedFailedJobPayload; + const data = JSON.parse(str!) as ParsedFailedJobPayload; expect(data.queue).toBe(specHelper.queue); expect(data.exception).toBe("Error"); expect(data.error).toBe('No job defined for class "somethingFake"'); @@ -324,7 +324,7 @@ describe("worker", () => { const nowInSeconds = Math.round(new Date().getTime() / 1000); await worker.start(); await new Promise((resolve) => - setTimeout(resolve, worker.options.timeout * 2), + setTimeout(resolve, worker.options.timeout! * 2), ); const pingKey = worker.connection.key( "worker", @@ -332,7 +332,7 @@ describe("worker", () => { worker.name, ); const firstPayload = JSON.parse( - await specHelper.redis.get(pingKey), + (await specHelper.redis.get(pingKey))!, ); expect(firstPayload.name).toEqual(worker.name); expect(firstPayload.time).toBeGreaterThanOrEqual(nowInSeconds); @@ -346,7 +346,7 @@ describe("worker", () => { }); const secondPayload = JSON.parse( - await specHelper.redis.get(pingKey), + (await specHelper.redis.get(pingKey))!, ); expect(secondPayload.name).toEqual(worker.name); expect(secondPayload.time).toBeGreaterThanOrEqual( diff --git a/__tests__/plugins/jobLock.ts b/__tests__/plugins/jobLock.ts index d96c20af..886aefae 100644 --- a/__tests__/plugins/jobLock.ts +++ b/__tests__/plugins/jobLock.ts @@ -202,7 +202,7 @@ describe("plugins", () => { Math.round(timestamps[0] / 1000), ); expect(str).toBeDefined(); - const dealyedJob = JSON.parse(str) as ParsedJob; + const dealyedJob = JSON.parse(str!) as ParsedJob; expect(dealyedJob.class).toBe("slowAdd"); expect(dealyedJob.args).toEqual([1, 2]); diff --git a/__tests__/plugins/retry.ts b/__tests__/plugins/retry.ts index eafb7475..4471c8c9 100644 --- a/__tests__/plugins/retry.ts +++ b/__tests__/plugins/retry.ts @@ -356,7 +356,7 @@ describe("plugins", () => { `${specHelper.namespace}:failure-resque-retry:brokenJob:1-2`, ); expect(String(retryAttempts)).toBe("0"); - const failure = JSON.parse(failureData) as ParsedFailedJobPayload; + const failure = JSON.parse(failureData!) as ParsedFailedJobPayload; expect(failure.payload).toEqual([1, 2]); expect(failure.exception).toBe("Error: BUSTED"); expect(failure.worker).toBe("brokenJob"); diff --git a/__tests__/utils/specHelper.ts b/__tests__/utils/specHelper.ts index 62627d1b..19575577 100644 --- a/__tests__/utils/specHelper.ts +++ b/__tests__/utils/specHelper.ts @@ -1,17 +1,48 @@ import Redis from "ioredis"; import * as NodeResque from "../../src/index"; +import { ConnectionOptions } from "../../src/types/options"; const namespace = `resque-test-${process.env.JEST_WORKER_ID || 0}`; -const queue = "test_queue"; +const queueName = "test_queue"; const pkg = "ioredis"; +interface SpecConnectionDetails extends ConnectionOptions { + pkg: string; + host: string; + password: string; + port: number; + database: number; + namespace: string; + options?: { [key: string]: any }; + redis?: Redis; +} + +interface SpecHelper { + pkg: string; + namespace: string; + queue: string; + timeout: number; + smallTimeout: number; + redis: Redis; + connectionDetails: SpecConnectionDetails; + worker: NodeResque.Worker; + scheduler: NodeResque.Scheduler; + connect: () => Promise; + cleanup: () => Promise; + disconnect: () => Promise; + startAll: (jobs: NodeResque.Jobs) => Promise; + endAll: () => Promise; + popFromQueue: () => Promise; + cleanConnectionDetails: () => { database: number; namespace: string }; +} + const SpecHelper = { pkg: pkg, namespace: namespace, - queue: queue, + queue: queueName, timeout: 500, smallTimeout: 3, - redis: null as Redis, + redis: null as unknown as Redis, connectionDetails: { pkg: pkg, host: process.env.REDIS_HOST || "127.0.0.1", @@ -19,13 +50,13 @@ const SpecHelper = { port: 6379, database: parseInt(process.env.JEST_WORKER_ID || "0"), namespace: namespace, - // looping: true - }, + } as SpecConnectionDetails, + worker: null as unknown as NodeResque.Worker, + scheduler: null as unknown as NodeResque.Scheduler, - connect: async function () { + connect: async function (this: SpecHelper) { if (!this.connectionDetails.options) this.connectionDetails.options = {}; - this.connectionDetails.options.db = - this.connectionDetails?.options?.database; + this.connectionDetails.options.db = this.connectionDetails.database; this.redis = new Redis( this.connectionDetails.port, this.connectionDetails.host, @@ -43,30 +74,28 @@ const SpecHelper = { this.connectionDetails.redis = this.redis; }, - cleanup: async function () { + cleanup: async function (this: SpecHelper) { const keys = await this.redis.keys(this.namespace + "*"); if (keys.length > 0) await this.redis.del(keys); }, - disconnect: async function () { + disconnect: async function (this: SpecHelper) { if (typeof this.redis.disconnect === "function") { - await this.redis.disconnect(); + this.redis.disconnect(); } else if (typeof this.redis.quit === "function") { await this.redis.quit(); } - delete this.redis; + this.redis = null as unknown as Redis; delete this.connectionDetails.redis; }, - startAll: async function (jobs: NodeResque.Jobs) { + startAll: async function (this: SpecHelper, jobs: NodeResque.Jobs) { const Worker = NodeResque.Worker; const Scheduler = NodeResque.Scheduler; - const Queue = NodeResque.Queue; this.worker = new Worker( { - //@ts-ignore connection: { redis: this.redis }, queues: this.queue, timeout: this.timeout, @@ -81,21 +110,18 @@ const SpecHelper = { }); await this.scheduler.connect(); - - this.queue = new Queue({ connection: { redis: this.redis } }); - await this.queue.connect(); }, - endAll: async function () { + endAll: async function (this: SpecHelper) { await this.worker.end(); await this.scheduler.end(); }, - popFromQueue: async function () { + popFromQueue: async function (this: SpecHelper) { return this.redis.lpop(this.namespace + ":queue:" + this.queue); }, - cleanConnectionDetails: function () { + cleanConnectionDetails: function (this: SpecHelper) { interface connectionDetails { database: number; namespace: string; diff --git a/jest.config.js b/jest.config.js index e616686b..c1ffc6d6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,6 +2,6 @@ module.exports = { maxWorkers: "50%", testPathIgnorePatterns: ["/__tests__/utils"], transform: { - "^.+\\.ts?$": "ts-jest", + "^.+\\.ts?$": ["ts-jest", { tsconfig: "tsconfig.test.json" }], }, }; diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 00000000..b949717b --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": ".", + "types": ["jest", "node"] + }, + "include": ["./src/**/*", "./__tests__/**/*"] +}