deno_std icon indicating copy to clipboard operation
deno_std copied to clipboard

Consider adding "testing/expect.ts" module

Open bartlomieju opened this issue 3 years ago • 24 comments

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.

bartlomieju avatar Jan 02 '22 11:01 bartlomieju

Good suggestion, but I believe it would be better to create a separate library rather than include it in deno std.

getspooky avatar Jan 03 '22 15:01 getspooky

@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.

bartlomieju avatar Jan 05 '22 03:01 bartlomieju

I like the idea. This makes the migration of existing libraries from node to deno very much easier.

kt3k avatar Jan 18 '22 07:01 kt3k

@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)

getspooky avatar Jan 18 '22 10:01 getspooky

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 ?

standvpmnt avatar Feb 19 '22 16:02 standvpmnt

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.

bartlomieju avatar Feb 19 '22 16:02 bartlomieju

Yes, simply importing it doesn't work in deno I suppose because of some module and dependency resolution.

standvpmnt avatar Feb 19 '22 18:02 standvpmnt

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.

bartlomieju avatar Feb 19 '22 22:02 bartlomieju

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?

standvpmnt avatar Feb 20 '22 07:02 standvpmnt

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 avatar Apr 23 '22 07:04 TomokiMiyauci

@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 avatar Apr 23 '22 12:04 bartlomieju

@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 avatar Apr 23 '22 15:04 TomokiMiyauci

@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 avatar Apr 23 '22 17:04 bartlomieju

@TomokiMiyauci looks awesome! I'd be more than happy to include it in the deno_std if you wanted to upstream it.

bartlomieju avatar Apr 23 '22 18:04 bartlomieju

@TomokiMiyauci should I expect a PR from you adding this API?

bartlomieju avatar May 05 '22 11:05 bartlomieju

@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 the not property can be checked via this.) Therefore, most matchers have error messages for not. unitest does not treat not 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?

TomokiMiyauci avatar May 06 '22 16:05 TomokiMiyauci

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 avatar May 06 '22 16:05 bartlomieju

@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 avatar May 07 '22 05:05 TomokiMiyauci

@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.

kt3k avatar May 07 '22 10:05 kt3k

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).

bartlomieju avatar May 07 '22 11:05 bartlomieju

@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 avatar May 07 '22 18:05 TomokiMiyauci

@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 avatar Jun 01 '22 15:06 kt3k

@kt3k Thanks for the response.

I will start working on the pull request. It may possibly be different from the current unitest implementation.

TomokiMiyauci avatar Jun 02 '22 01:06 TomokiMiyauci

@TomokiMiyauci Have you made any progress on this? Is there anything we can help on it?

kt3k avatar Nov 05 '22 12:11 kt3k

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.

timreichen avatar Nov 05 '22 13:11 timreichen

@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 avatar Nov 06 '22 11:11 TomokiMiyauci

@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 avatar Nov 06 '22 12:11 kt3k

@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.

TomokiMiyauci avatar Nov 07 '22 04:11 TomokiMiyauci

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

TomokiMiyauci avatar Nov 15 '22 16:11 TomokiMiyauci