jamiemason / expect-more Goto Github PK
View Code? Open in Web Editor NEWCurried Type Testing library, and Test Matchers for Jest
License: MIT License
Curried Type Testing library, and Test Matchers for Jest
License: MIT License
Had some good feedback on toSurvive
that it would be easier to understand if redesigned as:
expect(unsafe).toHandleMissingBranches(shape);
expect(unsafe).toHandleMissingLeaves(shape);
expect(unsafe).toHandleMissingNodes(shape);
expect(unsafe).toHandleNullBranches(shape);
expect(unsafe).toHandleNullLeaves(shape);
expect(unsafe).toHandleNullNodes(shape);
instead of:
expect(safe).toSurvive(gen.nullNodes(shape));
and to use lodash.get in the docs example instead of getIn
.
https://github.com/Dean177/jest-to-match-shape-of is a working example.
Although the matchers are registered correctly, they need to be done a particular way for the types to extend Jest correctly in TypeScript.
When using:
expect(arrayOfObjects).toBeArrayOfSize(n)
I am getting errors from expect-more on creation of the jest error message when the test fails:
TypeError: Cannot convert object to primitive value
at Array.join (<anonymous>)
at Array.toString (<anonymous>)
at message (node_modules/expect-more-jest/dist/to-be-array-of-size.js:7:51)
at message (node_modules/expect-more-jest/dist/lib/create-result.js:6:62)
at getMessage (node_modules/expect/build/index.js:209:15)
at processResult (node_modules/expect/build/index.js:327:25)
at Object.toBeArrayOfSize (node_modules/expect/build/index.js:396:16)
Assert collection
Array or Object contains any key from the provided array
of key names.
Asserts date
is on or after floorDate
and on or before ceilingDate
.
I have a case when the field can be present or not in the object. I would like to check the field if it's present in the object
Case 1: { a: 10, b: 'qwerty' }
Case 2: { a: 10, b: 'qwerty' , c: 10}
(this won't work)
expect({ a: 10, b: 'qwerty' }).toMatchObject({
a: expect.toBePositiveNumber(),
b: expect.toBeNonEmptyString(),
c: expect.toBeOptionalOf(expect.toBeNumber()),
})
Returns error:
Expected: {"a": toBePositiveNumber<>, "b": toBeNonEmptyString<>, "c": toBeOptionalOf<toBeNumber>}
Received: {"a": 10, "b": "qwerty"}
Maybe there is a way to check optional field?
Assert array
contains any value from the provided values
.
Why toBeWithinRange
is commented in Jest implementation and will it come back?
Asserts date
occurs on date of the month between 1 and 31.
There's a standalone package for jest-expect, but it uses different namespace from jest itself, and also different type names for matchers, so it's impossible to simply reuse expect-more-jest
package for this case.
It would really be very helpful to be able to extend that package with your matchers.
I'm using jest in esm mode, because my code simply requires it. But i can't use this library as it expects jest globals.
Import expect
from @jest/globals
.
https://jestjs.io/docs/ecmascript-modules#differences-between-esm-and-commonjs
Assert collection
Array or Object contains every key from the provided array
of key names.
The issue is in these 3 lines, a second argument is needed to received the shape
.
Cover with tests and fix code and typings.
Should be something like:
const createToHandleComparer = (matcherName: string, createGenerator: generatorCreator) =>
(received: () => void), shape: any[] | object) => {
const generator: IGenerator = createGenerator(shape);
const result = generator.assert(received);
// ....
When expecting against an async function in TypeScript, I find that
expect(fn).toBeFunction();
fails. Delving deeper, it's because the implementation doesn't just do something along the lines of:
assert(typeof(actual) === "function");
(which is how I've implemented toBeFunction before just being lazy and relying on expect-more-jest
). So the typescript test for the above fails because
Object.prototype.toString.call(fn) === "[object AsyncFunction]";
I wrote out the matcher and typings to complete this, in my repo:
import MatchersUtil = jasmine.MatchersUtil;
import CustomEqualityTester = jasmine.CustomEqualityTester;
import CustomMatcherResult = jasmine.CustomMatcherResult;
declare module jest {
interface Matchers<R> {
toBeAsyncFunction<R>(): void;
}
}
function assert(expr, failMessage) {
if (!expr) {
throw new Error(failMessage);
}
}
function runAssertions(func: () => void) {
try {
func();
return {
message: "",
pass: true
};
} catch (e) {
return {
pass: false,
message: e.message || e
};
}
}
jest.addMatchers({
toBeAsyncFunction: function (util: MatchersUtil, customEqualityTester: CustomEqualityTester[]) {
return {
compare: function (actual: any): CustomMatcherResult {
return runAssertions(() =>
assert(Object.prototype.toString.call(actual) === "[object AsyncFunction]",
`expected async function but got ${JSON.stringify(actual)}`)
);
}
};
}
});
Apologies for:
assert
and try/catch
-- I expect to add more matchers and have found this to be a relatively simple way to add more matchersI cloned this repo because I wanted to create a PR for this, but I can't successfully run tests -- npm test
doesn't run for me (**). I'm probably doing something wrong, so I'd appreciate a push in the right direction, in which case, I'll just submit a PR (: In the meantime, .toBeFunction
doesn't appear to recognise async functions correctly.
** What I have tried:
npm test
fails, throwing errors about invalid syntax around import
statements. Replacing the inbuilt transpile-tests.js
by installing ts-jest
and using that instead, fixed that, but then came:expect-more
. Now, I can see that each item under packages
has its own package.json
, but tests are run in the context of the base package; also, this is a bit of a chicken-and-egg: I can't write tests against the new code without uploading the package, if I'm to expect the import from the expect-more
in each package.json to suffice. I've tried hard-linking the src
folder of package.json
to the node_modules
folder in the base -- which gets tests to run, but many fail (for example isDivisibleBy
fails on typescript errors, saying that isDivisibleBy
should take two arguments -- and afaik, this is the difference between jasmine 1 and 2 tests? Not sure; anyhoo, I'm a bit lost as to the correct way to run tests and there's no point making a PR if I can't even prove that what I've added works :/ But again, given a push in the right direction, I'll gladly have a swing at it.isNonEmptyString
for example has a return type of : boolean
where : value is string
would be more useful.
I tried expect.not.toBeIso8601()
as an asymmetric matcher and got this error:
error TS2339: Property 'toBeIso8601' does not exist on type 'InverseAsymmetricMatchers'.
A fix like this needs to be done for every matcher. In the meantime, this same code works as a workaround in my user code:
declare global {
namespace jest {
interface InverseAsymmetricMatchers {
toBeIso8601(): any
}
}
}
P.S. I really appreciate this library. It gets the algebra correct and lets me reuse existing matchers (which throw errors with rich diffs) instead of making me write all-new predicates (that return boolean
with no diffs) unlike jest-extended
. Now I just have to get Jest to fix toHaveBeenCalledWith
(and friends) to stop masking the rich diffs...
The scaffolder newts
installs expect-even-more-jest
which depends on expect-more-jest
. After creating a project with the latest of both (npx newts@beta
), tests cannot run:
FAIL tests/index.spec.ts
โ Test suite failed to run
Cannot find module 'expect/build/jasmineUtils' from 'node_modules/expect-more-jest/dist/to-be-array-of.js'
Require stack:
node_modules/expect-more-jest/dist/to-be-array-of.js
node_modules/expect-more-jest/dist/index.js
node_modules/expect-even-more-jest/dist/index.js
tests/index.spec.ts
at Resolver._throwModNotFoundError (node_modules/jest/node_modules/jest-resolve/build/resolver.js:491:11)
at Object.<anonymous> (node_modules/expect-more-jest/dist/to-be-array-of.js:5:22)
delving a little deeper, by doing:
global.expect = require("expect");
require("expect-more-jest");
produces
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './build/jasmineUtils' is not defined by "exports" in C:\tmp\moo-cakes-wtf\node_modules\expect\package.json
at throwExportsNotFound (internal/modules/esm/resolve.js:299:9)
at packageExportsResolve (internal/modules/esm/resolve.js:522:3)
at resolveExports (internal/modules/cjs/loader.js:424:36)
at Function.Module._findPath (internal/modules/cjs/loader.js:464:31)
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:802:27)
at Function.Module._load (internal/modules/cjs/loader.js:667:27)
at Module.require (internal/modules/cjs/loader.js:887:19)
at require (internal/modules/cjs/helpers.js:74:18)
at Object.<anonymous> (C:\tmp\moo-cakes-wtf\node_modules\expect-more-jest\dist\to-be-array-of.js:5:22)
at Module._compile (internal/modules/cjs/loader.js:999:30) {
code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'
}
Perhaps copy-pasta the required code or use a git submodule to get to it?
If I get a moment, I'll try raise a PR
Hi there, thanks for a great library!
I'm having some TypeScript compiler errors on my project:
expect(result.sentAt).toBeIso8601();
Property 'toBeIso8601' does not exist on type 'Matchers<string>'.
I'm using TypeScript 2.9.2 with the following dependencies:
"@types/jest": "^23.3.0"
"expect-more-jest": "^2.0.0"
"jest": "^23.4.1"
I've tried to get around it for now by hacking the interface, but it makes my tests a little bit harder to read:
interface ExtendedMatchers extends jest.Matchers<R> {
toBeIso8601(): R;
}
// usage example
(expect(result.sentAt) as ExtendedMatchers).toBeIso8601();
Asserts date
is the same as or after otherDate
Asserts date
is the same as or before otherDate
Assert collection is an Array containing functions.
Asserts date
occurs on day of the week with index
, where Sunday is 0
and Saturday is 6
.
This project only declares devDependencies
which is not really accurate. devDependencies
are not transitory which means there is not currently any declared version compatibility limitation with respect to Jest and this project when used together in another project. However, this project breaks with jest
and jest-jasmine2
^28:
Cannot find module 'expect/build/jasmineUtils' from 'node_modules/expect-more-jest/dist/to-be-array-of.js'
Require stack:
node_modules/expect-more-jest/dist/to-be-array-of.js
node_modules/expect-more-jest/dist/index.js
at Resolver._throwModNotFoundError (node_modules/jest-runtime/node_modules/jest-resolve/build/resolver.js:491:11)
at Object.<anonymous> (node_modules/expect-more-jest/dist/to-be-array-of.js:5:22)
This project should be declaring regular runtime dependencies or peer dependencies for any version requirements it needs to run. Otherwise, users of this library are not alerted that this library even requires jest
let alone that it only works with certain versions.
Assert array
Array contains every value in the provided values
.
Asserts date
occurs in year
as number eg. 1969
Asserts date
occurs in month
, between 0 (January) and 11 (December).
expect-more-jest
should be migrated to jest v29 deps
upgrade deps
This library is very good. However the documentation doesn't mention that the matchers are also asymmetric. I had to test this by doing:
expect([{ dt: new Date('2021-08-29') }]).toBeArrayOf({ dt:
expect.toBeDateInMonth(7)
});
It'd be nice if this was mentioned as this is one of the best things about this lib.
Also document that this works with Vitest
When stating complex or partial matches on things like parameters, is is often necessary to compare the contents of objects in an array. With standard expectations like arrayContaining
, you can do this using asymmetric matchers like this:
test('should contain important objects in array', () => {
const array = [
{
important: 'important',
ignore: 'ignore'
},
{
ignore: 'ignore',
}
];
expect(soy).toHaveBeenCalledWith(expect.arrayContaining(
[expect.objectContaining({ important: 'important' })]
));
});
One would expect that expectations like toBeArrayIncludingOnly
would follow the same semantic rules as arrayContaining
and be a "drop in" replacement. However, this is not currently true because toBeArrayIncludingOnly
(and others) do not appear to support asymmetric matching.
Array functions similar to arrayContaining
should follow the same semantic rules and be "drop in" replacements by support asymmetric matchers.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.