Created
February 19, 2022 23:37
-
-
Save pcafstockf/6458879d2d155c44a390e8a84fba2a4d to your computer and use it in GitHub Desktop.
Do you really need Jest?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* If you wish to break free from the embrace->extend->imprison paradigm of Jest, this little Adapter can help you gradually break free. | |
* Use these methods along with the generic statements like xdescribe instead of describe.skip ('it', 'fit', 'xit', instead of 'test') | |
* Create your new tests using these adapters, and over time swap out your Jest specific calls in existing tests. | |
* Once your project is fully converted, you can simply replace Jasmine for Jest inside your package.json and all your tests should still be green. | |
* | |
* Jest+Yarn+jsdom expose your project to almost 4,000 currently open issues, and 400ish open PRs (somebody spent personal time to submit a fix, but it is still being ignored). | |
* For Node.js based applications, I personally just don't see the need for Jest. | |
* | |
* On a related note if you add CRA into the mix, you get an *additional* 2,000ish open issues and *another* 400ish open PRs. | |
* If the purpose of testing is to ensure stability, and if your UI tests really do take an excessive amount of time using the same environment your users actually use, | |
* perhaps a better strategy would be to set up a few machines each configured to run a portion of your test files. | |
* | |
* FUTURE: | |
* I may add Mocha in here, and am open to suggestions for other helpful cross-environment adapter functions. | |
* All my projects are TypeScript, but if there is any real interest here, I'll update this gist with a pure JavaScript version. | |
* | |
* FAIR WARNING! | |
* I've been using this code for a couple of years. | |
* However, when I decided to post this gist, I added the 3 "tick" functions at the bottom. | |
* I have never used the tick functions and don't actually know if they work :-) | |
* Furthermore, they require at least Jest 26 to work. | |
* | |
* This is free and unencumbered software released into the public domain to be used however you wish. | |
* Specifically it is released under "The Unlicense" <http://unlicense.org/> as defined on 2022/02/19 | |
*/ | |
declare var jest; | |
/** | |
* Set the timeout value for when a "hung" test is considered to have failed | |
*/ | |
export function setTestTimeout(ms: number) { | |
if (typeof jest !== 'undefined') { | |
if (typeof ms === 'number') | |
jest.setTimeout(ms); | |
} | |
else { | |
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; | |
beforeAll(function() { | |
jasmine.DEFAULT_TIMEOUT_INTERVAL = ms; | |
}); | |
afterAll(function() { | |
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; | |
}); | |
} | |
} | |
/** | |
* Create a simple function that when invoked will record its arguments and return value for each invocation. | |
* | |
* @param impl An optional delegate/callback to perform user specified operations. | |
*/ | |
export function createFnSpy(impl?: (...args: any[]) => any) { | |
if (typeof jest !== 'undefined') | |
return jest.fn(impl); | |
else { | |
let retVal = jasmine.createSpy('spy', impl); | |
if (impl) { | |
retVal = retVal.and.callFake((...args: any[]) => { | |
return impl(...args); | |
}); | |
} | |
return retVal; | |
} | |
} | |
/** | |
* Wrap the specified method of an object and return a spy for that object. | |
*/ | |
export function spyOnObject(obj: any, methodName: string) { | |
if (typeof jest !== 'undefined') | |
return jest.spyOn(obj, methodName); | |
else | |
return spyOn(obj, methodName).and.callThrough(); | |
} | |
/** | |
* Retrieve the arguments for all (or a specific) invocation(s) of a spy function or object method | |
*/ | |
export function spyCallArguments(spy: any, invocationIdx?: number) { | |
if (typeof jest !== 'undefined') { | |
if (typeof invocationIdx === 'number' && invocationIdx >= 0) | |
return spy.mock?.calls?.[invocationIdx]; | |
return spy.mock?.calls; | |
} | |
else { | |
if (typeof invocationIdx === 'number' && invocationIdx >= 0) | |
return spy.calls?.argsFor(invocationIdx); | |
return spy.calls?.allArgs(); | |
} | |
} | |
/** | |
* Retrieve the results of all (or a specific) invocation(s) of a spy function or object method. | |
*/ | |
export function spyCallResult(spy: any, invocationIdx?: number) { | |
if (typeof jest !== 'undefined') { | |
if (typeof invocationIdx === 'number' && invocationIdx >= 0) | |
spy.mock?.results?.[invocationIdx]?.value; | |
return spy.mock?.results?.map(m => m.value); | |
} | |
else { | |
if (typeof invocationIdx === 'number' && invocationIdx >= 0) | |
return spy.calls?.all()[invocationIdx]?.returnValue; | |
return spy.calls?.all().map(m => m.returnValue); | |
} | |
} | |
/** | |
* Exit a test with a specific failure. | |
*/ | |
export function failTest(err: string | Error, done?: (e?: Error) => void) { | |
if (typeof jest !== 'undefined') { | |
if (typeof err === 'string') | |
err = new Error(err); | |
if (typeof done === 'function') | |
done(err); | |
else | |
throw err; | |
} | |
else { | |
fail(err); | |
if (typeof done === 'function') | |
done(); | |
} | |
} | |
/** | |
* Stop the system clock from automatically advancing. | |
* WARNING: Don't forget to ensure @see resumeTicks is called to undo the effects of this function. | |
* @param date Optionally set the system time to a specific Date. | |
*/ | |
export function suspendTicks(date?: Date) { | |
if (typeof jest !== 'undefined') { | |
jest.useFakeTimers(); | |
if (date) | |
jest.setSystemTime(date.getTime()); | |
} | |
else { | |
jasmine.clock().install(); | |
if (date) | |
jasmine.clock().mockDate(date); | |
} | |
} | |
/** | |
* Advance the system clock by the specified number of milliseconds. | |
*/ | |
export function advanceTicks(ms: number) { | |
if (typeof jest !== 'undefined') { | |
jest.advanceTimersByTime(ms); | |
} | |
else { | |
jasmine.clock().tick(ms); | |
} | |
} | |
/** | |
* Undo the effects of @see suspendTicks | |
*/ | |
export function resumeTicks() { | |
if (typeof jest !== 'undefined') { | |
jest.useRealTimers(); | |
} | |
else { | |
jasmine.clock().uninstall(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment