use log-helper, remove common.js
[squeep-chores] / test / lib / chores.js
1 /* eslint-env mocha */
2 /* eslint-disable node/no-unpublished-require */
3 'use strict';
4
5 const Chores = require('../../lib/chores');
6 const { ChoreError } = require('../../lib/errors');
7 const { StubLogger } = require('@squeep/test-helper');
8 const assert = require('assert');
9 const sinon = require('sinon');
10
11 const snooze = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
12 const expectedException = new Error('oh no');
13
14 describe('Chores', function () {
15 let chores, logger, task;
16 beforeEach(function () {
17 this.timeout(1000);
18 this.slow(200);
19
20 logger = new StubLogger();
21 logger._reset();
22
23 chores = new Chores(logger);
24 task = sinon.spy((...args) => {
25 logger.debug('task', 'called', { args });
26 });
27 });
28 afterEach(function () {
29 chores.stopAllChores();
30 sinon.restore();
31 });
32
33 describe('_getChore', function () {
34 it('covers failure', function () {
35 assert.throws(() => chores._getChore('no chore'), ChoreError);
36 });
37 it('covers success', function () {
38 chores.establishChore('chore1', task, 0);
39 const chore = chores._getChore('chore1');
40 assert(chore);
41 });
42 }); // _getChore
43
44 describe('establishChore', function () {
45 it('establishes non-recurring chore', async function () {
46 chores.establishChore('chore1', task, 0);
47 await snooze(20);
48 assert(task.notCalled);
49 });
50 it('refuses to establish same chore twice', function () {
51 const choreName = 'chore1';
52 chores.establishChore(choreName, task, 0);
53 assert.throws(() => chores.establishChore(choreName, task, 0), ChoreError);
54 });
55 it('establishes recurring chore', async function () {
56 chores.establishChore('chore1', task, 10);
57 await snooze(25);
58 assert(task.called);
59 });
60 }); // establishChore
61
62 describe('runChore', function () {
63 it('requires existing chore', async function () {
64 await assert.rejects(chores.runChore('missingChore'), ChoreError);
65 });
66 it('runs non-recurring chore', async function () {
67 chores.establishChore('chore1', task, 0);
68 chores.runChore('chore1');
69 assert(task.called);
70 });
71 it('does not overlap runs', async function () {
72 const longTask = sinon.spy(async (...args) => {
73 await snooze(200);
74 logger.debug('task', 'called', { args });
75 });
76 chores.establishChore('longChore', longTask);
77 chores.runChore('longChore');
78 chores.runChore('longChore');
79 snooze(300);
80 assert(longTask.called);
81 assert.strictEqual(longTask.callCount, 1);
82 });
83 it('covers recurring task exception', async function () {
84 const failTask = sinon.spy(function () {
85 throw expectedException;
86 });
87 chores.establishChore('failChore', failTask, 10);
88 await snooze(50);
89 assert(failTask.called);
90 });
91 it('covers called task exception', async function () {
92 const failTask = sinon.spy(function () {
93 throw expectedException;
94 });
95 chores.establishChore('failChore', failTask, 0);
96 await assert.rejects(chores.runChore('failChore', 'argument', 'argument'), expectedException);
97 });
98 }); // runChore
99
100 describe('miscellaneous coverage', function () {
101 it('names error', function () {
102 const e = new ChoreError();
103 assert.strictEqual(e.name, 'ChoreError');
104 });
105 });
106
107 }); // Chores