Skip to content
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

Allow testing of commands that return multiple messages with respond_with_slack_message #157

Merged
merged 9 commits into from
Sep 18, 2017

Conversation

gcraig99
Copy link
Contributor

Allows testing of a single response out of multiple responses, and also allows testing of all responses from a single command call.

Resolves #135

@gcraig99 gcraig99 force-pushed the multiple_expect_slack_messages branch from a086f41 to 86d3188 Compare September 14, 2017 17:51
@dblock
Copy link
Collaborator

dblock commented Sep 14, 2017

I like the idea. This needs tests and a passing build, please. I would use "once" instead of "at least once" to have a stronger expectation. Maybe something more elaborate can afford for multiple repeated messages. Right now that's not the behavior for a single message.

@dblock
Copy link
Collaborator

dblock commented Sep 14, 2017

I also wonder whether we should instead introduce to_respond_with_slack_messages (plural)? Avoids the if and is clean and easily extensible.

…th_slack_message matcher was failing even if one of the messages received was the correct message. Refactored respond_with_slack_message to allow a check for a single message from multiple responses.

Also added respond_with_slack_messages matcher that can take an array of responses to test commands that return multiple messages.
Included are rspec tests for both the matchers.
README.md has been edited as well to add notes on the new matcher.
@gcraig99 gcraig99 force-pushed the multiple_expect_slack_messages branch from 86d3188 to ce559fb Compare September 15, 2017 02:54
@gcraig99
Copy link
Contributor Author

Refactored to update support for a single message from a group of messages using respond_with_slack_message and added new respond_with_slack_messages to allow checking of multiple responses at once. Agree that it's cleaner that way. Added tests for both matchers and updated README.md with notes on new matcher. A single test case is still failing for me, but it appears to be unrelated to any of my work. The VCR is not matching the response for migration_in_progress and is failing with an error that no response is available in the VCR.

@gcraig99
Copy link
Contributor Author

Build is still failing due to the above mentioned test case. If I'm missing something just let me know, but it doesn't appear that I'm the cause of that failure, copied below.

  1. SlackRubyBot::Server retries on rtm.start errors migration_in_progress
    Failure/Error:
    expect do
    subject.run
    end.to raise_error Slack::Web::Api::Error, 'unknown'

    expected Slack::Web::Api::Errors::SlackError with "unknown", got #<VCR::Errors::UnhandledHTTPRequestError: 
    

Copy link
Collaborator

@dblock dblock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good work. Lets deal with the spec failure later. Made some comments. Thanks for hanging in here!

CHANGELOG.md Outdated
@@ -1,6 +1,7 @@
### 0.10.5 (Next)

