Open steffanek opened 9 months ago
This happened as both DataTaggedError
and SchemaTaggedError
are extended from Error
, and for Error objects, now Vitest will only checks the message
prop. https://github.com/vitest-dev/vitest/blob/c692f76e58ae11fcc13631adcb4b80055843d447/packages/expect/src/jest-utils.ts#L98
Perhaps Vitest need to do more checks when both message
props are undefined
, I'm willing to make a PR to fix this.
I think jest still has the same code. There's one similar issue and even PR too, but they got closed as they didn't receive attention:
If there were no back-compat or jest-compat concern, then personally it makes sense to do the same treatment as NodeJS's assertion https://nodejs.org/api/assert.html#comparison-details_1, namely these two:
- Only enumerable "own" properties are considered.
- Error names and messages are always compared, even if these are not enumerable properties.
But in practice, changing this condition might have some larger implication.
I haven't tried but it might be possible to implement stricter Error
instance equality on user land by expect.addEqualityTesters
https://vitest.dev/api/expect.html#expect-addequalitytesters.
This happened as both
DataTaggedError
andSchemaTaggedError
are extended fromError
, and for Error objects, now Vitest will only checks themessage
prop.Perhaps Vitest need to do more checks when both
message
props areundefined
, I'm willing to make a PR to fix this.
@fenghan34 even they are extending from Error, I would expect from the toStrictEqual
to check if all key values matches. Does that make sense?
@steffanek Thanks for raising an issue btw.
The current behavior doesn't seem intuitive for me as well, but the code we're seeing here is originally from Jest https://github.com/jestjs/jest/blob/e6d60cb1ab04a2d691dcbf025ed53d7a07327889/packages/expect-utils/src/jasmineUtils.ts#L86-L88 and the comment says it's based on underscore, so it could be like more than 10 years old.
What I just wanted to add is that, there could be some reason people have been adopting this behavior, so I think it's worth spending time surveying some history and more comparison.
Like you've already shown, node:assert
is different (and personally it makes sense to me). But, we might want to also check others like lodash's isEqual
, other test frameworks and assertion libraries.
In terms of documentation, there's at least a warning about this for toEqual
(and internally toStrictEqual
doesn't treat Error
differently):
Also here is a repro to show the current behavior without effect
:
https://stackblitz.com/edit/vitest-dev-vitest-jzxduv?file=test%2Fsimple.test.ts
Next I'll see if I can do something with expect.addEqualityTesters
for the time being https://vitest.dev/api/expect.html#expect-addequalitytesters
I explored expect.addEqualityTesters
based approach and I think this should work for your use case for the time being:
https://stackblitz.com/edit/vitest-dev-vitest-944rfr?file=test%2Fbug.spec.ts
On Vitest side, probably what we can do for now is to just put more warning on documentation https://github.com/vitest-dev/vitest/pull/5253 Maybe if this behavior is desired so much, then we could introduce some opt-in flag to automatically enable this custom equality tester, but for that, we'll probably need more discussion based on use cases.
even they are extending from Error, I would expect from the
toStrictEqual
to check if all key values matches. Does that make sense?
@steffanek Yes, It makes sense to me to be honest. And I think @hi-ogawa has provided the appropriate solution at this time.
Thanks @hi-ogawa and @fenghan34 for your quick response and solution.
Another solution would be to simply import * as assert from "node:assert"
and use it directly in test files, whenever we want to check a deepStrictEqual
in case of any instances. Do you guys see some downsides? What can comes to my mind is: performance (comparing to expect.addEqualityTesters
) or wrong testing report?
Another solution would be to simply
import * as assert from "node:assert"
and use it directly in test files
Just a note, Vitest supports extended assert API: https://vitest.dev/api/assert.html
Another solution would be to simply
import * as assert from "node:assert"
and use it directly in test filesJust a note, Vitest supports extended assert API: https://vitest.dev/api/assert.html
@sheremet-va assert.deepStrictEqual
from vitest does not solve this issue.
Another solution would be to simply
import * as assert from "node:assert"
and use it directly in test files, whenever we want to check adeepStrictEqual
in case of any instances. Do you guys see some downsides? What can comes to my mind is: performance (comparing toexpect.addEqualityTesters
) or wrong testing report?
@steffanek Using node:assert
should work fine, but the downside is simply that it's not a part of expect
API, which would mean for example:
assert.deepStrictEqual(...)
if you are using expect(...).toStrictEqual(...)
around the code.expect
API works in a "stateful" way, such as expect.hasAssertions
doesn't take into assert.deepStrictEqual
account when counting the number of assertions.expect.soft
version of assert.deepStrictEqual
Regarding performance, I would guess node:assert
would be faster since expect/toEqual
does more stuff underneath. But I don't think such raw performance difference would practically matter for normal usages.
Makes sense @hi-ogawa thanks for your contribution. Let's see if this behavior is really desired, to enable it by default.
Hi @hi-ogawa it seems that I do not need anymore to use the custom matcher that you've initially provided. However, now I got the following issue (see below the last test where I compared two errors values inside an Exit data type :
import { it, expect } from "vitest";
import { Schema } from "@effect/schema";
import { Exit } from "effect";
class SchemaTaggedError extends Schema.TaggedError<SchemaTaggedError>()(
"SchemaTaggedError",
{
msg: Schema.String,
other: Schema.String,
}
) {}
class SchemaTaggedClass extends Schema.TaggedClass<SchemaTaggedClass>()(
"SchemaTaggedClass",
{
msg: Schema.String,
other: Schema.String,
}
) {}
it("Error type", () => {
expect(new SchemaTaggedError({ msg: "a", other: "other" })).toStrictEqual(
new SchemaTaggedError({ msg: "a", other: "other" })
);
});
it("Exit with SchemaTaggedClass", () => {
expect(
Exit.fail(new SchemaTaggedClass({ msg: "a", other: "other" }))
).toStrictEqual(
Exit.fail(new SchemaTaggedClass({ msg: "a", other: "other" }))
);
});
//This should not pass..
it("Exit with SchemaTaggedError", () => {
expect(
Exit.fail(new SchemaTaggedError({ msg: "a", other: "other" }))
).toStrictEqual(
Exit.fail(new SchemaTaggedError({ msg: "b", other: "other" }))
);
});
Describe the bug
Hi, I'm using the effect library to construct class instances, and I encounter the following issues, where the 2 assertions below pass (which is wrong):
I've initially raised an issue on the effect, but it result that by comparing with the native assert it works as expected:
Reproduction
reproduction on StackBlitz with the code above
System Info
Used Package Manager
pnpm
Validations