@emartech/program-executor 3.11.1 → 3.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,209 @@
1
+ 'use strict';
2
+
3
+ const ProgramExecutor = require('./index-pubsub');
4
+ const ProgramsRepository = require('./repositories/programs');
5
+ const e2eTestReuse = require('@emartech/pubsub-client-js/e2e/e2e-test-resuse.js');
6
+
7
+ const knex = require('knex');
8
+ const DbCleaner = require('./test-helper/db-cleaner');
9
+ const { db } = require('./test-helper/get-test-db-config');
10
+
11
+ const customerId = 1234;
12
+ const topicName = 'program-executor';
13
+
14
+ class SuccessfulJob {
15
+ static get name() {
16
+ return 'successful_job';
17
+ }
18
+
19
+ static create(programData) {
20
+ return new SuccessfulJob(programData);
21
+ }
22
+
23
+ // eslint-disable-next-line no-unused-vars
24
+ constructor(programData) {
25
+ /// ... initialize member variables based on programData if needed
26
+ }
27
+
28
+ async execute(message, jobDataHandler) {
29
+ // eslint-disable-next-line no-unused-vars
30
+ const jobSpecificData = await jobDataHandler.get();
31
+ }
32
+ }
33
+
34
+ class ProblematicJob {
35
+ static get name() {
36
+ return 'problematic_job';
37
+ }
38
+
39
+ static create(programData) {
40
+ return new ProblematicJob(programData);
41
+ }
42
+
43
+ // eslint-disable-next-line no-unused-vars
44
+ constructor(programData) {
45
+ }
46
+
47
+ // eslint-disable-next-line no-unused-vars
48
+ async execute(message, jobDataHandler) {
49
+ throw new Error('Some error happened in the job');
50
+ }
51
+ }
52
+
53
+
54
+ const testJobLibrary = {
55
+ firstJob: {},
56
+ secondJob: {},
57
+ successful_job: SuccessfulJob,
58
+ problematic_job: ProblematicJob
59
+ };
60
+
61
+ describe('ProgramExecutor', function () {
62
+ let config;
63
+ let configFlowControl;
64
+ let dbConnection;
65
+ let mockConstructorSpy;
66
+ let publisher;
67
+
68
+ beforeAll(async function () {
69
+ jest.clearAllMocks();
70
+ dbConnection = knex({
71
+ client: 'pg',
72
+ connection: db.connection.connString
73
+ });
74
+ await DbCleaner.create(dbConnection).tearDown();
75
+ ProgramsRepository.create(dbConnection, 'programs');
76
+ });
77
+
78
+ afterAll(async function () {
79
+ await DbCleaner.create(dbConnection).tearDown();
80
+ dbConnection.destroy();
81
+ });
82
+
83
+
84
+ afterEach(async () => {
85
+ await e2eTestReuse.afterEach(mockConstructorSpy, publisher);
86
+
87
+ publisher = undefined;
88
+ jest.clearAllMocks();
89
+ });
90
+
91
+
92
+ beforeEach(async function () {
93
+
94
+ config = {
95
+ knex: dbConnection,
96
+ tableName: 'programs',
97
+ topicName: topicName,
98
+ projectId: 'some-project-id'
99
+ };
100
+
101
+ configFlowControl = {
102
+ knex: dbConnection,
103
+ tableName: 'programs',
104
+ topicName: topicName,
105
+ projectId: 'some-project-id',
106
+ pubSubMaxExtensionMinutes: 20,
107
+ pubSubMinAckDeadline: 10,
108
+ pubSubMaxAckDeadline: {"millis":600000}
109
+ };
110
+ const result = await e2eTestReuse.beforeEach(topicName);
111
+ mockConstructorSpy = result.mockConstructorSpy;
112
+ publisher = result.publisher;
113
+
114
+ });
115
+
116
+ describe('#Program Executor', function () {
117
+ it('should execute program and maintain status in DB: two skipped jobs', async function () {
118
+ const runId = await ProgramExecutor.create(config).createProgram(
119
+ {
120
+ programData: {
121
+ customerId: customerId
122
+ },
123
+ jobs: ['current_program', 'next_program']
124
+ }
125
+ );
126
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
127
+
128
+ await e2eTestReuse.waitForMessages(1000);
129
+
130
+ const result = await dbConnection('programs').where({ run_id: runId }).first();
131
+
132
+ expect(result.run_id).toBe(runId);
133
+ expect(result.jobs).toEqual(['current_program', 'next_program']);
134
+ expect(result.step).toEqual(1);
135
+ expect(result.errored_at).toEqual(null);
136
+ expect(result.finished_at).not.toEqual(null);
137
+ expect(result.program_data).toEqual({ customerId: 1234 });
138
+ });
139
+
140
+ it('should execute program and maintain status in DB: two skipped jobs (with flow control config)', async function () {
141
+ const runId = await ProgramExecutor.create(configFlowControl).createProgram(
142
+ {
143
+ programData: {
144
+ customerId: customerId
145
+ },
146
+ jobs: ['current_program', 'next_program']
147
+ }
148
+ );
149
+ await ProgramExecutor.create(configFlowControl).processPrograms(testJobLibrary);
150
+
151
+ await e2eTestReuse.waitForMessages(1000);
152
+
153
+ const result = await dbConnection('programs').where({ run_id: runId }).first();
154
+
155
+ expect(result.run_id).toBe(runId);
156
+ expect(result.jobs).toEqual(['current_program', 'next_program']);
157
+ expect(result.step).toEqual(1);
158
+ expect(result.errored_at).toEqual(null);
159
+ expect(result.finished_at).not.toEqual(null);
160
+ expect(result.program_data).toEqual({ customerId: 1234 });
161
+ });
162
+
163
+ it('should execute program and maintain status in DB: one executed job', async function () {
164
+ const runId = await ProgramExecutor.create(config).createProgram(
165
+ {
166
+ programData: {
167
+ customerId: customerId
168
+ },
169
+ jobs: ['successful_job']
170
+ }
171
+ );
172
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
173
+
174
+ await e2eTestReuse.waitForMessages(1000);
175
+
176
+ const result = await dbConnection('programs').where({ run_id: runId }).first();
177
+
178
+ expect(result.run_id).toBe(runId);
179
+ expect(result.jobs).toEqual(['successful_job']);
180
+ expect(result.step).toEqual(0);
181
+ expect(result.errored_at).toEqual(null);
182
+ expect(result.finished_at).not.toEqual(null);
183
+ expect(result.program_data).toEqual({ customerId: 1234 });
184
+ });
185
+
186
+ it('should execute program and maintain status in DB: one failed job', async function () {
187
+ const runId = await ProgramExecutor.create(config).createProgram(
188
+ {
189
+ programData: {
190
+ customerId: customerId
191
+ },
192
+ jobs: ['problematic_job']
193
+ }
194
+ );
195
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
196
+
197
+ await e2eTestReuse.waitForMessages(1000);
198
+
199
+ const result = await dbConnection('programs').where({ run_id: runId }).first();
200
+
201
+ expect(result.run_id).toBe(runId);
202
+ expect(result.jobs).toEqual(['problematic_job']);
203
+ expect(result.step).toEqual(0);
204
+ expect(result.errored_at).not.toEqual(null);
205
+ expect(result.finished_at).toEqual(null);
206
+ expect(result.program_data).toEqual({ customerId: 1234 });
207
+ });
208
+ });
209
+ });
@@ -0,0 +1,84 @@
1
+ 'use strict';
2
+
3
+ const consumer = require('@emartech/pubsub-client-js').Consumer;
4
+ const EventEmitter = require('events');
5
+
6
+ const ProgramHandler = require('./program-handler');
7
+ const ProgramsRepository = require('./repositories/programs');
8
+ const QueueManager = require('./queue-manager-pubsub');
9
+
10
+ class ProgramExecutor extends EventEmitter {
11
+ /**
12
+ * @param {object} config
13
+ * @param {object} config.knex - Connected Knex instance
14
+ * @param {string} config.projectId - GCP Project ID
15
+ * @param {string} config.tableName - Table name for bookkeeping
16
+ * @param {string} config.topicName - Topic name to publish to
17
+ * @param {string} config.pubSubMaxExtensionMinutes - Pubsub lease management: max extension minutes
18
+ * @param {string} config.pubSubMinAckDeadline - Pubsub lease management: Min Ack Dead line
19
+ * @param {string} config.pubSubMaxAckDeadline - Pubsub lease management: Max Ack Dead line
20
+ */
21
+ constructor(config) {
22
+ super();
23
+ this._config = config;
24
+ this._programsRepository = ProgramsRepository.create(config.knex, config.tableName);
25
+ this._queueManager = QueueManager.create(config.topicName, config.projectId);
26
+ this._programHandler = ProgramHandler.create(this._programsRepository, this._queueManager);
27
+ }
28
+
29
+ /**
30
+ * @param {object} data
31
+ * @param {object} data.programData
32
+ * @param {array} data.jobs
33
+ * @param {object} data.jobsData
34
+ */
35
+ createProgram(data) {
36
+ return this._programHandler.createProgram(data);
37
+ }
38
+
39
+ processPrograms(jobLibrary) {
40
+ const eventEmitter = this; // eslint-disable-line consistent-this
41
+
42
+ const programExecutorProcessor = require('./program-executor-processor').create(
43
+ this._programHandler,
44
+ this._queueManager,
45
+ jobLibrary
46
+ );
47
+
48
+ consumer
49
+ .create(this._config.topicName,
50
+ {
51
+ logger: `${this._config.topicName}-consumer`,
52
+ MaxStreams: 1,
53
+ MaxMessages: 1,
54
+ MaxExtensionMinutes:this._config.pubSubMaxExtensionMinutes || 60,
55
+ MinAckDeadline:this._config.pubSubMinAckDeadline || undefined,
56
+ MaxAckDeadline:this._config.pubSubMaxAckDeadline || undefined,
57
+ onMessage: async (message) => {
58
+ try {
59
+ await programExecutorProcessor.process(message);
60
+ } catch (error) {
61
+ eventEmitter.emit('programError', { message, error });
62
+ error.message = error.message.substring(0, 255);
63
+ throw error;
64
+ }
65
+ }
66
+ },
67
+ { projectId: this._config.projectId }
68
+ )
69
+ .process();
70
+ }
71
+
72
+ /**
73
+ * @param {object} config
74
+ * @param {object} config.knex - Connected Knex instance
75
+ * @param {string} config.projectId - GCP Project ID
76
+ * @param {string} config.tableName - Table name for bookkeeping
77
+ * @param {string} config.topicName - Topic name to publish to
78
+ */
79
+ static create(config) {
80
+ return new ProgramExecutor(config);
81
+ }
82
+ }
83
+
84
+ module.exports = ProgramExecutor;
@@ -0,0 +1,160 @@
1
+ 'use strict';
2
+
3
+ const ProgramExecutor = require('./index-pubsub');
4
+ const ProgramHandler = require('./program-handler');
5
+ const ProgramsRepository = require('./repositories/programs');
6
+ const QueueManager = require('./queue-manager-pubsub');
7
+ const ProgramExecutorProcessor = require('./program-executor-processor');
8
+ const Consumer = require('@emartech/pubsub-client-js').Consumer;
9
+
10
+ const testJobLibrary = {
11
+ firstJob: {},
12
+ secondJob: {}
13
+ };
14
+
15
+ describe('ProgramExecutor', function () {
16
+ let config;
17
+
18
+ beforeEach(async function () {
19
+ config = {
20
+ knex: this.db,
21
+ tableName: 'programs',
22
+ topicName: 'program-executor',
23
+ projectId: 'amqp://guest:guest@localhost:9999',
24
+ pubSubMaxExtensionMinutes: 60,
25
+ pubSubMinAckDeadline: {'millis':600000},
26
+ pubSubMaxAckDeadline: {'millis':600000}
27
+ };
28
+
29
+
30
+ jest.spyOn(ProgramHandler, 'create');
31
+ ProgramHandler.prototype.createProgram = jest.fn().mockReturnValue(true);
32
+
33
+ jest.spyOn(ProgramsRepository, 'create');
34
+ jest.spyOn(QueueManager, 'create');
35
+ jest.spyOn(ProgramExecutorProcessor, 'create');
36
+
37
+ ProgramExecutorProcessor.prototype.process = jest.fn().mockReturnValue(true);
38
+ jest.spyOn(Consumer, 'create');
39
+ Consumer.prototype.process = jest.fn().mockReturnValue(true);
40
+
41
+
42
+ });
43
+
44
+ describe('#createProgram', function () {
45
+ it('should create program handler and call createProgram with given data', async function () {
46
+ await ProgramExecutor.create(config).createProgram({
47
+ jobs: ['current_program', 'next_program']
48
+ });
49
+
50
+ expect(ProgramHandler.create).toHaveBeenCalledWith(
51
+ expect.any(ProgramsRepository),
52
+ expect.any(QueueManager)
53
+ );
54
+ expect(ProgramsRepository.create).toHaveBeenCalledWith(config.knex, config.tableName);
55
+ expect(QueueManager.create).toHaveBeenCalledWith(config.topicName, config.projectId);
56
+ expect(ProgramHandler.prototype.createProgram).toHaveBeenCalledWith({
57
+ jobs: ['current_program', 'next_program']
58
+ });
59
+ });
60
+ });
61
+
62
+ describe('#processPrograms', function () {
63
+ it('should create program executor processor with job library', async function () {
64
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
65
+
66
+ expect(ProgramExecutorProcessor.create).toHaveBeenCalledWith(
67
+ expect.any(Object), //TODO check
68
+ expect.any(QueueManager),
69
+ testJobLibrary
70
+ );
71
+
72
+ expect(ProgramsRepository.create).toHaveBeenCalledWith(config.knex, config.tableName);
73
+ expect(QueueManager.create).toHaveBeenCalledWith(config.topicName, config.projectId);
74
+ });
75
+
76
+ it('should create consumer with the given pubsub config', async function () {
77
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
78
+
79
+ expect(Consumer.create.mock.calls[0][0]).toEqual(config.topicName);
80
+ });
81
+
82
+ it('should create consumer to consume the given topic', async function () {
83
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
84
+
85
+ expect(Consumer.create.mock.calls[0][1]).toEqual(expect.objectContaining({
86
+ MaxMessages: 1,
87
+ MaxStreams: 1,
88
+ MaxExtensionMinutes: 60,
89
+ MinAckDeadline:{'millis':600000},
90
+ MaxAckDeadline:{'millis':600000},
91
+ logger: 'program-executor-consumer' }));
92
+ });
93
+
94
+ it('should create consumer with a logger based on the given topic name', async function () {
95
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
96
+
97
+ expect(Consumer.create.mock.calls[0][1]).toEqual(
98
+ expect.objectContaining({ logger: `${config.topicName}-consumer` }));
99
+ });
100
+
101
+ it('should config consumer with given flow control settings', async function () {
102
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
103
+
104
+ expect(Consumer.create.mock.calls[0][1]).toEqual(
105
+ expect.objectContaining({ MaxMessages: 1,
106
+ MaxStreams: 1 }));
107
+ });
108
+
109
+ it('should call the created executor when message callback fires', async function () {
110
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
111
+
112
+ const onMessageFunction = Consumer.create.mock.calls[0][1].onMessage;
113
+
114
+ await onMessageFunction({ random: 'message' });
115
+
116
+ expect(ProgramExecutorProcessor.prototype.process).toHaveBeenCalledWith({ random: 'message' });
117
+ });
118
+
119
+ it('should truncate log message to avoid splitting by heroku', async function () {
120
+ const veryLongError = new Error('1'.repeat(100000));
121
+
122
+ ProgramExecutorProcessor.prototype.process = jest.fn().mockRejectedValue(veryLongError);
123
+
124
+ let caughtError;
125
+ try {
126
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
127
+ const onMessageFunction = Consumer.create.mock.calls[0][1].onMessage;
128
+ await onMessageFunction({ random: 'message' });
129
+ } catch (error) {
130
+ caughtError = error;
131
+ }
132
+
133
+ expect(caughtError).not.toBe(undefined);
134
+ expect(caughtError.message.length).toEqual(255);
135
+ });
136
+
137
+ it('should emit an error event', function (done) {
138
+ const sampleError = new Error('Error to be emitted');
139
+ ProgramExecutorProcessor.prototype.process = jest.fn().mockRejectedValue(sampleError);
140
+
141
+ const programExecutor = ProgramExecutor.create(config);
142
+
143
+ programExecutor.on('programError', function ({ error, message }) {
144
+ expect(message).toEqual({ random: 'message' });
145
+ expect(error.message).toEqual('Error to be emitted');
146
+ done();
147
+ });
148
+
149
+ programExecutor.processPrograms(testJobLibrary);
150
+ const onMessageFunction = Consumer.create.mock.calls[0][1].onMessage;
151
+ onMessageFunction({ random: 'message' }).catch(() => {});
152
+ });
153
+
154
+ it('should start processing', async function () {
155
+ await ProgramExecutor.create(config).processPrograms(testJobLibrary);
156
+
157
+ expect(Consumer.prototype.process).toHaveBeenCalled();
158
+ });
159
+ });
160
+ });
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const ProgramExecutor = require('./');
3
+ const ProgramExecutor = require('.');
4
4
  const ProgramHandler = require('./program-handler');
5
5
  const ProgramsRepository = require('./repositories/programs');
6
6
  const QueueManager = require('./queue-manager');
@@ -23,125 +23,129 @@ describe('ProgramExecutor', function () {
23
23
  amqpUrl: 'amqp://guest:guest@localhost:9999'
24
24
  };
25
25
 
26
- this.sandbox.spy(ProgramHandler, 'create');
27
- this.sandbox.stub(ProgramHandler.prototype, 'createProgram');
28
26
 
29
- this.sandbox.spy(ProgramsRepository, 'create');
30
- this.sandbox.spy(QueueManager, 'create');
27
+ jest.spyOn(ProgramHandler, 'create');
28
+ ProgramHandler.prototype.createProgram = jest.fn().mockReturnValue(true);
29
+
30
+ jest.spyOn(ProgramsRepository, 'create');
31
+ jest.spyOn(QueueManager, 'create');
32
+ jest.spyOn(ProgramExecutorProcessor, 'create');
33
+
34
+ ProgramExecutorProcessor.prototype.process = jest.fn().mockReturnValue(true);
35
+ jest.spyOn(Consumer, 'create');
36
+ Consumer.prototype.process = jest.fn().mockReturnValue(true);
31
37
 
32
- this.sandbox.spy(ProgramExecutorProcessor, 'create');
33
- this.sandbox.stub(ProgramExecutorProcessor.prototype, 'process');
34
38
 
35
- this.sandbox.spy(Consumer, 'create');
36
- this.sandbox.stub(Consumer.prototype, 'process');
37
39
  });
38
40
 
39
- describe('#createProgram', async function () {
41
+ describe('#createProgram', function () {
40
42
  it('should create program handler and call createProgram with given data', async function () {
41
43
  await ProgramExecutor.create(config).createProgram({
42
44
  jobs: ['current_program', 'next_program']
43
45
  });
44
46
 
45
- expect(ProgramHandler.create).to.have.been.calledWith(
46
- this.sinon.match.instanceOf(ProgramsRepository),
47
- this.sinon.match.instanceOf(QueueManager)
47
+ expect(ProgramHandler.create).toHaveBeenCalledWith(
48
+ expect.any(ProgramsRepository),
49
+ expect.any(QueueManager)
48
50
  );
49
- expect(ProgramsRepository.create).to.have.been.calledWith(config.knex, config.tableName);
50
- expect(QueueManager.create).to.have.been.calledWith(config.amqpUrl, config.queueName);
51
- expect(ProgramHandler.prototype.createProgram).to.have.been.calledWith({
51
+ expect(ProgramsRepository.create).toHaveBeenCalledWith(config.knex, config.tableName);
52
+ expect(QueueManager.create).toHaveBeenCalledWith(config.amqpUrl, config.queueName);
53
+ expect(ProgramHandler.prototype.createProgram).toHaveBeenCalledWith({
52
54
  jobs: ['current_program', 'next_program']
53
55
  });
54
56
  });
55
57
  });
56
58
 
57
- describe('#processPrograms', async function () {
59
+ describe('#processPrograms', function () {
58
60
  it('should create program executor processor with job library', async function () {
59
61
  await ProgramExecutor.create(config).processPrograms(testJobLibrary);
60
62
 
61
- expect(ProgramExecutorProcessor.create).to.have.been.calledWith(
62
- this.sinon.match.instanceOf(ProgramHandler),
63
- this.sinon.match.instanceOf(QueueManager),
63
+ expect(ProgramExecutorProcessor.create).toHaveBeenCalledWith(
64
+ expect.any(Object), //TODO check
65
+ expect.any(QueueManager),
64
66
  testJobLibrary
65
67
  );
66
68
 
67
- expect(ProgramsRepository.create).to.have.been.calledWith(config.knex, config.tableName);
68
- expect(QueueManager.create).to.have.been.calledWith(config.amqpUrl, config.queueName);
69
+ expect(ProgramsRepository.create).toHaveBeenCalledWith(config.knex, config.tableName);
70
+ expect(QueueManager.create).toHaveBeenCalledWith(config.amqpUrl, config.queueName);
69
71
  });
70
72
 
71
73
  it('should create consumer with the given rabbitMq config', async function () {
72
74
  await ProgramExecutor.create(config).processPrograms(testJobLibrary);
73
75
 
74
- expect(Consumer.create.lastCall.args[0]).to.eql({ default: { url: config.amqpUrl } });
76
+ expect(Consumer.create.mock.calls[0][0]).toEqual({ default: { url: config.amqpUrl } });
75
77
  });
76
78
 
77
79
  it('should create consumer to consume the given queue', async function () {
78
80
  await ProgramExecutor.create(config).processPrograms(testJobLibrary);
79
81
 
80
- expect(Consumer.create.lastCall.args[1]).to.containSubset({ channel: config.queueName });
82
+ expect(Consumer.create.mock.calls[0][1]).toEqual(
83
+ expect.objectContaining({ channel: config.queueName }));
81
84
  });
82
85
 
83
86
  it('should create consumer with a logger based on the given queue name', async function () {
84
87
  await ProgramExecutor.create(config).processPrograms(testJobLibrary);
85
88
 
86
- expect(Consumer.create.lastCall.args[1]).to.containSubset({ logger: `${config.queueName}-consumer` });
89
+ expect(Consumer.create.mock.calls[0][1]).toEqual(
90
+ expect.objectContaining({ logger: `${config.queueName}-consumer` }));
87
91
  });
88
92
 
89
93
  it('should config consumer with prefecth count and a retry time', async function () {
90
94
  await ProgramExecutor.create(config).processPrograms(testJobLibrary);
91
95
 
92
- expect(Consumer.create.lastCall.args[1]).to.containSubset({ prefetchCount: 1, retryTime: 1000 });
96
+ expect(Consumer.create.mock.calls[0][1]).toEqual(
97
+ expect.objectContaining({ prefetchCount: 1, retryTime: 1000 }));
93
98
  });
94
99
 
95
100
  it('should call the created executor when message callback fires', async function () {
96
101
  await ProgramExecutor.create(config).processPrograms(testJobLibrary);
97
102
 
98
- const onMessageFunction = Consumer.create.lastCall.args[1].onMessage;
103
+ const onMessageFunction = Consumer.create.mock.calls[0][1].onMessage;
99
104
 
100
105
  await onMessageFunction({ random: 'message' });
101
106
 
102
- expect(ProgramExecutorProcessor.prototype.process).to.have.been.calledWith({ random: 'message' });
107
+ expect(ProgramExecutorProcessor.prototype.process).toHaveBeenCalledWith({ random: 'message' });
103
108
  });
104
109
 
105
110
  it('should truncate log message to avoid splitting by heroku', async function () {
106
111
  const veryLongError = new Error('1'.repeat(100000));
107
112
 
108
- ProgramExecutorProcessor.prototype.process.rejects(veryLongError);
113
+ ProgramExecutorProcessor.prototype.process = jest.fn().mockRejectedValue(veryLongError);
109
114
 
110
115
  let caughtError;
111
116
  try {
112
117
  await ProgramExecutor.create(config).processPrograms(testJobLibrary);
113
- const onMessageFunction = Consumer.create.lastCall.args[1].onMessage;
118
+ const onMessageFunction = Consumer.create.mock.calls[0][1].onMessage;
114
119
  await onMessageFunction({ random: 'message' });
115
120
  } catch (error) {
116
121
  caughtError = error;
117
122
  }
118
123
 
119
- expect(caughtError).not.to.be.undefined;
120
- expect(caughtError.message.length).to.eql(255);
124
+ expect(caughtError).not.toBe(undefined);
125
+ expect(caughtError.message.length).toEqual(255);
121
126
  });
122
127
 
123
128
  it('should emit an error event', function (done) {
124
129
  const sampleError = new Error('Error to be emitted');
125
-
126
- ProgramExecutorProcessor.prototype.process.rejects(sampleError);
130
+ ProgramExecutorProcessor.prototype.process = jest.fn().mockRejectedValue(sampleError);
127
131
 
128
132
  const programExecutor = ProgramExecutor.create(config);
129
133
 
130
134
  programExecutor.on('programError', function ({ error, message }) {
131
- expect(message).to.eql({ random: 'message' });
132
- expect(error.message).to.eql('Error to be emitted');
135
+ expect(message).toEqual({ random: 'message' });
136
+ expect(error.message).toEqual('Error to be emitted');
133
137
  done();
134
138
  });
135
139
 
136
140
  programExecutor.processPrograms(testJobLibrary);
137
- const onMessageFunction = Consumer.create.lastCall.args[1].onMessage;
141
+ const onMessageFunction = Consumer.create.mock.calls[0][1].onMessage;
138
142
  onMessageFunction({ random: 'message' }).catch(() => {});
139
143
  });
140
144
 
141
145
  it('should start processing', async function () {
142
146
  await ProgramExecutor.create(config).processPrograms(testJobLibrary);
143
147
 
144
- expect(Consumer.prototype.process).to.have.been.called;
148
+ expect(Consumer.prototype.process).toHaveBeenCalled();
145
149
  });
146
150
  });
147
151
  });