Skip to content

Integration test #209

@josephktcheung

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

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