-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature]: typesafe assertions #13334
Comments
Fix it. Just open a PR (; |
Would love |
Hi, can I try this? |
Yeah, go for it! |
Hey guys! I'm facing a problem here.
and when I test in a local app using it works fine and TypeScript gives me the error But when I add the same assertion to the Does anyone know what could be happening here? |
here is index e2fc97916..d7d6f7cfd 100644
--- a/packages/expect/src/types.ts
+++ b/packages/expect/src/types.ts
@@ -94,9 +94,9 @@ export interface BaseExpect {
}
export type Expect = {
- <T = unknown>(actual: T): Matchers<void> &
- Inverse<Matchers<void>> &
- PromiseMatchers;
+ <T = unknown>(actual: T): Matchers<void, T> &
+ Inverse<Matchers<void, T>> &
+ PromiseMatchers<T>;
} & BaseExpect &
AsymmetricMatchers &
Inverse<Omit<AsymmetricMatchers, 'any' | 'anything'>>;
@@ -118,20 +118,20 @@ export interface AsymmetricMatchers {
stringMatching(sample: string | RegExp): AsymmetricMatcher;
}
-type PromiseMatchers = {
+type PromiseMatchers<E = unknown> = {
/**
* Unwraps the reason of a rejected promise so any other matcher can be chained.
* If the promise is fulfilled the assertion fails.
*/
- rejects: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>>>;
+ rejects: Matchers<Promise<void>, E> & Inverse<Matchers<Promise<void>, E>>;
/**
* Unwraps the value of a fulfilled promise so any other matcher can be chained.
* If the promise is rejected the assertion fails.
*/
- resolves: Matchers<Promise<void>> & Inverse<Matchers<Promise<void>>>;
+ resolves: Matchers<Promise<void>, E> & Inverse<Matchers<Promise<void>, E>>;
};
-export interface Matchers<R extends void | Promise<void>> {
+export interface Matchers<R extends void | Promise<void>, E = unknown> {
/**
* Ensures the last call to a mock function was provided specific args.
*/
@@ -152,7 +152,7 @@ export interface Matchers<R extends void | Promise<void>> {
* Checks that a value is what you expect. It calls `Object.is` to compare values.
* Don't use `toBe` with floating-point numbers.
*/
- toBe(expected: unknown): R;
+ toBe(expected: E): R;
/**
* Ensures that a mock function is called.
*/ |
Most probably you should build the repo and all will work. By the way, to test the change you should write type tests. The type tests for matchers live here: packages/jest-types/typetests/expect.test.ts To run them, build the repo and run One use case which looks problematic: For example, here is what Usage example: expect('abc').toBe<string>('abc');
expect('abc').not.toBe<number>(123); This approach works for many other matchers too (just look through Is it really useful? Is it worth to spend time implementing? These are other questions. |
i can't really think of a use case where you'd want to explicitly specify the generics for non-matching types as i can't see how it provides any additional safety. imo in those cases using |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
not stale |
Similar change was made in |
to address some of the points mentioned in that discussion:
however if this really is too big of a breaking change, i would suggest making a new typesafe api while keeping the old one, like what dart is doing |
One can use type arguments for extra type safety as well. I think we could agree that there is no consensus on this feature and that is why it is not implemented. Would you agree that EDIT That is right that the DT's PR was implementing more than just |
do you mean how it runs the tests on each change? idk, i often turn that off because it can be resource-intensive to be running tests constantly. i always think it's better to see type errors before having to run any code, which is kinda the point of using typescript in the first place it also wouldn't pick up cases where for example a function that works properly at runtime could have the incorrect type at compiletime // foo.d.ts
export declare const doThing: () => number // wrong type // foo.js
export const doThing = () => 'asdf' // foo.spec.ts
import { doThing } from './foo'
test('doThing', () => {
expect(doThing()).toBe('asdf') // no compile error or runtime error
}) |
Usually I run slow e2e tests separately from unit tests. In this setup The other problem you talk about needs a type test. In Jest repo we run type tests via I understand that the line between TypeScript and JavaScript is very thin, but look at Jest website: "Jest is a delightful JavaScript Testing Framework". It does not sound like Jest promised to check your types. The point is that Jest should allow everything what JavaScript allows and test only the logic of your code. So seeing no error in your example is correct. Perhaps a custom transformer is a solution? The TS Compiler API allows custom module resolution. It is pretty simply to make it load something else instead of import from @CreativeTechGuy ping. We had similar discussion in DefinitelyTyped/DefinitelyTyped#63610 |
Actually, no need to have any option or to wrestle with the Compiler API and no need to involve import {expect} from 'jest-strictly-typed-expect'; Could work like this too (I did not try): import type {StrictlyTypedMatchers} from 'jest-strictly-typed-matchers';
declare module 'expect' {
interface Matchers<R> extends StrictlyTypedMatchers<R> {}
} |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
Not stale |
Matchers isn't as typed as some users would like (see jestjs#13334, jestjs#13812). For users who want to customize it by extending the `Matchers` interface, it's useful to have access to the type of `actual` (the argument of `expect`) so you can do, say, ```ts interface Matchers<R, T> { toTypedEqual(expected: T): R } ``` This commit exposes it. The first-party matchers still have the same types as before.
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
Not stale |
i really think this issue needs to be addressed. jest's assertion library is used by many other testing tools, so this problem comes up in many different places.
expect(page.locator('li').count()).toBe(2) //comparing Promise<number> to number this is just one example where the error could easily be caught at compiletime, but it isn't. playwright isn't just used for e2e tests either (see https://playwright.dev/docs/test-components)
times have changed since that was written. typescript is the standard now, and i can't think of any excuse to not be using it over javascript in the current year. so many "typescript-first" projects use jest's assertion library under the hood, so it seems a little counter-productive to not support it properly. |
@mrazauskas I feel that this comment is somewhat misguided, if an end user is using JavaScript, then they will not see any TypeScript type errors, if the user has opted into using TypeScript then they explicitly want to see type errors and expect the language to behave in the most useful way possible (showing type errors where available). To opt out of type correctness in this one example seems to go counter to the concepts of typing and type safety in general. FYI, Kotlin uses this tight strictness for assertions: https://kotlinlang.org/api/latest/kotlin.test/kotlin.test/assert-equals.html |
Changes in this repo will have no effect on Playwright’s After #13848 it should be possible to redeclare matcher typings as strict as you like them. (Not sure if that will work for Playwright.) |
i mean it won't have an immediate effect but if they're copying jest's assertion library it's reasonable to assume they will eventually update it with upstream changes. otherwise they wouldn't close issues that suggest changes to it |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
Not stale |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
Not stale |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
Not stale |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
Not stale |
Just use |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
🚀 Feature Proposal
this will always fail, but since typescript infers the type as
unknown
, there's no compile error:Motivation
it will allow you to identify errors in your tests much earlier, speeding up development 🚀🚀🚀
Example
Pitch
the current
expect
types make using typescript with jest pretty much useless. i think if jest is going to support typescript, it should support basic functionality like thisThe text was updated successfully, but these errors were encountered: