Skip to content

Commit 76b6b44

Browse files
committed
feat: run in background method and test
1 parent 90e6dd1 commit 76b6b44

File tree

2 files changed

+78
-14
lines changed

2 files changed

+78
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,75 @@
1-
import { sleep } from '../async.utils';
1+
import { createLogger } from '../../logger/logger.utils';
2+
import { runInBackground, sleep } from '../async.utils';
3+
4+
jest.mock('../../logger/logger.utils', () => {
5+
const actualModule = jest.requireActual('../../logger/logger.utils');
6+
return {
7+
...actualModule,
8+
createLogger: jest.fn().mockReturnValue({
9+
error: jest.fn(),
10+
}),
11+
};
12+
});
213

314
describe('async-utils', () => {
15+
afterEach(() => {
16+
jest.clearAllMocks();
17+
});
18+
419
describe('#sleep', () => {
5-
it('should resolve after 1000ms', async () => {
6-
jest.useFakeTimers();
20+
test('it sleeps for the given milliseconds', async () => {
21+
const timeoutSpy = jest.spyOn(global, 'setTimeout');
722

8-
let didSleep = false;
23+
const sleepMillis = 100;
24+
const varianceMillis = sleepMillis * 0.5;
925

10-
const fn = jest.fn().mockImplementation(async () => {
11-
await sleep(1000);
12-
didSleep = true;
13-
});
26+
const start = Date.now();
27+
28+
await sleep(100);
29+
30+
const end = Date.now();
31+
32+
expect(timeoutSpy).toBeCalledTimes(1);
33+
expect(end - start).toBeGreaterThanOrEqual(sleepMillis - varianceMillis);
34+
expect(end - start).toBeLessThanOrEqual(sleepMillis + varianceMillis);
35+
});
36+
});
37+
38+
describe('#runInBackground', () => {
39+
test('when given a callback then it runs in background', (done) => {
40+
runInBackground(done);
41+
});
1442

15-
expect(didSleep).toBe(false); // sanity check
43+
test('when callback throws then it propagates', (done) => {
44+
try {
45+
runInBackground(() => {
46+
throw new Error('test');
47+
});
48+
} catch (error) {
49+
done();
50+
}
51+
});
1652

17-
fn(); // kick off promise in background
53+
test('when given a promise then it runs in background', (done) => {
54+
runInBackground(async () => {
55+
done();
56+
});
57+
});
1858

19-
expect(didSleep).toBe(false); // assert that sleep function hasn't resolved yet
59+
test('when promise rejects then it logs', (done) => {
60+
const logger = createLogger('async:utils');
2061

21-
jest.advanceTimersByTime(1000); // advance time for sleep function
22-
await jest.runAllTimersAsync(); // yield to let sleep function resolve
62+
runInBackground(async () => {
63+
throw new Error('test');
64+
});
2365

24-
expect(didSleep).toBe(true); // assert that sleep function resolved
66+
setTimeout(() => {
67+
expect(logger.error).toHaveBeenCalledWith(
68+
'unhandled promise exception: test',
69+
expect.any(Object)
70+
);
71+
done();
72+
}, 250);
2573
});
2674
});
2775
});

electron/common/async/async.utils.ts

+16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
import { createLogger } from '../logger/logger.utils';
2+
3+
const logger = createLogger('async:utils');
4+
15
export const sleep = (ms: number): Promise<void> => {
26
return new Promise((resolve) => setTimeout(resolve, ms));
37
};
8+
9+
/**
10+
* For "fire and forget" scenarios when you don't want, or can't, await
11+
* a function but it *is* async and so you want the errors logged, if any.
12+
*/
13+
export const runInBackground = (fn: () => Promise<unknown>): void => {
14+
Promise.resolve(fn()).catch((error) => {
15+
logger.error(`unhandled promise exception: ${error?.message}`, {
16+
error,
17+
});
18+
});
19+
};

0 commit comments

Comments
 (0)