Skip to content

Integration test #209

Description

@josephktcheung

Hi,

Related to #83, I'd like to share how I write Stealth's integration test. Source code can be found here https://github.com/josephktcheung/stealth-integration-test. @luizcarvalho @mgomes please take a look and see if this can be improved.

Steps:

  1. Run stealth new to generate a new stealth app

  2. Install following gems for testing

group :test do
  gem "rack-test"
  gem "rspec"
  gem "mock_redis"
end
  1. In spec/spec_helper.rb
# coding: utf-8
# frozen_string_literal: true


require 'rspec'
require 'stealth'
require 'mock_redis'
require 'sidekiq/testing'

# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'bot'))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'config'))
$LOAD_PATH.unshift(File.dirname(__FILE__))

Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
require_relative "../bot/helpers/bot_helper"

ENV['STEALTH_ENV'] = 'test'

RSpec.configure do |config|
  I18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', 'config', 'locales', '*.{rb,yml}')]
  config.include BotHelper
  config.before(:each) do |example|
    Sidekiq::Worker.clear_all
    Sidekiq::Testing.fake!
    $redis = MockRedis.new
    allow(Redis).to receive(:new).and_return($redis)
  end
  config.filter_run_when_matching :focus
  config.formatter = :documentation

  config.before(:suite) do
    Stealth.boot
  end
end
  1. Define sample_message class in spec/support/sample_message.rb
class SampleMessage

  def initialize(service:)
    @service = service
    @base_message = Stealth::ServiceMessage.new(service: @service)
    @base_message.sender_id = sender_id
    @base_message.timestamp = timestamp
    @base_message
  end

  def message_with_text(message)
    @base_message.message = message
    self
  end

  def message_with_payload(payload)
    @base_message.payload = payload
    self
  end

  def message_with_location(location)
    @base_message.location = location
    self
  end

  def message_with_attachments(attachments)
    @base_message.attachments = attachments
    self
  end

  def sender_id
    "8b3e0a3c-62f1-401e-8b0f-615c9d256b1f"
  end

  def timestamp
    @base_message.timestamp || Time.now
  end

  def to_request_json
    if @base_message.message.present?
      JSON.generate({
        entry: [
          {
            "messaging": [
              "sender": {
                "id": @base_message.sender_id
              },
              "recipient": {
                "id": "<PAGE_ID>"
              },
              "timestamp": @base_message.timestamp.to_i * 1000,
              "message": {
                "mid":"mid.1457764197618:41d102a3e1ae206a38",
                "text": @base_message.message
              }
            ]
          }
        ]
      })
    end
  end
end
  1. Define custom matcher send_reply in spec/support/matchers/send_reply.rb (Thanks @sunny for correction)
RSpec::Matchers.define :receive_message do |message|
  match do |client|
    stub = double("client")
    allow(stub).to receive(:transmit).and_return(true)
    @replies.each do |reply|
      expect(client).to receive(:new)
        .with(hash_including(reply: hash_including(reply)))
        .ordered
        .and_return(stub)
    end

    json = message.to_request_json
    post "/incoming/#{@service}", json, { "CONTENT_TYPE" => "application/json" }
  end

  chain :as_service do |service|
    @service = service
  end
  
  chain :and_send_replies do |replies|
    @replies = replies
  end
end
  1. In spec/features/chatbot_flow_spec.rb
require "spec_helper"

describe "chatbot flow" do
  include Rack::Test::Methods

  def app
    Stealth::Server
  end

  let(:message) { 
    SampleMessage.new(
      service: "facebook"
    )
  }

  let(:client) { Stealth::Services::Facebook::Client }

  it "handles user conversation" do
    Sidekiq::Testing.inline! do
      expect(client).to receive_message(
        message.message_with_text("hello")
      )
        .as_service("facebook")
        .and_send_replies([
          {
            "recipient" => {
              "id" => message.sender_id
            },
            "message" => {
              "text" => "Hello World!"
            }
          },
          {
            "recipient" => {
              "id" => message.sender_id
            },
            "message" => {
              "text" => "Goodbye World!"
            }
          }
        ])
    end
  end
end
  1. In bot/controllers/hellos_controller.rb
class HellosController < BotController

  def say_hello
    send_replies
    step_to flow: "goodbye"
  end

end
  1. Run bundle e rspec and test passes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions