Skip to content

Commit

Permalink
feat: add waitFor() for polling check ready status
Browse files Browse the repository at this point in the history
  • Loading branch information
rocwind committed Apr 11, 2021
1 parent 228e8c8 commit 3fc5e2d
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/wait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export type WaitReturn<T, Name extends string> = {
[P in `reset${Name}`]: ReadyStatusSetter<T>;
};

export const wait = <T, Name extends string = ''>(name?: Name): WaitReturn<T, Name> => {
export function wait<T, Name extends string = ''>(name?: Name): WaitReturn<T, Name> {
let readyStatus: ReadyStatusEnum = ReadyStatusEnum.Pending;
let resultValue: T;
let waitPromise: Promise<T>;
Expand Down Expand Up @@ -127,4 +127,4 @@ export const wait = <T, Name extends string = ''>(name?: Name): WaitReturn<T, Na
setResult(ReadyStatusEnum.Pending, value);
},
} as WaitReturn<T, Name>;
};
}
35 changes: 35 additions & 0 deletions src/waitFor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { waitFor } from './waitFor';

describe('waitFor()', () => {
beforeEach(() => {
jest.useFakeTimers();
});

it('resolves after second check', () => {
const check = jest.fn();
check.mockReturnValueOnce(false);
check.mockReturnValueOnce(true);

const result = waitFor(check);
jest.runAllTimers();

expect(check).toHaveBeenCalledTimes(2);
expect(setTimeout).toHaveBeenCalledTimes(1);
return expect(result).resolves.toEqual(true);
});

it('rejects when check throws error', () => {
const check = jest.fn();
check.mockReturnValueOnce(false);
check.mockImplementationOnce(() => {
throw new Error('check error');
});

const result = waitFor(check);
jest.runAllTimers();

expect(check).toHaveBeenCalledTimes(2);
expect(setTimeout).toHaveBeenCalledTimes(1);
return expect(result).rejects.toEqual(new Error('check error'));
});
});
48 changes: 48 additions & 0 deletions src/waitFor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { wait } from './wait';

/**
* check function that returns check result
* falsy values means not ready, truthy values will be used to resolve the promise
*/
type WaitForCheckFun<T> = () => T;

interface WaitForOptions {
/**
* the interval(ms) for each check, default to 200ms
*/
checkInterval?: number;
/**
* throw a timeout error and reject the promise after given timeout(ms),
* default is no timeout
*/
timeout?: number;
}

export function waitFor<T>(check: WaitForCheckFun<T>, options?: WaitForOptions): Promise<T> {
const { checkInterval = 200, timeout } = options ?? {};

const { afterReady, setReady, setFailed } = wait<T>();

const startTimestamp = Date.now();
const doCheck = () => {
try {
const result = check();
if (result) {
setReady(result);
return;
}

if (timeout && Date.now() - startTimestamp > timeout) {
setFailed((new Error('timeout') as unknown) as T);
return;
}

setTimeout(doCheck, checkInterval);
} catch (err) {
setFailed(err);
}
};
doCheck();

return afterReady();
}

0 comments on commit 3fc5e2d

Please sign in to comment.