Best JavaScript code snippet using fast-check-monorepo
TaskManager.test.ts
Source:TaskManager.test.ts  
1import type { PromiseCancellable } from '@matrixai/async-cancellable';2import type { ContextTimed } from '@/contexts/types';3import type { Task, TaskHandlerId, TaskPath } from '@/tasks/types';4import fs from 'fs';5import path from 'path';6import os from 'os';7import { DB } from '@matrixai/db';8import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';9import { Lock } from '@matrixai/async-locks';10import * as fc from 'fast-check';11import TaskManager from '@/tasks/TaskManager';12import * as tasksErrors from '@/tasks/errors';13import * as utils from '@/utils';14import { promise, sleep, never } from '@/utils';15describe(TaskManager.name, () => {16  const logger = new Logger(`${TaskManager.name} test`, LogLevel.WARN, [17    new StreamHandler(),18  ]);19  const handlerId = 'testId' as TaskHandlerId;20  let dataDir: string;21  let db: DB;22  beforeEach(async () => {23    dataDir = await fs.promises.mkdtemp(24      path.join(os.tmpdir(), 'polykey-test-'),25    );26    const dbPath = path.join(dataDir, 'db');27    db = await DB.createDB({28      dbPath,29      logger,30    });31  });32  afterEach(async () => {33    await db.stop();34    await fs.promises.rm(dataDir, { recursive: true, force: true });35  });36  test('can start and stop', async () => {37    const taskManager = await TaskManager.createTaskManager({38      db,39      lazy: false,40      logger,41    });42    await taskManager.stop();43    await taskManager.start();44    await taskManager.stop();45  });46  // TODO: use timer mocking to speed up testing47  test('tasks persist between Tasks object creation', async () => {48    let taskManager = await TaskManager.createTaskManager({49      db,50      lazy: true,51      logger,52    });53    const handlerId = 'asd' as TaskHandlerId;54    const handler = jest.fn();55    handler.mockImplementation(async () => {});56    taskManager.registerHandler(handlerId, handler);57    await taskManager.startProcessing();58    await taskManager.scheduleTask({59      handlerId,60      parameters: [1],61      delay: 1000,62      lazy: true,63    });64    await taskManager.scheduleTask({65      handlerId,66      parameters: [2],67      delay: 100,68      lazy: true,69    });70    await taskManager.scheduleTask({71      handlerId,72      parameters: [3],73      delay: 2000,74      lazy: true,75    });76    await taskManager.scheduleTask({77      handlerId,78      parameters: [4],79      delay: 10,80      lazy: true,81    });82    await taskManager.scheduleTask({83      handlerId,84      parameters: [5],85      delay: 10,86      lazy: true,87    });88    await taskManager.scheduleTask({89      handlerId,90      parameters: [6],91      delay: 10,92      lazy: true,93    });94    await taskManager.scheduleTask({95      handlerId,96      parameters: [7],97      delay: 3000,98      lazy: true,99    });100    await sleep(500);101    await taskManager.stop();102    expect(handler).toHaveBeenCalledTimes(4);103    handler.mockClear();104    taskManager = await TaskManager.createTaskManager({105      db,106      lazy: true,107      logger,108    });109    taskManager.registerHandler(handlerId, handler);110    await taskManager.startProcessing();111    await sleep(4000);112    await taskManager.stop();113    expect(handler).toHaveBeenCalledTimes(3);114  });115  // TODO: use timer mocking to speed up testing116  test('tasks persist between Tasks stop and starts', async () => {117    const taskManager = await TaskManager.createTaskManager({118      db,119      lazy: true,120      logger,121    });122    const handlerId = 'asd' as TaskHandlerId;123    const handler = jest.fn();124    handler.mockImplementation(async () => {});125    taskManager.registerHandler(handlerId, handler);126    await taskManager.startProcessing();127    await taskManager.scheduleTask({128      handlerId,129      parameters: [1],130      delay: 1000,131      lazy: true,132    });133    await taskManager.scheduleTask({134      handlerId,135      parameters: [2],136      delay: 100,137      lazy: true,138    });139    await taskManager.scheduleTask({140      handlerId,141      parameters: [3],142      delay: 2000,143      lazy: true,144    });145    await taskManager.scheduleTask({146      handlerId,147      parameters: [4],148      delay: 10,149      lazy: true,150    });151    await taskManager.scheduleTask({152      handlerId,153      parameters: [5],154      delay: 10,155      lazy: true,156    });157    await taskManager.scheduleTask({158      handlerId,159      parameters: [6],160      delay: 10,161      lazy: true,162    });163    await taskManager.scheduleTask({164      handlerId,165      parameters: [7],166      delay: 3000,167      lazy: true,168    });169    await sleep(500);170    await taskManager.stop();171    expect(handler).toHaveBeenCalledTimes(4);172    handler.mockClear();173    await taskManager.start();174    await sleep(4000);175    await taskManager.stop();176    expect(handler).toHaveBeenCalledTimes(3);177  });178  // FIXME: needs more experimenting to get this to work.179  test.skip('tasks persist between Tasks stop and starts TIMER FAKING', async () => {180    const taskManager = await TaskManager.createTaskManager({181      db,182      lazy: true,183      logger,184    });185    const handlerId = 'asd' as TaskHandlerId;186    const handler = jest.fn();187    handler.mockImplementation(async () => {});188    taskManager.registerHandler(handlerId, handler);189    // Console.log('a');190    await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 1000 });191    const t1 = await taskManager.scheduleTask({192      handlerId,193      parameters: [1],194      delay: 100,195      lazy: false,196    });197    await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 2000 });198    await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 10 });199    await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 10 });200    await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 10 });201    await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 3000 });202    // Setting up actions203    jest.useFakeTimers();204    setTimeout(async () => {205      // Console.log('starting processing');206      await taskManager.startProcessing();207    }, 0);208    setTimeout(async () => {209      // Console.log('stop');210      await taskManager.stop();211    }, 500);212    setTimeout(async () => {213      // Console.log('start');214      await taskManager.start();215    }, 1000);216    // Running tests here...217    // after 600 ms we should stop and 4 taskManager should've run218    jest.advanceTimersByTime(400);219    jest.runAllTimers();220    jest.advanceTimersByTime(200);221    // Console.log(jest.getTimerCount());222    jest.runAllTimers();223    // Console.log(jest.getTimerCount());224    await t1.promise();225    expect(handler).toHaveBeenCalledTimes(4);226    // After another 5000ms the rest should've been called227    handler.mockClear();228    jest.advanceTimersByTime(5000);229    // Expect(handler).toHaveBeenCalledTimes(3);230    jest.useRealTimers();231    await taskManager.stop();232  });233  test('activeLimit is enforced', async () => {234    const activeLimit = 5;235    const taskArb = fc236      .record({237        handlerId: fc.constant(handlerId),238        delay: fc.integer({ min: 10, max: 1000 }),239        parameters: fc.constant([]),240        priority: fc.integer({ min: -200, max: 200 }),241      })242      .noShrink();243    const scheduleCommandArb = taskArb.map(244      (taskSpec) => async (context: { taskManager: TaskManager }) => {245        return await context.taskManager.scheduleTask({246          ...taskSpec,247          lazy: false,248        });249      },250    );251    const sleepCommandArb = fc252      .integer({ min: 10, max: 100 })253      .noShrink()254      .map((value) => async (_context) => {255        await sleep(value);256      });257    const commandsArb = fc.array(258      fc.oneof(259        { arbitrary: scheduleCommandArb, weight: 2 },260        { arbitrary: sleepCommandArb, weight: 1 },261      ),262      { maxLength: 50, minLength: 50 },263    );264    await fc.assert(265      fc.asyncProperty(commandsArb, async (commands) => {266        const taskManager = await TaskManager.createTaskManager({267          activeLimit,268          db,269          fresh: true,270          logger,271        });272        const handler = jest.fn();273        handler.mockImplementation(async () => {274          await sleep(200);275        });276        taskManager.registerHandler(handlerId, handler);277        await taskManager.startProcessing();278        const context = { taskManager };279        // Scheduling taskManager to be scheduled280        const pendingTasks: Array<PromiseCancellable<any>> = [];281        for (const command of commands) {282          expect(taskManager.activeCount).toBeLessThanOrEqual(activeLimit);283          const task = await command(context);284          if (task != null) pendingTasks.push(task.promise());285        }286        let completed = false;287        const waitForcompletionProm = (async () => {288          await Promise.all(pendingTasks);289          completed = true;290        })();291        // Check for active tasks while tasks are still running292        while (!completed) {293          expect(taskManager.activeCount).toBeLessThanOrEqual(activeLimit);294          await Promise.race([sleep(100), waitForcompletionProm]);295        }296        await taskManager.stop();297      }),298      { interruptAfterTimeLimit: globalThis.defaultTimeout - 2000, numRuns: 3 },299    );300  });301  // TODO: Use fastCheck for this302  test('tasks are handled exactly once per task', async () => {303    const handler = jest.fn();304    const pendingLock = new Lock();305    const [lockReleaser] = await pendingLock.lock()();306    const resolvedTasks = new Map<number, number>();307    const totalTasks = 50;308    handler.mockImplementation(async (_ctx, _taskInfo, number: number) => {309      resolvedTasks.set(number, (resolvedTasks.get(number) ?? 0) + 1);310      if (resolvedTasks.size >= totalTasks) await lockReleaser();311    });312    const taskManager = await TaskManager.createTaskManager({313      db,314      handlers: { [handlerId]: handler },315      logger,316    });317    await db.withTransactionF(async (tran) => {318      for (let i = 0; i < totalTasks; i++) {319        await taskManager.scheduleTask(320          {321            handlerId,322            parameters: [i],323            lazy: true,324          },325          tran,326        );327      }328    });329    await pendingLock.waitForUnlock();330    // Each task called exactly once331    resolvedTasks.forEach((value) => expect(value).toEqual(1));332    await taskManager.stop();333    expect(handler).toHaveBeenCalledTimes(totalTasks);334  });335  // TODO: use fastCheck336  test('awaited taskPromises resolve', async () => {337    const handler = jest.fn();338    handler.mockImplementation(async (_ctx, _taskInfo, fail) => {339      if (!fail) throw Error('three');340      return fail;341    });342    const taskManager = await TaskManager.createTaskManager({343      db,344      handlers: { [handlerId]: handler },345      logger,346    });347    const taskSucceed = await taskManager.scheduleTask({348      handlerId,349      parameters: [true],350      lazy: false,351    });352    // Promise should succeed with result353    const taskSucceedP = taskSucceed!.promise();354    await expect(taskSucceedP).resolves.toBe(true);355    await taskManager.stop();356  });357  // TODO: use fastCheck358  test('awaited taskPromises reject', async () => {359    const handler = jest.fn();360    handler.mockImplementation(async (_ctx, _taskInfo, fail) => {361      if (!fail) throw Error('three');362      return fail;363    });364    const taskManager = await TaskManager.createTaskManager({365      db,366      handlers: { [handlerId]: handler },367      logger,368    });369    const taskFail = await taskManager.scheduleTask({370      handlerId,371      parameters: [false],372      lazy: false,373    });374    // Promise should throw375    const taskFailP = taskFail.promise();376    await expect(taskFailP).rejects.toThrow(Error);377    await taskManager.stop();378  });379  // TODO: use fastCheck380  test('awaited taskPromises resolve or reject', async () => {381    const handler = jest.fn();382    handler.mockImplementation(async (_ctx, _taskInfo, fail) => {383      if (!fail) throw Error('three');384      return fail;385    });386    const taskManager = await TaskManager.createTaskManager({387      db,388      handlers: { [handlerId]: handler },389      logger,390    });391    const taskFail = await taskManager.scheduleTask({392      handlerId,393      parameters: [false],394      lazy: false,395    });396    const taskSuccess = await taskManager.scheduleTask({397      handlerId,398      parameters: [true],399      lazy: false,400    });401    // Promise should succeed with result402    await expect(taskSuccess.promise()).resolves.toBe(true);403    await expect(taskFail.promise()).rejects.toThrow(Error);404    await taskManager.stop();405  });406  test('tasks fail with no handler', async () => {407    const taskManager = await TaskManager.createTaskManager({408      db,409      logger,410    });411    const taskFail = await taskManager.scheduleTask({412      handlerId,413      parameters: [],414      lazy: false,415    });416    // Promise should throw417    const taskFailP = taskFail.promise();418    await expect(taskFailP).rejects.toThrow(419      tasksErrors.ErrorTaskHandlerMissing,420    );421    await taskManager.stop();422  });423  test('tasks fail with unregistered handler', async () => {424    const handler = jest.fn();425    handler.mockImplementation(async (_ctx, _taskInfo, fail) => {426      if (!fail) throw Error('three');427      return fail;428    });429    const taskManager = await TaskManager.createTaskManager({430      db,431      handlers: { [handlerId]: handler },432      logger,433    });434    const taskSucceed = await taskManager.scheduleTask({435      handlerId,436      parameters: [false],437      lazy: false,438    });439    // Promise should succeed440    const taskSucceedP = taskSucceed.promise();441    await expect(taskSucceedP).rejects.not.toThrow(442      tasksErrors.ErrorTaskHandlerMissing,443    );444    // Deregister445    taskManager.deregisterHandler(handlerId);446    const taskFail = await taskManager.scheduleTask({447      handlerId,448      parameters: [false],449      lazy: false,450    });451    const taskFailP = taskFail.promise();452    await expect(taskFailP).rejects.toThrow(453      tasksErrors.ErrorTaskHandlerMissing,454    );455    await taskManager.stop();456  });457  test('eager taskPromise resolves when awaited after task completion', async () => {458    const handler = jest.fn();459    handler.mockImplementation(async (_ctx, _taskInfo, fail) => {460      if (!fail) throw Error('three');461      return fail;462    });463    const taskManager = await TaskManager.createTaskManager({464      db,465      handlers: { [handlerId]: handler },466      lazy: true,467      logger,468    });469    const taskSucceed1 = await taskManager.scheduleTask({470      handlerId,471      parameters: [true],472      lazy: false,473    });474    await taskManager.startProcessing();475    await expect(taskSucceed1.promise()).resolves.toBe(true);476    const taskSucceed2 = await taskManager.scheduleTask({477      handlerId,478      parameters: [true],479      lazy: false,480    });481    await expect(taskSucceed2.promise()).resolves.toBe(true);482    await taskManager.stop();483  });484  test('lazy taskPromise rejects when awaited after task completion', async () => {485    const handler = jest.fn();486    handler.mockImplementation(async () => {});487    const taskManager = await TaskManager.createTaskManager({488      db,489      handlers: { [handlerId]: handler },490      lazy: true,491      logger,492    });493    const taskSucceed = await taskManager.scheduleTask({494      handlerId,495      parameters: [],496      lazy: true,497    });498    const taskProm = taskManager.getTaskPromise(taskSucceed.id);499    await taskManager.startProcessing();500    await taskProm;501    await expect(taskSucceed.promise()).rejects.toThrow();502    await taskManager.stop();503  });504  test('Task Promises should be singletons', async () => {505    const taskManager = await TaskManager.createTaskManager({506      db,507      lazy: true,508      logger,509    });510    const task1 = await taskManager.scheduleTask({511      handlerId,512      parameters: [],513      lazy: false,514    });515    const task2 = await taskManager.scheduleTask({516      handlerId,517      parameters: [],518      lazy: true,519    });520    expect(task1.promise()).toBe(task1.promise());521    expect(task1.promise()).toBe(taskManager.getTaskPromise(task1.id));522    expect(taskManager.getTaskPromise(task1.id)).toBe(523      taskManager.getTaskPromise(task1.id),524    );525    expect(task2.promise()).toBe(task2.promise());526    expect(task2.promise()).toBe(taskManager.getTaskPromise(task2.id));527    expect(taskManager.getTaskPromise(task2.id)).toBe(528      taskManager.getTaskPromise(task2.id),529    );530    await taskManager.stop();531  });532  test('can cancel scheduled task, clean up and reject taskPromise', async () => {533    const taskManager = await TaskManager.createTaskManager({534      db,535      lazy: true,536      logger,537    });538    const task1 = await taskManager.scheduleTask({539      handlerId,540      parameters: [],541      lazy: false,542    });543    const task2 = await taskManager.scheduleTask({544      handlerId,545      parameters: [],546      lazy: true,547    });548    // Cancellation should reject promise549    const taskPromise = task1.promise();550    taskPromise.cancel('cancelled');551    await expect(taskPromise).rejects.toBe('cancelled');552    // Should cancel without awaiting anything553    task2.cancel('cancelled');554    await sleep(200);555    // Task should be cleaned up556    expect(await taskManager.getTask(task1.id)).toBeUndefined();557    expect(await taskManager.getTask(task2.id)).toBeUndefined();558    await taskManager.stop();559  });560  test('can cancel queued task, clean up and reject taskPromise', async () => {561    const taskManager = await TaskManager.createTaskManager({562      db,563      lazy: true,564      logger,565    });566    const task1 = await taskManager.scheduleTask({567      handlerId,568      parameters: [],569      lazy: false,570    });571    const task2 = await taskManager.scheduleTask({572      handlerId,573      parameters: [],574      lazy: true,575    });576    // @ts-ignore: private method577    await taskManager.startScheduling();578    await sleep(100);579    // Cancellation should reject promise580    const taskPromise = task1.promise();581    taskPromise.cancel('cancelled');582    await expect(taskPromise).rejects.toBe('cancelled');583    task2.cancel('cancelled');584    await sleep(200);585    // Task should be cleaned up586    expect(await taskManager.getTask(task1.id)).toBeUndefined();587    expect(await taskManager.getTask(task2.id)).toBeUndefined();588    await taskManager.stop();589  });590  test('can cancel active task, clean up and reject taskPromise', async () => {591    const handler = jest.fn();592    const pauseProm = promise();593    handler.mockImplementation(async (ctx: ContextTimed) => {594      const abortProm = new Promise((resolve, reject) =>595        ctx.signal.addEventListener('abort', () => reject(ctx.signal.reason)),596      );597      await Promise.race([pauseProm.p, abortProm]);598    });599    const taskManager = await TaskManager.createTaskManager({600      db,601      handlers: { [handlerId]: handler },602      lazy: true,603      logger,604    });605    const task1 = await taskManager.scheduleTask({606      handlerId,607      parameters: [],608      lazy: false,609    });610    const task2 = await taskManager.scheduleTask({611      handlerId,612      parameters: [],613      lazy: true,614    });615    await taskManager.startProcessing();616    await sleep(100);617    // Cancellation should reject promise618    const taskPromise = task1.promise();619    taskPromise.cancel('cancelled');620    // Await taskPromise.catch(reason => console.error(reason));621    await expect(taskPromise).rejects.toBe('cancelled');622    task2.cancel('cancelled');623    await sleep(200);624    // Task should be cleaned up625    expect(await taskManager.getTask(task1.id, true)).toBeUndefined();626    expect(await taskManager.getTask(task2.id, true)).toBeUndefined();627    pauseProm.resolveP();628    await taskManager.stop();629  });630  test('incomplete active tasks cleaned up during startup', async () => {631    const handler = jest.fn();632    handler.mockImplementation(async () => {});633    const taskManager = await TaskManager.createTaskManager({634      db,635      handlers: { [handlerId]: handler },636      lazy: true,637      logger,638    });639    // Seeding data640    const task = await taskManager.scheduleTask({641      handlerId,642      parameters: [],643      deadline: 100,644      lazy: false,645    });646    // Moving task to active in database647    const taskScheduleTime = task.scheduled.getTime();648    // @ts-ignore: private property649    const tasksScheduledDbPath = taskManager.tasksScheduledDbPath;650    // @ts-ignore: private property651    const tasksActiveDbPath = taskManager.tasksActiveDbPath;652    const taskIdBuffer = task.id.toBuffer();653    await db.withTransactionF(async (tran) => {654      await tran.del([655        ...tasksScheduledDbPath,656        utils.lexiPackBuffer(taskScheduleTime),657        taskIdBuffer,658      ]);659      await tran.put([...tasksActiveDbPath, taskIdBuffer], null);660    });661    // Task should be active662    const newTask1 = await taskManager.getTask(task.id);663    expect(newTask1!.status).toBe('active');664    // Restart to clean up665    await taskManager.stop();666    await taskManager.start({ lazy: true });667    // Task should be back to queued668    const newTask2 = await taskManager.getTask(task.id, false);669    expect(newTask2!.status).toBe('queued');670    await taskManager.startProcessing();671    await newTask2!.promise();672    await taskManager.stop();673  });674  test('stopping should gracefully end active tasks', async () => {675    const handler = jest.fn();676    const pauseProm = promise();677    handler.mockImplementation(async (ctx: ContextTimed) => {678      const abortProm = new Promise((resolve, reject) =>679        ctx.signal.addEventListener('abort', () =>680          reject(681            new tasksErrors.ErrorTaskRetry(undefined, {682              cause: ctx.signal.reason,683            }),684          ),685        ),686      );687      await Promise.race([pauseProm.p, abortProm]);688    });689    const taskManager = await TaskManager.createTaskManager({690      db,691      handlers: { [handlerId]: handler },692      lazy: true,693      logger,694    });695    const task1 = await taskManager.scheduleTask({696      handlerId,697      parameters: [],698      lazy: true,699    });700    const task2 = await taskManager.scheduleTask({701      handlerId,702      parameters: [],703      lazy: true,704    });705    await taskManager.startProcessing();706    await sleep(100);707    await taskManager.stop();708    // TaskManager should still exist.709    await taskManager.start({ lazy: true });710    expect(await taskManager.getTask(task1.id)).toBeDefined();711    expect(await taskManager.getTask(task2.id)).toBeDefined();712    await taskManager.stop();713  });714  test('stopped tasks should run again if allowed', async () => {715    const pauseProm = promise();716    const handlerId1 = 'handler1' as TaskHandlerId;717    const handler1 = jest.fn();718    handler1.mockImplementation(async (ctx: ContextTimed) => {719      const abortProm = new Promise((resolve, reject) =>720        ctx.signal.addEventListener('abort', () =>721          reject(722            new tasksErrors.ErrorTaskRetry(undefined, {723              cause: ctx.signal.reason,724            }),725          ),726        ),727      );728      await Promise.race([pauseProm.p, abortProm]);729    });730    const handlerId2 = 'handler2' as TaskHandlerId;731    const handler2 = jest.fn();732    handler2.mockImplementation(async (ctx: ContextTimed) => {733      const abortProm = new Promise((resolve, reject) =>734        ctx.signal.addEventListener('abort', () => reject(ctx.signal.reason)),735      );736      await Promise.race([pauseProm.p, abortProm]);737    });738    const taskManager = await TaskManager.createTaskManager({739      db,740      handlers: { [handlerId1]: handler1, [handlerId2]: handler2 },741      lazy: true,742      logger,743    });744    const task1 = await taskManager.scheduleTask({745      handlerId: handlerId1,746      parameters: [],747      lazy: true,748    });749    const task2 = await taskManager.scheduleTask({750      handlerId: handlerId2,751      parameters: [],752      lazy: true,753    });754    await taskManager.startProcessing();755    await sleep(100);756    await taskManager.stop();757    // Tasks were run758    expect(handler1).toHaveBeenCalled();759    expect(handler2).toHaveBeenCalled();760    handler1.mockClear();761    handler2.mockClear();762    await taskManager.start({ lazy: true });763    const task1New = await taskManager.getTask(task1.id, false);764    const task2New = await taskManager.getTask(task2.id, false);765    await taskManager.startProcessing();766    // Task1 should still exist767    expect(task1New).toBeDefined();768    // Task2 should've been removed769    expect(task2New).toBeUndefined();770    pauseProm.resolveP();771    await expect(task1New?.promise()).resolves.toBeUndefined();772    // Tasks were run773    expect(handler1).toHaveBeenCalled();774    expect(handler2).not.toHaveBeenCalled();775    await taskManager.stop();776  });777  test('tests for taskPath', async () => {778    const taskManager = await TaskManager.createTaskManager({779      db,780      lazy: true,781      logger,782    });783    await taskManager.scheduleTask({784      handlerId,785      parameters: [1],786      path: ['one'],787      lazy: true,788    });789    await taskManager.scheduleTask({790      handlerId,791      parameters: [2],792      path: ['two'],793      lazy: true,794    });795    await taskManager.scheduleTask({796      handlerId,797      parameters: [3],798      path: ['two'],799      lazy: true,800    });801    await taskManager.scheduleTask({802      handlerId,803      parameters: [4],804      path: ['group1', 'three'],805      lazy: true,806    });807    await taskManager.scheduleTask({808      handlerId,809      parameters: [5],810      path: ['group1', 'four'],811      lazy: true,812    });813    await taskManager.scheduleTask({814      handlerId,815      parameters: [6],816      path: ['group1', 'four'],817      lazy: true,818    });819    await taskManager.scheduleTask({820      handlerId,821      parameters: [7],822      path: ['group2', 'five'],823      lazy: true,824    });825    await taskManager.scheduleTask({826      handlerId,827      parameters: [8],828      path: ['group2', 'six'],829      lazy: true,830    });831    const listTasks = async (taskGroup: TaskPath) => {832      const taskManagerList: Array<Task> = [];833      for await (const task of taskManager.getTasks(834        undefined,835        true,836        taskGroup,837      )) {838        taskManagerList.push(task);839      }840      return taskManagerList;841    };842    expect(await listTasks(['one'])).toHaveLength(1);843    expect(await listTasks(['two'])).toHaveLength(2);844    expect(await listTasks(['group1'])).toHaveLength(3);845    expect(await listTasks(['group1', 'four'])).toHaveLength(2);846    expect(await listTasks(['group2'])).toHaveLength(2);847    expect(await listTasks([])).toHaveLength(8);848  });849  test('getTask', async () => {850    const taskManager = await TaskManager.createTaskManager({851      db,852      lazy: true,853      logger,854    });855    const task1 = await taskManager.scheduleTask({856      handlerId,857      parameters: [1],858      lazy: true,859    });860    const task2 = await taskManager.scheduleTask({861      handlerId,862      parameters: [2],863      lazy: true,864    });865    const gotTask1 = await taskManager.getTask(task1.id, true);866    expect(task1.toString()).toEqual(gotTask1?.toString());867    const gotTask2 = await taskManager.getTask(task2.id, true);868    expect(task2.toString()).toEqual(gotTask2?.toString());869  });870  test('getTasks', async () => {871    const taskManager = await TaskManager.createTaskManager({872      db,873      lazy: true,874      logger,875    });876    await taskManager.scheduleTask({ handlerId, parameters: [1], lazy: true });877    await taskManager.scheduleTask({ handlerId, parameters: [2], lazy: true });878    await taskManager.scheduleTask({ handlerId, parameters: [3], lazy: true });879    await taskManager.scheduleTask({ handlerId, parameters: [4], lazy: true });880    const taskList: Array<Task> = [];881    for await (const task of taskManager.getTasks()) {882      taskList.push(task);883    }884    expect(taskList.length).toBe(4);885  });886  test('updating tasks while scheduled', async () => {887    const handlerId1 = 'handler1' as TaskHandlerId;888    const handlerId2 = 'handler2' as TaskHandlerId;889    const handler1 = jest.fn();890    const handler2 = jest.fn();891    const taskManager = await TaskManager.createTaskManager({892      db,893      handlers: { [handlerId1]: handler1, [handlerId2]: handler2 },894      lazy: true,895      logger,896    });897    const task1 = await taskManager.scheduleTask({898      handlerId: handlerId1,899      delay: 100000,900      parameters: [],901      lazy: false,902    });903    await taskManager.updateTask(task1.id, {904      handlerId: handlerId2,905      delay: 0,906      parameters: [1],907      priority: 100,908      deadline: 100,909      path: ['newPath'],910    });911    // Task should be updated912    const oldTask = await taskManager.getTask(task1.id);913    if (oldTask == null) never();914    expect(oldTask.id.equals(task1.id)).toBeTrue();915    expect(oldTask.handlerId).toEqual(handlerId2);916    expect(oldTask.delay).toBe(0);917    expect(oldTask.parameters).toEqual([1]);918    expect(oldTask.priority).toEqual(100);919    expect(oldTask.deadline).toEqual(100);920    expect(oldTask.path).toEqual(['newPath']);921    // Path should've been updated922    let task_: Task | undefined;923    for await (const task of taskManager.getTasks(undefined, true, [924      'newPath',925    ])) {926      task_ = task;927      expect(task.id.equals(task1.id)).toBeTrue();928    }929    expect(task_).toBeDefined();930    await taskManager.stop();931  });932  test('updating tasks while queued or active should fail', async () => {933    const handler = jest.fn();934    handler.mockImplementation(async (_ctx, _taskInfo, value) => value);935    const taskManager = await TaskManager.createTaskManager({936      db,937      handlers: { [handlerId]: handler },938      lazy: true,939      logger,940    });941    // @ts-ignore: private method, only schedule tasks942    await taskManager.startScheduling();943    const task1 = await taskManager.scheduleTask({944      handlerId,945      delay: 0,946      parameters: [],947      lazy: false,948    });949    await sleep(100);950    await expect(951      taskManager.updateTask(task1.id, {952        delay: 1000,953        parameters: [1],954      }),955    ).rejects.toThrow(tasksErrors.ErrorTaskRunning);956    // Task has not been updated957    const oldTask = await taskManager.getTask(task1.id);958    if (oldTask == null) never();959    expect(oldTask.delay).toBe(0);960    expect(oldTask.parameters).toEqual([]);961    await taskManager.stop();962  });963  test('updating tasks delay should update schedule timer', async () => {964    const handlerId1 = 'handler1' as TaskHandlerId;965    const handlerId2 = 'handler2' as TaskHandlerId;966    const handler1 = jest.fn();967    const handler2 = jest.fn();968    handler1.mockImplementation(async (_ctx, _taskInfo, value) => value);969    handler2.mockImplementation(async (_ctx, _taskInfo, value) => value);970    const taskManager = await TaskManager.createTaskManager({971      db,972      handlers: { [handlerId1]: handler1, [handlerId2]: handler2 },973      lazy: true,974      logger,975    });976    const task1 = await taskManager.scheduleTask({977      handlerId: handlerId1,978      delay: 100000,979      parameters: [],980      lazy: false,981    });982    const task2 = await taskManager.scheduleTask({983      handlerId: handlerId1,984      delay: 100000,985      parameters: [],986      lazy: false,987    });988    await taskManager.updateTask(task1.id, {989      delay: 0,990      parameters: [1],991    });992    // Task should be updated993    const newTask = await taskManager.getTask(task1.id);994    if (newTask == null) never();995    expect(newTask.delay).toBe(0);996    expect(newTask.parameters).toEqual([1]);997    // Task should resolve with new parameter998    await taskManager.startProcessing();999    await expect(task1.promise()).resolves.toBe(1);1000    await sleep(100);1001    expect(handler1).toHaveBeenCalledTimes(1);1002    // Updating task should update existing timer1003    await taskManager.updateTask(task2.id, {1004      delay: 0,1005      parameters: [1],1006      handlerId: handlerId2,1007    });1008    await expect(task2.promise()).resolves.toBe(1);1009    expect(handler1).toHaveBeenCalledTimes(1);1010    expect(handler2).toHaveBeenCalledTimes(1);1011    await taskManager.stop();1012  });1013  test('task should run after scheduled delay', async () => {1014    const handler = jest.fn();1015    const taskManager = await TaskManager.createTaskManager({1016      db,1017      handlers: { [handlerId]: handler },1018      lazy: true,1019      logger,1020    });1021    // Edge case delays1022    // same as 0 delay1023    await taskManager.scheduleTask({1024      handlerId,1025      delay: NaN,1026      lazy: true,1027    });1028    // Same as max delay1029    await taskManager.scheduleTask({1030      handlerId,1031      delay: Infinity,1032      lazy: true,1033    });1034    // Normal delays1035    await taskManager.scheduleTask({1036      handlerId,1037      delay: 500,1038      lazy: true,1039    });1040    await taskManager.scheduleTask({1041      handlerId,1042      delay: 1000,1043      lazy: true,1044    });1045    await taskManager.scheduleTask({1046      handlerId,1047      delay: 1500,1048      lazy: true,1049    });1050    expect(handler).toHaveBeenCalledTimes(0);1051    await taskManager.startProcessing();1052    await sleep(250);1053    expect(handler).toHaveBeenCalledTimes(1);1054    await sleep(500);1055    expect(handler).toHaveBeenCalledTimes(2);1056    await sleep(500);1057    expect(handler).toHaveBeenCalledTimes(3);1058    await sleep(500);1059    expect(handler).toHaveBeenCalledTimes(4);1060    await taskManager.stop();1061  });1062  test('queued tasks should be started in priority order', async () => {1063    const handler = jest.fn();1064    const pendingProm = promise();1065    const totalTasks = 31;1066    const completedTaskOrder: Array<number> = [];1067    handler.mockImplementation(async (_ctx, _taskInfo, priority) => {1068      completedTaskOrder.push(priority);1069      if (completedTaskOrder.length >= totalTasks) pendingProm.resolveP();1070    });1071    const taskManager = await TaskManager.createTaskManager({1072      db,1073      handlers: { [handlerId]: handler },1074      lazy: true,1075      logger,1076    });1077    const expectedTaskOrder: Array<number> = [];1078    for (let i = 0; i < totalTasks; i += 1) {1079      const priority = 150 - i * 10;1080      expectedTaskOrder.push(priority);1081      await taskManager.scheduleTask({1082        handlerId,1083        parameters: [priority],1084        priority,1085        lazy: true,1086      });1087    }1088    // @ts-ignore: start scheduling first1089    await taskManager.startScheduling();1090    await sleep(500);1091    // @ts-ignore: Then queueing1092    await taskManager.startQueueing();1093    // Wait for all tasks to complete1094    await pendingProm.p;1095    expect(completedTaskOrder).toEqual(expectedTaskOrder);1096    await taskManager.stop();1097  });1098  test('task exceeding deadline should abort and clean up', async () => {1099    const handler = jest.fn();1100    const pauseProm = promise();1101    handler.mockImplementation(async (ctx: ContextTimed) => {1102      const abortProm = new Promise((resolve, reject) =>1103        ctx.signal.addEventListener('abort', () => reject(ctx.signal.reason)),1104      );1105      await Promise.race([pauseProm.p, abortProm]);1106    });1107    const taskManager = await TaskManager.createTaskManager({1108      db,1109      handlers: { [handlerId]: handler },1110      lazy: true,1111      logger,1112    });1113    const task = await taskManager.scheduleTask({1114      handlerId,1115      parameters: [],1116      deadline: 100,1117      lazy: false,1118    });1119    await taskManager.startProcessing();1120    // Cancellation should reject promise1121    const taskPromise = task.promise();1122    // FIXME: check for deadline timeout error1123    await expect(taskPromise).rejects.toThrow(tasksErrors.ErrorTaskTimeOut);1124    // Task should be cleaned up1125    const oldTask = await taskManager.getTask(task.id);1126    expect(oldTask).toBeUndefined();1127    pauseProm.resolveP();1128    await taskManager.stop();1129  });1130  test.todo('scheduled task times should not conflict');1131  // TODO: this should move the clock backwards with mocking1132  test.todo('taskIds are monotonic');1133  // TODO: needs fast check1134  test.todo('general concurrent API usage to test robustness');...commands.spec.ts
Source:commands.spec.ts  
1import * as fc from 'fast-check';2import { commands } from '../../../src/arbitrary/commands';3import prand from 'pure-rand';4import { Command } from '../../../src/check/model/command/Command';5import { Random } from '../../../src/random/generator/Random';6import { Arbitrary } from '../../../src/check/arbitrary/definition/Arbitrary';7import { Value } from '../../../src/check/arbitrary/definition/Value';8import { Stream } from '../../../src/stream/Stream';9import { tuple } from '../../../src/arbitrary/tuple';10import { nat } from '../../../src/arbitrary/nat';11import { isStrictlySmallerArray } from './__test-helpers__/ArrayHelpers';12type Model = Record<string, unknown>;13type Real = unknown;14type Cmd = Command<Model, Real>;15const model: Model = Object.freeze({});16const real: Real = Object.freeze({});17describe('commands (integration)', () => {18  function simulateCommands(cmds: Iterable<Cmd>): void {19    for (const c of cmds) {20      if (!c.check(model)) continue;21      try {22        c.run(model, real);23      } catch (err) {24        return;25      }26    }27  }28  it('should generate a cloneable instance', () => {29    fc.assert(30      fc.property(fc.integer(), fc.option(fc.integer({ min: 2 }), { nil: undefined }), (seed, biasFactor) => {31        // Arrange32        const mrng = new Random(prand.xorshift128plus(seed));33        const logOnCheck: { data: string[] } = { data: [] };34        // Act35        const commandsArb = commands([36          new FakeConstant(new SuccessCommand(logOnCheck)),37          new FakeConstant(new SkippedCommand(logOnCheck)),38          new FakeConstant(new FailureCommand(logOnCheck)),39        ]);40        const baseCommands = commandsArb.generate(mrng, biasFactor);41        // Assert42        return baseCommands.hasToBeCloned;43      })44    );45  });46  it('should skip skipped commands on shrink', () => {47    fc.assert(48      fc.property(fc.integer(), fc.option(fc.integer({ min: 2 }), { nil: undefined }), (seed, biasFactor) => {49        // Arrange50        const mrng = new Random(prand.xorshift128plus(seed));51        const logOnCheck: { data: string[] } = { data: [] };52        // Act53        const commandsArb = commands([54          new FakeConstant(new SuccessCommand(logOnCheck)),55          new FakeConstant(new SkippedCommand(logOnCheck)),56          new FakeConstant(new FailureCommand(logOnCheck)),57        ]);58        const baseCommands = commandsArb.generate(mrng, biasFactor);59        simulateCommands(baseCommands.value);60        // Assert61        const shrinks = commandsArb.shrink(baseCommands.value_, baseCommands.context);62        for (const shrunkCmds of shrinks) {63          logOnCheck.data = [];64          [...shrunkCmds.value].forEach((c) => c.check(model));65          expect(logOnCheck.data.every((e) => e !== 'skipped')).toBe(true);66        }67      })68    );69  });70  it('should shrink with failure at the end', () => {71    fc.assert(72      fc.property(fc.integer(), fc.option(fc.integer({ min: 2 }), { nil: undefined }), (seed, biasFactor) => {73        // Arrange74        const mrng = new Random(prand.xorshift128plus(seed));75        const logOnCheck: { data: string[] } = { data: [] };76        // Act77        const commandsArb = commands([78          new FakeConstant(new SuccessCommand(logOnCheck)),79          new FakeConstant(new SkippedCommand(logOnCheck)),80          new FakeConstant(new FailureCommand(logOnCheck)),81        ]);82        const baseCommands = commandsArb.generate(mrng, biasFactor);83        simulateCommands(baseCommands.value);84        fc.pre(logOnCheck.data[logOnCheck.data.length - 1] === 'failure');85        // Assert86        const shrinks = commandsArb.shrink(baseCommands.value_, baseCommands.context);87        for (const shrunkCmds of shrinks) {88          logOnCheck.data = [];89          [...shrunkCmds.value].forEach((c) => c.check(model));90          if (logOnCheck.data.length > 0) {91            // either empty or ending by the failure92            expect(logOnCheck.data[logOnCheck.data.length - 1]).toEqual('failure');93          }94        }95      })96    );97  });98  it('should shrink with at most one failure and all successes', () => {99    fc.assert(100      fc.property(fc.integer(), fc.option(fc.integer({ min: 2 }), { nil: undefined }), (seed, biasFactor) => {101        // Arrange102        const mrng = new Random(prand.xorshift128plus(seed));103        const logOnCheck: { data: string[] } = { data: [] };104        // Act105        const commandsArb = commands([106          new FakeConstant(new SuccessCommand(logOnCheck)),107          new FakeConstant(new SkippedCommand(logOnCheck)),108          new FakeConstant(new FailureCommand(logOnCheck)),109        ]);110        const baseCommands = commandsArb.generate(mrng, biasFactor);111        simulateCommands(baseCommands.value);112        // Assert113        const shrinks = commandsArb.shrink(baseCommands.value_, baseCommands.context);114        for (const shrunkCmds of shrinks) {115          logOnCheck.data = [];116          [...shrunkCmds.value].forEach((c) => c.check(model));117          expect(logOnCheck.data.every((e) => e === 'failure' || e === 'success')).toBe(true);118          expect(logOnCheck.data.filter((e) => e === 'failure').length <= 1).toBe(true);119        }120      })121    );122  });123  it('should provide commands which have never run', () => {124    const commandsArb = commands([new FakeConstant(new SuccessCommand({ data: [] }))], {125      disableReplayLog: true,126    });127    const manyArbsIncludingCommandsOne = tuple(nat(16), commandsArb, nat(16));128    const assertCommandsNotStarted = (value: Value<[number, Iterable<Cmd>, number]>) => {129      // Check the commands have never been executed130      // by checking the toString of the iterable is empty131      expect(String(value.value_[1])).toEqual('');132    };133    const startCommands = (value: Value<[number, Iterable<Cmd>, number]>) => {134      // Iterate over all the generated commands to run them all135      let ranOneCommand = false;136      for (const cmd of value.value_[1]) {137        ranOneCommand = true;138        cmd.run({}, {});139      }140      // Confirming that executing at least one command will make the toString of the iterable141      // not empty142      if (ranOneCommand) {143        expect(String(value.value_[1])).not.toEqual('');144      }145    };146    fc.assert(147      fc.property(148        fc.integer().noShrink(),149        fc.infiniteStream(fc.nat()),150        fc.option(fc.integer({ min: 2 }), { nil: undefined }),151        (seed, shrinkPath, biasFactor) => {152          // Generate the first Value153          const it = shrinkPath[Symbol.iterator]();154          const mrng = new Random(prand.xorshift128plus(seed));155          let currentValue: Value<[number, Iterable<Cmd>, number]> | null = manyArbsIncludingCommandsOne.generate(156            mrng,157            biasFactor158          );159          // Check status and update first Value160          assertCommandsNotStarted(currentValue);161          startCommands(currentValue);162          // Traverse the shrink tree in order to detect already seen ids163          while (currentValue !== null) {164            currentValue = manyArbsIncludingCommandsOne165              .shrink(currentValue.value_, currentValue.context)166              .map((nextValue) => {167                // Check nothing starting for the next one168                assertCommandsNotStarted(nextValue);169                // Start everything: not supposed to impact any other shrinkable170                startCommands(nextValue);171                return nextValue;172              })173              .getNthOrLast(it.next().value);174          }175        }176      )177    );178  });179  it('should shrink to smaller values', () => {180    const commandsArb = commands([nat(3).map((id) => new SuccessIdCommand(id))]);181    fc.assert(182      fc.property(183        fc.integer().noShrink(),184        fc.infiniteStream(fc.nat()),185        fc.option(fc.integer({ min: 2 }), { nil: undefined }),186        (seed, shrinkPath, biasFactor) => {187          // Generate the first Value188          const it = shrinkPath[Symbol.iterator]();189          const mrng = new Random(prand.xorshift128plus(seed));190          let currentValue: Value<Iterable<Cmd>> | null = commandsArb.generate(mrng, biasFactor);191          // Run all commands of first Value192          simulateCommands(currentValue.value_);193          // Traverse the shrink tree in order to detect already seen ids194          const extractIdRegex = /^custom\((\d+)\)$/;195          while (currentValue !== null) {196            const currentItems = [...currentValue.value_].map((c) => +extractIdRegex.exec(c.toString())![1]);197            currentValue = commandsArb198              .shrink(currentValue.value_, currentValue.context)199              .map((nextValue) => {200                // Run all commands of nextShrinkable201                simulateCommands(nextValue.value_);202                // Check nextShrinkable is strictly smaller than current one203                const nextItems = [...nextValue.value_].map((c) => +extractIdRegex.exec(c.toString())![1]);204                expect(isStrictlySmallerArray(nextItems, currentItems)).toBe(true);205                // Next is eligible for shrinking206                return nextValue;207              })208              .getNthOrLast(it.next().value);209          }210        }211      )212    );213  });214  it('should shrink the same way when based on replay data', () => {215    fc.assert(216      fc.property(217        fc.integer().noShrink(),218        fc.nat(100),219        fc.option(fc.integer({ min: 2 }), { nil: undefined }),220        (seed, numValues, biasFactor) => {221          // create unused logOnCheck222          const logOnCheck: { data: string[] } = { data: [] };223          // generate scenario and simulate execution224          const rng = prand.xorshift128plus(seed);225          const refArbitrary = commands([226            new FakeConstant(new SuccessCommand(logOnCheck)),227            new FakeConstant(new SkippedCommand(logOnCheck)),228            new FakeConstant(new FailureCommand(logOnCheck)),229            nat().map((v) => new SuccessIdCommand(v)),230          ]);231          const refValue: Value<Iterable<Cmd>> = refArbitrary.generate(new Random(rng), biasFactor);232          simulateCommands(refValue.value_);233          // trigger computation of replayPath234          // and extract shrinks for ref235          const refShrinks = [236            ...refArbitrary237              .shrink(refValue.value_, refValue.context)238              .take(numValues)239              .map((s) => [...s.value_].map((c) => c.toString())),240          ];241          // extract replayPath242          const replayPath = /\/\*replayPath=['"](.*)['"]\*\//.exec(refValue.value_.toString())![1];243          // generate scenario but do not simulate execution244          const noExecArbitrary = commands(245            [246              new FakeConstant(new SuccessCommand(logOnCheck)),247              new FakeConstant(new SkippedCommand(logOnCheck)),248              new FakeConstant(new FailureCommand(logOnCheck)),249              nat().map((v) => new SuccessIdCommand(v)),250            ],251            { replayPath }252          );253          const noExecValue: Value<Iterable<Cmd>> = noExecArbitrary.generate(new Random(rng), biasFactor);254          // check shrink values are identical255          const noExecShrinks = [256            ...noExecArbitrary257              .shrink(noExecValue.value_, noExecValue.context)258              .take(numValues)259              .map((s) => [...s.value_].map((c) => c.toString())),260          ];261          expect(noExecShrinks).toEqual(refShrinks);262        }263      )264    );265  });266});267// Helpers268class FakeConstant extends Arbitrary<Cmd> {269  constructor(private readonly cmd: Cmd) {270    super();271  }272  generate(): Value<Cmd> {273    return new Value(this.cmd, undefined);274  }275  canShrinkWithoutContext(value: unknown): value is Cmd {276    return false;277  }278  shrink(): Stream<Value<Cmd>> {279    return Stream.nil();280  }281}282class SuccessIdCommand implements Cmd {283  constructor(readonly id: number) {}284  check = () => true;285  run = () => {};286  toString = () => `custom(${this.id})`;287}288class SuccessCommand implements Cmd {289  constructor(readonly log: { data: string[] }) {}290  check = () => {291    this.log.data.push(this.toString());292    return true;293  };294  run = () => {};295  toString = () => 'success';296}297class SkippedCommand implements Cmd {298  constructor(readonly log: { data: string[] }) {}299  check = () => {300    this.log.data.push(this.toString());301    return false;302  };303  run = () => {};304  toString = () => 'skipped';305}306class FailureCommand implements Cmd {307  constructor(readonly log: { data: string[] }) {}308  check = () => {309    this.log.data.push(this.toString());310    return true;311  };312  run = () => {313    throw 'error';314  };315  toString = () => 'failure';...dequeue.spec.ts
Source:dequeue.spec.ts  
1// Copyright 2019 Ryan Zeigler2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7//     http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14import { expect } from "chai";15import fc, { Arbitrary, Command } from "fast-check";16import * as O from "fp-ts/lib/Option";17import { none, some } from "fp-ts/lib/Option";18import * as p from "fp-ts/lib/pipeable";19import { pipe } from "fp-ts/lib/pipeable";20import { Dequeue, empty } from "../src/support/dequeue";21describe("Dequeue", () => {22  it("take on empty is none", () => {23    expect(empty().take()).to.deep.equal(none);24  });25  it("pull on empty is none", () => {26    expect(empty().pull()).to.deep.equal(none);27  });28  it("take after offer is a value", () => {29    const queue = empty().offer(42);30    const result = pipe(queue.take(), O.map((v) => v[0]));31    expect(result).to.deep.equal(some(42));32  });33  it("pull after offer is a value", () => {34    const queue = empty<number>().offer(42);35    const result = queue.pull();36    p.pipe(37      result,38      O.fold(39        () => { throw new Error("expected some"); },40        (tuple) => expect(tuple[0]).to.equal(42)41      )42    );43  });44  it("take after multiple offers is the first", () => {45    const queue = empty()46      .offer(42)47      .offer(43)48      .offer(44);49    const result = queue.take();50    p.pipe(51      result,52      O.fold(53        () => { throw new Error("expected some"); },54        (tuple) => {55          expect(tuple[0]).to.equal(42);56          expect(tuple[1].size()).to.equal(2);57        }58      )59    );60  });61  it("pull after multiple offers is the last", () => {62    const queue = empty()63      .offer(42)64      .offer(43)65      .offer(44);66    const result = queue.pull();67    p.pipe(68      result,69      O.fold(70        () => { throw new Error("expected some"); },71        (tuple) => {72          expect(tuple[0]).to.equal(44);73          expect(tuple[1].size()).to.equal(2);74        }75      )76    );77  });78    interface Model {79        fake: number[];80    }81    interface Real {82        actual: Dequeue<number>;83    }84    // push addss to the right, offer adds to the left85    // pull takes from the left, take takes from the right86    const pushCommandArb: Arbitrary<Command<Model, Real>> = fc.nat()87      .map((n) => {88        return {89          check(_m: Model): boolean {90            return true;91          },92          run(m: Model, r: Real): void {93            m.fake.push(n);94            r.actual = r.actual.push(n);95          },96          toString() {97            return `push ${n}`;98          }99        };100      });101    const pullCommandArb: Arbitrary<Command<Model, Real>> = fc.constant({102      check(_m: Model): boolean {103        return true;104      },105      run(m: Model, r: Real): void {106        const expected = m.fake.shift();107        p.pipe(108          r.actual.pull(),109          O.fold(110            () => {111              if (expected) {112                throw new Error("expected there to be something");113              }114            },115            ([n, q]) => {116              expect(n).to.equal(expected);117              r.actual = q;118            }119          )120        );121      },122      toString() {123        return "pull";124      }125    });126    const offerCommandArb: Arbitrary<Command<Model, Real>> = fc.nat()127      .map((n) => {128        return {129          check(_m: Model): boolean {130            return true;131          },132          run(m: Model, r: Real): void {133            m.fake.unshift(n);134            r.actual = r.actual.offer(n);135          },136          toString() {137            return `offer ${n}`;138          }139        };140      });141    const takeCommandArb: Arbitrary<Command<Model, Real>> = fc.constant({142      check(_m: Model): boolean {143        return true;144      },145      run(m: Model, r: Real): void {146        const expected = m.fake.pop();147        p.pipe(148          r.actual.take(),149          O.fold(150            () => {151              if (expected) {152                throw new Error("expected there to be something");153              }154            },155            ([n, q]) => {156              expect(n).to.equal(expected);157              r.actual = q;158            }159          )160        );161      },162      toString() {163        return "take";164      }165    });166    const commandsArb = fc.commands([pushCommandArb, pullCommandArb, offerCommandArb, takeCommandArb]);167    it("should never lose elements", () => {168      fc.assert(169        fc.property(commandsArb, (commands) => {170          fc.modelRun(() => ({model: {fake: []}, real: {actual: empty()}}), commands);171        })172      );173    });...Using AI Code Generation
1import { commandsArb } from 'fast-check-monorepo';2import { commandsArb } from 'fast-check';3import { commandsArb } from 'fast-check/lib/check/arbitrary/CommandArbitrary.js';4import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';5import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';6import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';7import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';8import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';9import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';10import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';11import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';12import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';13import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';14import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';Using AI Code Generation
1const fc = require('fast-check');2const { commandsArb } = require('fast-check-monorepo');3const commandsArb = commandsArb();4fc.assert(5  fc.property(commandsArb, (commands) => {6  })7);8const fc = require('fast-check');9const { commandsArb } = require('fast-check-monorepo');10const commandsArb = commandsArb();11fc.assert(12  fc.property(commandsArb, (commands) => {13  })14);15const fc = require('fast-check');16const { commandsArb } = require('fast-check-monorepo');17const commandsArb = commandsArb();18fc.assert(19  fc.property(commandsArb, (commands) => {20  })21);22const fc = require('fast-check');23const { commandsArb } = require('fast-check-monorepo');24const commandsArb = commandsArb();25fc.assert(26  fc.property(commandsArb, (commands) => {27  })28);29const fc = require('fast-check');30const { commandsArb } = require('fast-check-monorepo');31const commandsArb = commandsArb();32fc.assert(33  fc.property(commandsArb, (commands) => {34  })35);36const fc = require('fast-check');37const { commandsArb } = require('fast-check-monorepo');38const commandsArb = commandsArb();39fc.assert(40  fc.property(commandsArb, (commands) => {41  })42);43const fc = require('fast-check');44const { commandsArb } = require('fast-check-monorepo');Using AI Code Generation
1import fc from 'fast-check';2import { commandsArb } from 'fast-check-monorepo';3fc.assert(4  fc.property(commandsArb(), commands => {5  })6);7import fc from 'fast-check';8import { commandsArb } from 'fast-check-monorepo';9fc.assert(10  fc.property(commandsArb(), commands => {11  })12);13import fc from 'fast-check';14import { commandsArb } from 'fast-check-monorepo';15fc.assert(16  fc.property(commandsArb(), commands => {17  })18);19import fc from 'fast-check';20import { commandsArb } from 'fast-check-monorepo';21fc.assert(22  fc.property(commandsArb(), commands => {23  })24);25import fc from 'fast-check';26import { commandsArb } from 'fast-check-monorepo';27fc.assert(28  fc.property(commandsArb(), commands => {29  })30);31import fc from 'fast-check';32import { commandsArb } from 'fast-check-monorepo';33fc.assert(34  fc.property(commandsArb(), commands => {35  })36);37import fc from 'fast-check';38import { commandsArb } from 'fast-check-monorepo';39fc.assert(40  fc.property(commandsArb(), commands => {41  })42);43import fc from 'fast-check';44import { commandsArb } from 'fast-check-monorepo';45fc.assert(46  fc.property(commandsArb(), commands => {47  })Using AI Code Generation
1const { commandsArb } = require('fast-check-monorepo');2const commands = commandsArb().generate().value;3console.log(commands);4{5  "scripts": {6  },7  "dependencies": {8  }9}10const { operationsArb } = require('fast-check-monorepo');11const operations = operationsArb().generate().value;12console.log(operations);13{14  "scripts": {15  },16  "dependencies": {17  }18}19[ { type: 'C', source: 'foo', destination: 'bar' },20  { type: 'M', source: 'foo', destination: 'bar' },21  { type: 'R', source: 'foo', destination: 'bar' } ]Using AI Code Generation
1const fc = require('fast-check');2const commandsArb = require('fast-check-monorepo').commandsArb;3const model = { value: 0 };4const run = (model, cmd) => {5  switch (cmd) {6      model.value++;7      break;8      model.value--;9      break;10      throw new Error('Unknown command');11  }12  return model;13};14fc.assert(15  fc.property(commandsArb(['inc', 'dec']), cmds => {16    cmds.reduce(run, model);17    return model.value === 0;18  })19);Using AI Code Generation
1const { commandsArb } = require("fast-check-monorepo");2const { Command } = require("fast-check-monorepo");3const myCommand = new Command("myCommand", () => {4});5const myOtherCommand = new Command("myOtherCommand", () => {6});7const myCommandList = [myCommand, myOtherCommand];8const myCommandArb = commandsArb(myCommandList);9const { commandsArb } = require("fast-check-monorepo");10const { Command } = require("fast-check-monorepo");11const myCommand = new Command("myCommand", () => {12});13const myOtherCommand = new Command("myOtherCommand", () => {14});15const myCommandList = [myCommand, myOtherCommand];16const myCommandArb = commandsArb(myCommandList);17const { commandsArb } = require("fast-check-monorepo");18const { Command } = require("fast-check-monorepo");19const myCommand = new Command("myCommand", () => {20});21const myOtherCommand = new Command("myOtherCommand", () => {22});23const myCommandList = [myCommand, myOtherCommand];24const myCommandArb = commandsArb(myCommandList);25const { commandsArb } = require("fast-check-monorepo");26const { Command } = require("fast-check-monorepo");27const myCommand = new Command("myCommand", () => {28});29const myOtherCommand = new Command("myOtherCommand", () => {30});31const myCommandList = [myCommand, myOtherCommand];32const myCommandArb = commandsArb(myCommandList);33const { commandsArb } = require("fastUsing AI Code Generation
1const { commandsArb } = require('fast-check-monorepo');2const { Command } = require('fast-check-monorepo/lib/check/model/command/Command');3const { Model } = require('fast-check-monorepo/lib/check/model/Model');4const { Arbitrary } = require('fast-check-monorepo/lib/check/arbitrary/definition/Arbitrary');5const { assert } = require('chai');6class MyModel extends Model {7  constructor() {8    super();9    this._value = 0;10  }11  get value() {12    return this._value;13  }14  increment() {15    this._value += 1;16  }17}18class MyCommand extends Command {19  constructor() {20    super();21    this._name = 'increment';22  }23  check(m) {24    return m instanceof MyModel;25  }26  run(m) {27    m.increment();28  }29}30const myArbitrary = Arbitrary.constant(new MyCommand());31const modelRun = (m, c) => {32  if (c instanceof MyCommand) {33    m.increment();34  }35};36const realRun = (m, c) => {37  if (c instanceof MyCommand) {38    m.increment();39  }40};41const pre = (m, c) => {42  return true;43};44const post = (m, c, r) => {45  return m.value === r.value;46};47const equal = (m, r) => {48  return m.value === r.value;49};50const shrink = (c) => {51  return [];52};53const beforeEach = (m) => {54  m._value = 0;55};56const afterEach = (m, r) => {57  assert.equal(m.value, r.value);58};59const beforeEachCommand = (m, c) => {60  console.log('beforeEachCommand');61};Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