* Refactored `SlackRubyBot::MVC::Controller::Base`, consolidated ivar handling, centralized object allocations and DRYed up the code - [@chuckremes](https://github.com/chuckremes).
* [#157](https://github.com/slack-ruby/slack-ruby-bot/pull/157): Added support for checking multiple responses at once via new `respond_with_slack_messages` matcher, and single response out of multiple responses to `response_with_slack_message` matcher - [@gcraig99](https://github.com/gcraig99)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already had respond_with_slack_message (typo btw), so I would just say "Added respond_with_slack_messages RSpec expectation".

You need a period at the end of this for Danger to be happy ;)

README.md Outdated
@@ -547,6 +547,7 @@ Slack-ruby-bot ships with a number of shared RSpec behaviors that can be used in

* [behaves like a slack bot](lib/slack-ruby-bot/rspec/support/slack-ruby-bot/it_behaves_like_a_slack_bot.rb): A bot quacks like a Slack Ruby bot.
* [respond with slack message](lib/slack-ruby-bot/rspec/support/slack-ruby-bot/respond_with_slack_message.rb): The bot responds with a message.
* [respond with slack messages](lib/slack-ruby-bot/rspec/support/slack-ruby-bot/respond_with_slack_messages.rb): The bot responds with a set of message.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set of messageS or just "multiple messages"

message_command.call(client, Hashie::Mash.new(text: message, channel: channel, user: user))
expect(client).to have_received(:message).with(channel: channel, text: expected).once
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this changes behavior, ie. it allows the client to receive multiple messages that aren't the one expected plus the one expected. I think we don't want that, we want expectations to be "precise".

require 'rspec/expectations'
RSpec::Matchers.define :respond_with_slack_messages do |expected|
match do |actual|
raise ArgumentError, 'respond_with_slack_messages expects an array of ordered responses' unless expected.is_a? Array
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would check for Enumerable instead or maybe just that it responds to each? This way I can get the messages from some collection, database, whatever, if needed.

expected.each do |exp|
expect(client).to have_received(:message).with(channel: channel, text: exp).once
end
true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, I think we want exact expectations, making sure only the messages expected have been received. This behavior should have tests in both cases.

def parse(actual)
actual = { message: actual } unless actual.is_a?(Hash)
[actual[:channel] || 'channel', actual[:user] || 'user', actual[:message]]
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some duplication here with the other expectation. Maybe put the common code in a module and include it?

@dblock
Copy link
Collaborator

dblock commented Sep 15, 2017

Without debugging, the VCR error means that something is making an HTTP request that wasn't expecting. You can record that and look at what's being made by changing vcr.rb to record new episodes, but most likely there's a behavior change in the code if it's failing an old spec.

lothos and others added 4 commits September 15, 2017 16:36
…changed from start to connect in the slack-ruby-client. Changed vcr file to reflect rtm.connect.

Added better logging to respond_with_slack_message and respond_with_slack_messages so it's easier to see why the test is failing.

Added a few more tests for the message expectations.

Fixed CHANGELOG.md message as requested.
 moving common code in expectations to a module and including it.
 Checking that expected responds to each, instead of testing specifically for an array.
@gcraig99
Copy link
Contributor Author

Ok, I think I've addressed all of the concerns and we have a passing build now. If there's anything else just let me know.

Copy link
Collaborator

@dblock dblock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better. Still seems a bit complicated wrt the implementation, see my comments.


def client.say(options = {})
super
@test_received_messages = @test_received_messages.nil? ? '' : @test_received_messages
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sending messages with \n is going to confuse things, so make this an array:

test_received_messages ||= []
test_received_messages << options

SlackRubyBot::Client.new
end
client = respond_to?(:client) ? send(:client) : SlackRubyBot::Client.new
def client.test_messages
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try client.attr_accessor :test_messages instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No go, that causes an error since it's an instance of a class, rather than a class definition.

message_command.call(client, Hashie::Mash.new(text: message, channel: channel, user: user))
@messages = client.test_messages
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not leave the old code with expect, and then you don't need the failure_message at all?

allow(client).to receive(:message)
message_command.call(client, Hashie::Mash.new(text: message, channel: channel, user: user))
@messages = client.test_messages
expected.each do |exp|
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you make this expect(...) above you don't need to do this whole saving of @messages and failure_message, no? This seems unnecessarily complicated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expect statements are still there, the issue is that when using the expect statement without the custom failure message and the storage of the received messages, you don't get any useful output.

This is the output without the custom failure message:

  1. RSpec it_fails_on_purpose_to_show_output
    Failure/Error:
    expect(message: "#{SlackRubyBot.config.user} single message")
    .to respond_with_slack_message(/failure message/i)

    expected {:message=>"rubybot single message"} to respond with slack message /failure message/i

  2. RSpec respond_with_failure_to_show_output
    Failure/Error:
    expect(message: "#{SlackRubyBot.config.user} respond 5 times")
    .to respond_with_slack_messages(expected_responses)

    expected {:message=>"rubybot respond 5 times"} to respond with slack messages /response 0/i, /response 1/i, /response 2/i, /response 3/i, /response 4/i, and /response 7/i

This is the output with the custom failure message, much more useful in figuring out why it failed.

  1. RSpec it_fails_on_purpose_to_show_output
    Failure/Error:
    expect(message: "#{SlackRubyBot.config.user} single message")
    .to respond_with_slack_message(/failure message/i)

    `expected to receive message with text: (?i-mx:failure message) once,
     received:[{:text=>"single response", :channel=>"channel"}]`
    
  2. RSpec respond_with_failure_to_show_output
    Failure/Error:
    expect(message: "#{SlackRubyBot.config.user} respond 5 times")
    .to respond_with_slack_messages(expected_responses)

    expected to receive messages in order with text: [/response 0/i, /response 1/i, /response 2/i, /response 3/i, /response 4/i, /response 7/i] received:[{:text=>"response 0", :channel=>"channel"}, {:text=>"response 1", :channel=>"channel"}, {:text=>"response 2", :channel=>"channel"}, {:text=>"response 3", :channel=>"channel"}, {:text=>"response 4", :channel=>"channel"}]

@gcraig99 gcraig99 force-pushed the multiple_expect_slack_messages branch from df5b7d3 to 887980d Compare September 18, 2017 00:09
@dblock
Copy link
Collaborator

dblock commented Sep 18, 2017

Merging, thanks for the good work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants