-
-
Notifications
You must be signed in to change notification settings - Fork 225
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
Closes #253: Add change matchers, .toChange(), .toChangeBy(), .toChangeTo() #521
base: main
Are you sure you want to change the base?
Conversation
It looks like the |
@keeganwitt is there anything I can do to help progress this forward? |
Thanks for the PR! I'll try to take a look this week. |
Codecov Report
@@ Coverage Diff @@
## main #521 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 72 77 +5
Lines 594 642 +48
Branches 151 161 +10
=========================================
+ Hits 594 642 +48
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
I haven't forgotten about you. I've been ill the last several days. |
I'm kinda questioning whether there's value in adding |
I've wondered if this should be assuming numbers. expect(() =>menu.updateDailySpecial(tuesday)).toChangeTo(() => menu.dailySpecial, 'Meatloaf'); |
I think // first bowl is free
expect(() => {
lunch.add("chips and salsa")
}).not.toChange(() => lunch.totalCost())
// but the second bowl will cost you
expect(() => {
lunch.add("chips and salsa")
}).toChange(() => lunch.totalCost()) |
… support for non-numeric values
That's fair. |
I'm still on the fence about adding these. They do improve readability, but they don't reduce any setup. There's not any use case I can think of that is made easier by having these. This project tries to add matches that provide a certain "threshold" of value and not to add every conceivable matcher. I'm still thinking about whether this feature has reached that threshold. |
Naturally I think it brings enough value, I wouldn't have opened the PR if I didn't. I expect that I have an argument that would convince you, but with Thanksgiving preparations I don't have a lot of time to write up a full explanation, so I'll put in a brief, bulleted version for now and maybe provide more context if needed after the holiday.
expect(Product.count()).toEqual(0)
Product.create()
expect(Product.count()).toEqual(1) What you're writing is more like const initialCount = Product.count()
Product.create()
expect(Product.count()).toEqual(initialCount + 1)
|
I'm not trying to shoot this idea down. I just want to be thoughtful before proceeding. I'm also with family this week. I just wanted to let you know I was still mulling this over. The short version of what's giving me pause is const counter = new Counter();
expect(counter.increment).toChange(counter.count);
// vs
const counter = new Counter();
const originalCount = counter.count;
counter.increment();
expect(counter.count).not.toBe(originalCount); const counter = new Counter();
expect(counter.increment).toChangeBy(counter.count);
// vs
const counter = new Counter();
const originalCount = counter.count;
counter.increment();
expect(counter.count - originalCount).toEqual(originalCount + 1); const counter = new Counter();
expect(counter.increment).toChangeTo(counter.count, 1);
// vs
const counter = new Counter();
counter.increment();
expect(counter.count).toEqual(1); The new matchers save a tiny bit of code, and it's more readable, but one could ask "how far should this go?" Should we make function wrappers be added for other existing matchers? e.g. testing that a value was added/removed to an array after a function call, testing that a date was mutated by a certain amount after a function call, testing that the type of something changed to a string/boolean/number etc after a function call, testing that a number is/isn't negative after a function call, etc. Lots of matchers could have a version added that does its check after invoking a function. But I'll give what you've written some more thought. |
Adds three change matchers, .toChange(), .toChangeBy(), and .toChangeTo(), based on #253 (comment).
Instead of one matcher with variant modes, I split it into three separate matchers so that the typescript definitions would not be overloaded.
What
This is an implementation of the matchers requested in #253 with unit tests and documentation added.
Each of these matchers accept a
checker
callback function that it calls before and after invoking the mutator function. The checker function should access some mutable state value that can be modified by the code under test..toChange(checker)
Expect the state to have changed, or not to have changed when used with
.not
, by comparing to the before value with===
..toChangeBy(checker, by)
Expect the state to change by the given amount, which must be a number.
.toChangeTo(checker, to)
Expect the state to change to the given value.
Why
It's pretty common to test something that should make a change in your app, such as adding or removing an item from a list, then having an assertion to check that the count has changed. Often when we write these tests, we simply check the count of the list after the change.
This test can pass if the function works as advertised, but it can also pass if the list was empty from the start. Change matchers can assert that the state was changed by the logic you're testing.
Notes
First contribution 👋
Housekeeping