deno_std
deno_std copied to clipboard
Consider adding "testing/expect.ts" module
Jest is arguably the most popular testing framework for Node ecosystem at the moment. It uses expect
style assertions, which seems to be very popular way of exercising tests too.
I was prompted to consider it by a recent issue in vitest
(which seems to be somewhat compatible with Jest.
To be clear: I prefer to write tests using testing/asserts.ts
, but we shouldn't limit ourselves to only a single style, if the other is also very popular (> 8mm weekly downloads) then we should consider adding it too.
Good suggestion, but I believe it would be better to create a separate library rather than include it in deno std.
@getspooky is there a reason why you would prefer it as a third party lib? The whole idea is to have it in deno_std
so it's easy to discover and could be used reliably.
I like the idea. This makes the migration of existing libraries from node to deno very much easier.
@bartlomieju could you please specify list of functions will be supported ? I think we can start with :
-
expect(value)
-
expect.anything()
-
expect.arrayContaining(array)
-
expect.assertions(number)
-
expect.hasAssertions()
-
expect.not.arrayContaining(array)
-
expect.not.objectContaining(object)
-
expect.not.stringContaining(string)
-
expect.not.stringMatching(string | regexp)
-
expect.objectContaining(object)
-
expect.stringContaining(string)
-
expect.stringMatching(string | regexp)
I might not be understanding the full context here but, could someone instead just add the expect package from jest into their project instead, by adding something like expect package from skypack ?
I might not be understanding the full context here but, could someone instead just add the expect package from jest into their project instead, by adding something like expect package from skypack ?
Yes, that would be equivalent (if the library indeed works with Deno), however we would like to make sure that this library is guaranteed to work with Deno and tested as part of our CI pipeline. I haven't tested this URL so can't say if it would just work.
@bartlomieju could you please specify list of functions will be supported ?
Ideally we would support all APIs listed in the link from the first comment, but this list is a good start.
Yes, simply importing it doesn't work in deno I suppose because of some module and dependency resolution.
Yes, simply importing it doesn't work in deno I suppose because of some module and dependency resolution.
Right, so ideally we'd have first-class support by having this module in deno_std
, so users can safely rely on it for crucial part of project which is test code.
Makes sense. From looking around, I found that there is a 3rd party package that some people in the community were working on with similar objectives deno.land/x/expect could we try reaching out to them and explore any possibilities of bringing that into standard library?
I have previously created a module unitest/expect.
With the significant enhancements to the testing environment since 1.21.0, it would be nice if this module could also be provided as a standard.
I hope my work will be of some help.
@TomokiMiyauci your module looks very interesting, but it looks like it only provides single expect
function. I was aiming for a module that would provide the same API as in Jest: https://jestjs.io/docs/expect Unless I'm misunderstanding and there are more methods available?
With the significant enhancements to the testing environment since 1.21.0, it would be nice if this module could also be provided as a standard.
Indeed, I think we are missing a few more APIs (and maybe TAP output) to have a complete testing experience.
@bartlomieju Since the API consists of pure functions only, except for throwing Error, some APIs were not implemented.
- APIs related to snapshots
-
expect.assertions
-
expect.hasAssertions
And in the interest on composability, some APIs were cut out as functions.
-
expect.extend
->extendExpect
Also, so-called asymmetric matchers (like expect.anything
) are in expect/dummy.
@TomokiMiyauci I see; I think we don't need all of the APIs in the first iteration. Could you possibly list which APIs are supported in your library?
@bartlomieju
Note that there is no guarantee of equivalence with jest
.
unitest/expect API
- expect.toBe
- expect.toEqual
- expect.toBeFalsy
- expect.toBeTruthy
- expect.toBeDefined
- expect.toBeUndefined
- expect.toBeNull
- expect.toBeNaN
- expect.toBeInstanceOf
- expect.toBeGreaterThan
- expect.toBeGreaterThanOrEqual
- expect.toBeLessThan
- expect.toBeCloseTo
- expect.toBeLessThanOrEqual
- expect.toHaveLength
- expect.toHaveBeenCalled
- expect.toHaveBeenCalledTimes
- expect.toHaveBeenCalledWith
- expect.toHaveBeenLastCalledWith
- expect.toHaveBeenNthCalledWith
- expect.toHaveReturned
- expect.toHaveReturnedTimes
- expect.toHaveReturnedWith
- expect.toHaveLastReturnedWith
- expect.toHaveNthReturnedWith
- expect.toHaveProperty
- expect.toMatchObject
- expect.toMatch
- expect.toContain
- expect.toContainEqual
- expect.toThrow
- .not
- .resolves
- .rejects
As Function
-
expect.anything
-> anything -
expect.any
-> any -
expect.arrayContaining
-> arrayContaining -
expect.stringContaining
-> stringContaining -
expect.stringMatching
-> stringMatching -
expect.extend
-> extendExpect
@TomokiMiyauci looks awesome! I'd be more than happy to include it in the deno_std if you wanted to upstream it.
@TomokiMiyauci should I expect a PR from you adding this API?
@bartlomieju I intend to issue a PR, but before I do, there is something that should be clarified.
unitest internal implementation is very different from jest. Therefore, I'm not sure if the community will like it.
Specifically, the following points are very different:
-
Proxy
It does not take a class-based approach like jest. unitest emphasizes composability, and by default, there is none. I know that deno/std does not meta-programming. https://deno.land/manual/contributing/style_guide#meta-programming-is-discouraged-including-the-use-of-proxy
-
Error message
The jest matcher depends on
not
. (The use of thenot
property can be checked viathis
.) Therefore, most matchers have error messages fornot
. unitest does not treatnot
specially. It only adds[not]
to the error message.
As you aim for a jest-like API, do you plan to provide jest-like messages as well?
Proxy
It does not take a class-based approach like jest. unitest emphasizes composability, and by default, there is none. I know that deno/std does not meta-programming. https://deno.land/manual/contributing/style_guide#meta-programming-is-discouraged-including-the-use-of-proxy
We can make exceptions to that rule, and it seems like this is one of these situations where we should.
As you aim for a jest-like API, do you plan to provide jest-like messages as well?
I aimed for Jest-like API, I don't particularly care if errors messages are the same.
@bartlomieju
I am not sure if it should be a jest like class base implementation or a unitest like Proxy implementation.
jest's expect
is a mix of matchers (e.g. toBe
), modifiers (e.g. not
, rejects
), dummy objects (e.g. anything
), and even assertions
.
Since unitest/expect is overly concerned with bundle size, only matchers and modifiers are configurable. Also, the dummy object is a pure function, and no assertions
are implemented.
If the API is to be exactly the same as jest, a class-based approach would be better. Any opinions on this point?
@TomokiMiyauci Can you give us more specific examples which show the differences of jest and unitest?
We generally don't try to make it 100% compatible with existing libraries (in this case jest) in std. So subtle difference is just fine in my view.
I agree, the high level goal is to have similar API to what Jest provides. I'd also be fine with an implementation that is a direct port of what vitest
has (linked in the first comment).
@kt3k The biggest difference is the presence of ambient(interface).
jest defines interface for matchers, etc.
The matcher interface is almost the same in jest and unitest. For example toBe
:
declare function toBe(actual: unknown, expected: unknown) {}
Matchers are defined as pure functions. (although jest depends on this
).
Since actual
is actually passed internally, the first argument, actual
, must be removed as the actual type definition.
jest overrides the type definition by interface. unitest resolves this with generics.
Because of this difference, jest cannot separate interface from implementation and has many defaults. On the other hand, because the type definition is modified by generics, there is a limitation that comments cannot appear in the intellisense.
One way to address this would be to change the matcher interface. Perhaps this is simpler.
function toBe(expected: unknown) {
// this.actual
}
@TomokiMiyauci Sorry for the delay in response. In my view, the compatibility of matcher implementation to jest version is not that important to our case. (deno_std doesn't aim to be 100% compatible with jest)
So the unitest
's matcher typing looks just fine to me.
Actually unitest
's interface looks more reasonable than jest to me, and such differences are rather welcome/desirable.
@kt3k Thanks for the response.
I will start working on the pull request. It may possibly be different from the current unitest
implementation.
@TomokiMiyauci Have you made any progress on this? Is there anything we can help on it?
Just saw this issue. I am not sure about implementing this in deno std. This is a framework and std should be as unopinionated as possible, on which 3rd party libs can build upon. As a framework, I think it is better suited for /x. There it can also be guaranteed to work with deno.
@kt3k When I learned that npm will be supported in Deno, I questioned the need for this module and left it out. Sorry about that.
Do you think this module is still necessary even after npm is fully supported?
@TomokiMiyauci
Yes, I think we still need this because Deno-first implementation is better than jest or chai via npm:
specifier in several ways (less dependencies, less downloads, better typings, etc).
npm:
feature is mainly for compatibility to existing apps/libraries, and we generally don't recommend the usage of npm:
to new projects.
@kt3k I understand.
I do not know if I will be able to do this work this week.
If it is urgent, someone can do it for me.
I am currently redesigning the internal interface of expect. The type definition complexity of unitest's expect was not good, so I am designing it to be as simple as possible.
Hopefully, I may be able to submit a Draft PR in the near future.
You can check this work in progress. https://github.com/TomokiMiyauci/expect.js