-
Notifications
You must be signed in to change notification settings - Fork 133
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
Support have_enqueued_sidekiq_job
with no args
#215
Conversation
👋 Thanks for the PR @3v0k4 In general, I don't really want to modify the behavior of The block syntax is better for exactly the reason you outlined above, it's more like the RSpec built-ins folks are used to: expect { raise StandardError.new("arg") }.not_to raise_error # fails
expect { AwesomeJob.perform_async }.not_to enqueue_sidekiq_job # fails Modifying the expected arguments coming into # should enqueue job without arguments
AwesomeJob.perform_async
# expects no argument
expect(AwesomeJob).to have_enqueue_sidekiq_job
# later an argument is added but maybe the job wasn't updated to handle it
AwesomeJob.peform_async "oh no"
# expectation still passes with the new `any_args` default
expect(AwesomeJob).to have_enqueue_sidekiq_job
# passes While we could argue that default is "less bad", both are not great. That's why the documentation is as plain as possible about what the current default is and why the block syntax is preferred. |
Isn't it true also for def enqueue
AwesomeJob.peform_async
end
expect { enqueue }.to enqueue_sidekiq_job # ✅
###
def enqueue
AwesomeJob.peform_async "oh no"
end
expect { enqueue }.to enqueue_sidekiq_job # ✅
I would recommend against for a couple of reasons. The block is evaluated after the expectation. Let's say I have a expect { subject.call }.to enqueue_sidekiq_job(EmailWorker).with(User.last!.id)
subject.call
expect(EmailWorker).to have_enqueued_sidekiq_job(Organization.last!.id) It's (IMO) sometimes cleaner to use Example testing multiple workers: expect {
expect {
subject.call
}.to enqueue_sidekiq_job(OneWorker)
}.to enqueue_sidekiq_job(OtherWorker)
# vs
subject.call
expect(OneWorker).to have_enqueued_sidekiq_job
expect(OtherWorker).to have_enqueued_sidekiq_job Example testing multiple things: expect { subject.call }.to enqueue_sidekiq_job(OneWorker)
expect(User.last.flag).to eq(true)
# vs
subject.call
expect(OneWorker).to have_enqueued_sidekiq_job
expect(User.last.flag).to eq(true) You may argue those could be separate test examples, but I like that More in general, I think it makes sense to have both to satisfy the symmetry of |
🤔 All interesting perspectives and valuable feedback. Quick points on multiple expectations (while it might be more of a preference thing) the enqueue matcher is composable: expect do
OneWorker.perform_async
OtherWorker.perform_async
end.to enqueue_sidekiq_job(OneWorker).and enqueue_sidekiq_job(OtherWorker) I hear you on the How about this as a compromise: The main thing that concerns me about the change is just that the current default has been the default. The behavior, even if less clear, is what it is, and updating this might break out from under folks without warning. I'd prefer that we have a period of time where we add a warning message for uses of Would you be open to that? |
Good point on the composability! I always forget about that 🤦 Let me put together some code that incorporates what you suggested. |
3914349
to
00bf5f9
Compare
I propose we release the first commit of this PR as minor and the second one as major. WDYT? |
@3v0k4 Sounds reasonable. Are you okay with me cherry-picking your first commit onto main? |
Sure. I can also open a separate PR if you prefer. |
Let's do a separate PR so we can link discussion points from this PR into that so I have breadcrumbs to follow in the future 😄 |
I opened the separate PR. If that works for you, I'll rebase onto |
@wspurgin please give me a ping when you update the changelog on main and release the change from the other PR. I'll rebase and update |
Sorry @3v0k4 - had life come up in the last week that delayed me. I've been piloting this with some friends and coworkers, and they suggested I add way to silence the warnings if they want to make use of the new default (rather than update all their specs to explicitly use After testing that out with them today, I'll merge and release a minor version this week. If you have any thoughts on their LMK! |
@3v0k4 4.2.0 released. Feel free to rebase and this will be part of 5.0 (along with me deprecating some ruby versions) |
@wspurgin Rebased 🙏 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again @3v0k4!
Hello folks, With this change, if I, say, prefer the Say, I need to test that some particular job has not been enqueued. Before I did How do I do it after v5 upgrade, please advice. |
@pyromaniac negation is partially why we made this change, because most folks probably want "expect no job of [job class] to be enqueue". In v5 that is: expect(AwesomeJob).not_to have_enqueue_sidekiq_job(any_args) If however, you want to maintain the exact same behavior as ≤4, use: expect(AwesomeJob).not_to have_enqueue_sidekiq_job(no_args)
|
@pyromaniac say more? It should still be respected in V5. |
@wspurgin hello, I finally got to the bottom of this and you are right, everything works as you suggested. The new approach is way safer. Thanks! |
First of all, thanks for your work on
rspec-sidekiq
, it helped cleaning up our tests tremendously!When I started using
rspec-sidekiq
, I assumed it would work similarly to the builtin matchers.For example, the negation of
raise_error
works as follows:In the case of
rspec-sidekiq
, it's different:I believe the need for more documentation on this (603b9) stems from the confusing semantics.
It's especially important to provide loose matching for the negative case because it may give a sense of false confidence (I was bitten by this):
I'd argue it's a better default to check for any jobs enqueued instead of jobs with no arguments.
This change applies to both
expect(Job).not_to have_enqueued_sidekiq_job
andexpect(Job).to have_enqueued_sidekiq_job
, but we could apply it only to the negative case if you prefer.I'm happy to discuss alternatives if you think this is an issue but don't like the specific solution.
I guess in the longer term,
enqueue_sidekiq_job
andhave_enqueued_sidekiq_job
could have the same API: