You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
363 lines
13 KiB
363 lines
13 KiB
require 'spec_helper'
|
|
|
|
class WechatController < ActionController::Base
|
|
wechat_responder
|
|
end
|
|
|
|
RSpec.describe WechatController, type: :controller do
|
|
def xml_to_hash(response)
|
|
Hash.from_xml(response.body)['xml'].symbolize_keys
|
|
end
|
|
|
|
render_views
|
|
|
|
let(:signature_params) do
|
|
timestamp = '1234567'
|
|
nonce = 'nonce'
|
|
signature = Digest::SHA1.hexdigest([ENV['WECHAT_TOKEN'], timestamp, nonce].sort.join)
|
|
{ timestamp: timestamp, nonce: nonce, signature: signature }
|
|
end
|
|
|
|
let(:message_base) do
|
|
{
|
|
ToUserName: 'toUser',
|
|
FromUserName: 'fromUser',
|
|
CreateTime: '1348831860',
|
|
MsgId: '1234567890123456'
|
|
}
|
|
end
|
|
|
|
let(:text_message) { message_base.merge(MsgType: 'text', Content: 'text message') }
|
|
|
|
specify 'config responder using global config' do
|
|
expect(controller.class.wechat).to eq(Wechat.api)
|
|
expect(controller.class.token).to eq(Wechat.config.token)
|
|
end
|
|
|
|
describe 'config responder using per controller configuration' do
|
|
controller do
|
|
wechat_responder appid: 'controller_appid', secret: 'controller_secret', token: 'controller_token',
|
|
access_token: 'controller_access_token',
|
|
agentid: 1, encoding_aes_key: 'encoding_aes_key'
|
|
end
|
|
specify 'will set controller wechat api and token' do
|
|
access_token = controller.class.wechat.access_token
|
|
expect(access_token.appid).to eq('controller_appid')
|
|
expect(access_token.secret).to eq('controller_secret')
|
|
expect(access_token.token_file).to eq('controller_access_token')
|
|
expect(controller.class.token).to eq('controller_token')
|
|
expect(controller.class.agentid).to eq(1)
|
|
expect(controller.class.encrypt_mode).to eq(false)
|
|
expect(controller.class.encoding_aes_key).to eq('encoding_aes_key')
|
|
end
|
|
end
|
|
|
|
describe 'Verify signature' do
|
|
specify 'on show action' do
|
|
get :show, signature_params.merge(signature: 'invalid_signature')
|
|
expect(response.code).to eq('403')
|
|
end
|
|
|
|
specify 'on create action' do
|
|
post :create, signature_params.merge(signature: 'invalid_signature')
|
|
expect(response.code).to eq('403')
|
|
end
|
|
end
|
|
|
|
specify "echo 'echostr' param when show" do
|
|
get :show, signature_params.merge(echostr: 'hello')
|
|
expect(response.body).to eq('hello')
|
|
end
|
|
|
|
describe 'responders' do
|
|
specify 'responders only accept :text, :image, :voice, :video, :location, :link, :event, :fallback message type' do
|
|
[:text, :image, :voice, :video, :location, :link, :event, :fallback].each do |message_type|
|
|
controller.class.on message_type, respond: 'response'
|
|
end
|
|
end
|
|
|
|
specify 'will raise error if message type is unkonwn' do
|
|
expect { controller.class.on :unkonwn, respond: 'response' }.to raise_error
|
|
end
|
|
|
|
specify 'responder take :with argument only for :text and :event message_type' do
|
|
expect(controller.class.on :text, with: 'command', respond: 'response').to eq(with: 'command', respond: 'response')
|
|
expect(controller.class.on :event, with: 'subscribe').to eq(with: 'subscribe')
|
|
expect { controller.class.on :image, with: 'with' }.to raise_error
|
|
end
|
|
end
|
|
|
|
describe 'responder_for' do
|
|
controller do
|
|
wechat_responder
|
|
on :text, with: 'command', respond: 'string matched'
|
|
on :text, with: /^cmd:(.*)$/, respond: 'regex matched'
|
|
on :text, respond: 'text content'
|
|
on :event, with: 'subscribe', respond: 'subscribe event'
|
|
on :click, with: 'EVENTKEY', respond: 'EVENTKEY clicked'
|
|
on :image, respond: 'image content'
|
|
end
|
|
|
|
specify 'find first responder for matched type' do
|
|
expect do |b|
|
|
controller.class.responder_for(MsgType: 'image', &b)
|
|
end.to yield_with_args(respond: 'image content')
|
|
end
|
|
|
|
specify "find 'general text' responder if none of the text responders matches request content" do
|
|
expect do |b|
|
|
controller.class.responder_for(MsgType: 'text', Content: 'some text', &b)
|
|
end.to yield_with_args({ respond: 'text content' }, 'some text')
|
|
end
|
|
|
|
specify "find 'string matched' responder if request content matches string" do
|
|
expect do |b|
|
|
controller.class.responder_for(MsgType: 'text', Content: 'command', &b)
|
|
end.to yield_with_args({ respond: 'string matched', with: 'command' }, 'command')
|
|
end
|
|
|
|
specify "find 'regex mached' responder if request content matches regex" do
|
|
expect do |b|
|
|
controller.class.responder_for(MsgType: 'text', Content: 'cmd:my_command', &b)
|
|
end.to yield_with_args({ respond: 'regex matched', with: /^cmd:(.*)$/ }, 'my_command')
|
|
end
|
|
|
|
specify "find 'subscribe event' responder if event request matches event" do
|
|
expect do |b|
|
|
controller.class.responder_for(MsgType: 'event', Event: 'subscribe', &b)
|
|
end.to yield_with_args({ respond: 'subscribe event', with: 'subscribe' }, 'subscribe')
|
|
end
|
|
|
|
specify "find 'click' responder if event request matches click" do
|
|
expect do |b|
|
|
controller.class.responder_for(MsgType: 'event', Event: 'click', EventKey: 'EVENTKEY', &b)
|
|
end.to yield_with_args({ respond: 'EVENTKEY clicked', with: 'EVENTKEY' }, 'EVENTKEY')
|
|
end
|
|
end
|
|
|
|
specify 'will respond empty if no responder for the message type' do
|
|
post :create, signature_params.merge(xml: text_message)
|
|
expect(response.code).to eq('200')
|
|
expect(response.body.strip).to be_empty
|
|
end
|
|
|
|
describe 'respond_to wechat helper' do
|
|
controller do
|
|
wechat_responder
|
|
on :text do |_message, _content|
|
|
wechat
|
|
end
|
|
end
|
|
|
|
specify 'will return normal' do
|
|
expect do
|
|
post :create, signature_params.merge(xml: text_message)
|
|
end.not_to raise_error
|
|
end
|
|
end
|
|
|
|
describe 'respond_to wechat_url helper' do
|
|
controller do
|
|
wechat_responder
|
|
on :text do |_message, _content|
|
|
wechat_url
|
|
end
|
|
end
|
|
|
|
specify 'will return normal' do
|
|
expect do
|
|
post :create, signature_params.merge(xml: text_message)
|
|
end.not_to raise_error
|
|
end
|
|
end
|
|
|
|
describe 'fallback responder' do
|
|
controller do
|
|
wechat_responder
|
|
on :fallback, respond: 'fallback responder'
|
|
end
|
|
|
|
specify 'will respond to any message' do
|
|
post :create, signature_params.merge(xml: text_message)
|
|
expect(xml_to_hash(response)[:Content]).to eq('fallback responder')
|
|
end
|
|
end
|
|
|
|
describe 'fallback responder transfer to customer service' do
|
|
controller do
|
|
wechat_responder
|
|
on :fallback do |message|
|
|
message.reply.transfer_customer_service
|
|
end
|
|
end
|
|
|
|
specify 'will change MsgType to transfer_customer_service' do
|
|
post :create, signature_params.merge(xml: text_message)
|
|
expect(xml_to_hash(response)[:MsgType]).to eq 'transfer_customer_service'
|
|
end
|
|
end
|
|
|
|
describe 'default text transfer to customer service' do
|
|
controller do
|
|
wechat_responder
|
|
on :text do |request, _content|
|
|
request.reply.transfer_customer_service
|
|
end
|
|
end
|
|
|
|
specify 'will change MsgType to transfer_customer_service' do
|
|
post :create, signature_params.merge(xml: text_message)
|
|
expect(xml_to_hash(response)[:MsgType]).to eq 'transfer_customer_service'
|
|
end
|
|
end
|
|
|
|
describe '#create use cases' do
|
|
controller do
|
|
wechat_responder
|
|
on :text, respond: 'text message' do |message, _content|
|
|
message.replay.text('should not be here')
|
|
end
|
|
|
|
on :text, with: 'command' do |message, content|
|
|
message.reply.text("text: #{content}")
|
|
end
|
|
|
|
on :text, with: /^cmd:(.*)$/ do |message, cmd|
|
|
message.reply.text("cmd: #{cmd}")
|
|
end
|
|
|
|
on :text, with: 'session count' do |message|
|
|
message.session[:count] ||= 0
|
|
message.session[:count] += 1
|
|
message.reply.text message.session[:count]
|
|
end
|
|
|
|
on :event, with: 'subscribe' do |message, event|
|
|
message.reply.text("event: #{event}")
|
|
end
|
|
|
|
on :event, with: 'unsubscribe' do |message|
|
|
message.reply.success
|
|
end
|
|
|
|
on :scan, with: 'qrscene_xxxxxx' do |request, ticket|
|
|
request.reply.text "Unsubscribe user #{request[:FromUserName]} Ticket #{ticket}"
|
|
end
|
|
|
|
on :scan, with: 'scene_id' do |request, ticket|
|
|
request.reply.text "Subscribe user #{request[:FromUserName]} Ticket #{ticket}"
|
|
end
|
|
|
|
on :event, with: 'scan' do |request|
|
|
if request[:EventKey].present?
|
|
request.reply.text "event scan got EventKey #{request[:EventKey]} Ticket #{request[:Ticket]}"
|
|
end
|
|
end
|
|
|
|
on :location do |message|
|
|
message.reply.text("Latitude: #{message[:Latitude]} Longitude: #{message[:Longitude]}")
|
|
end
|
|
|
|
on :image do |message|
|
|
message.reply.text("image: #{message[:PicUrl]}")
|
|
end
|
|
|
|
on :voice do |message|
|
|
message.reply.text("voice: #{message[:MediaId]}")
|
|
end
|
|
|
|
on :video do |message|
|
|
message.reply.text("video: #{message[:MediaId]}")
|
|
end
|
|
|
|
on :link do |message|
|
|
message.reply.text("link: #{message[:Url]}")
|
|
end
|
|
end
|
|
|
|
specify 'response with respond field' do
|
|
post :create, signature_params.merge(xml: text_message.merge(Content: 'message'))
|
|
result = xml_to_hash(response)
|
|
expect(result[:ToUserName]).to eq('fromUser')
|
|
expect(result[:FromUserName]).to eq('toUser')
|
|
expect(result[:Content]).to eq('text message')
|
|
end
|
|
|
|
specify 'response text with text match' do
|
|
post :create, signature_params.merge(xml: text_message.merge(Content: 'command'))
|
|
expect(xml_to_hash(response)[:Content]).to eq('text: command')
|
|
end
|
|
|
|
specify 'response text with regex matched' do
|
|
post :create, signature_params.merge(xml: text_message.merge(Content: 'cmd:reload'))
|
|
expect(xml_to_hash(response)[:Content]).to eq('cmd: reload')
|
|
end
|
|
|
|
specify 'response text with session count' do
|
|
post :create, signature_params.merge(xml: text_message.merge(Content: 'session count'))
|
|
expect(xml_to_hash(response)[:Content]).to eq('1')
|
|
end
|
|
|
|
specify 'response subscribe event with matched event' do
|
|
event_message = message_base.merge(MsgType: 'event', Event: 'subscribe', EventKey: 'qrscene_not_exist')
|
|
post :create, signature_params.merge(xml: event_message)
|
|
expect(xml_to_hash(response)[:Content]).to eq('event: subscribe')
|
|
end
|
|
|
|
specify 'response unsubscribe event with matched event' do
|
|
event_message = message_base.merge(MsgType: 'event', Event: 'unsubscribe')
|
|
post :create, signature_params.merge(xml: event_message)
|
|
expect(response.code).to eq('200')
|
|
expect(response.body).to eq('success')
|
|
end
|
|
|
|
specify 'response subscribe scan event with matched event' do
|
|
event_message = message_base.merge(MsgType: 'event', Event: 'subscribe', EventKey: 'qrscene_xxxxxx')
|
|
post :create, signature_params.merge(xml: event_message.merge(Ticket: 'TICKET'))
|
|
expect(xml_to_hash(response)[:Content]).to eq 'Unsubscribe user fromUser Ticket TICKET'
|
|
end
|
|
|
|
specify 'response scan event with matched event' do
|
|
event_message = message_base.merge(MsgType: 'event', Event: 'SCAN', EventKey: 'scene_id')
|
|
post :create, signature_params.merge(xml: event_message.merge(Ticket: 'TICKET'))
|
|
expect(xml_to_hash(response)[:Content]).to eq 'Subscribe user fromUser Ticket TICKET'
|
|
end
|
|
|
|
specify 'response scan event with by_passed scene_id' do
|
|
event_message = message_base.merge(MsgType: 'event', Event: 'SCAN', EventKey: 'scene_id_by_pass_scan_process')
|
|
post :create, signature_params.merge(xml: event_message.merge(Ticket: 'TICKET'))
|
|
expect(xml_to_hash(response)[:Content]).to eq 'event scan got EventKey scene_id_by_pass_scan_process Ticket TICKET'
|
|
end
|
|
|
|
specify 'response location' do
|
|
message = message_base.merge(MsgType: 'event', Event: 'LOCATION', Latitude: 23.137466, Longitude: 113.352425, Precision: 119.385040)
|
|
post :create, signature_params.merge(xml: message)
|
|
expect(xml_to_hash(response)[:Content]).to eq('Latitude: 23.137466 Longitude: 113.352425')
|
|
end
|
|
|
|
specify 'response image' do
|
|
image_message = message_base.merge(MsgType: 'image', MediaId: 'image_media_id', PicUrl: 'pic_url')
|
|
post :create, signature_params.merge(xml: image_message)
|
|
expect(xml_to_hash(response)[:Content]).to eq('image: pic_url')
|
|
end
|
|
|
|
specify 'response voice' do
|
|
message = message_base.merge(MsgType: 'voice', MediaId: 'voice_media_id', Format: 'format')
|
|
post :create, signature_params.merge(xml: message)
|
|
expect(xml_to_hash(response)[:Content]).to eq('voice: voice_media_id')
|
|
end
|
|
|
|
specify 'response video' do
|
|
message = message_base.merge(MsgType: 'video', MediaId: 'video_media_id', ThumbMediaId: 'thumb_media_id')
|
|
post :create, signature_params.merge(xml: message)
|
|
expect(xml_to_hash(response)[:Content]).to eq('video: video_media_id')
|
|
end
|
|
|
|
specify 'response link' do
|
|
message = message_base.merge(MsgType: 'link', Url: 'link_url', Title: 'title', Description: 'description')
|
|
post :create, signature_params.merge(xml: message)
|
|
expect(xml_to_hash(response)[:Content]).to eq('link: link_url')
|
|
end
|
|
end
|
|
end
|