braintree 2.2.0 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/braintree.rb +1 -4
- data/lib/braintree/credit_card.rb +7 -6
- data/lib/braintree/credit_card_verification.rb +3 -2
- data/lib/braintree/customer.rb +13 -6
- data/lib/braintree/error_codes.rb +18 -7
- data/lib/braintree/error_result.rb +7 -1
- data/lib/braintree/ssl_expiration_check.rb +0 -5
- data/lib/braintree/subscription.rb +1 -0
- data/lib/braintree/transaction.rb +6 -1
- data/lib/braintree/transparent_redirect.rb +31 -0
- data/lib/braintree/version.rb +2 -2
- data/lib/braintree/xml/parser.rb +10 -2
- data/lib/braintree/xml/rexml.rb +71 -0
- data/spec/integration/braintree/credit_card_spec.rb +48 -6
- data/spec/integration/braintree/customer_spec.rb +128 -4
- data/spec/{unit → integration}/braintree/ssl_expiration_check_spec.rb +6 -14
- data/spec/integration/braintree/subscription_spec.rb +24 -11
- data/spec/integration/braintree/transaction_spec.rb +20 -4
- data/spec/integration/braintree/transparent_redirect_spec.rb +217 -2
- data/spec/spec_helper.rb +50 -2
- data/spec/unit/braintree/credit_card_spec.rb +2 -21
- data/spec/unit/braintree/credit_card_verification_spec.rb +3 -2
- data/spec/unit/braintree/customer_spec.rb +80 -0
- data/spec/unit/braintree/error_result_spec.rb +40 -0
- data/spec/unit/braintree/xml/parser_spec.rb +51 -0
- data/spec/unit/braintree/xml/rexml_spec.rb +51 -0
- metadata +28 -19
@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + "/../spec_helper"
|
|
3
3
|
describe Braintree::TransparentRedirect do
|
4
4
|
it "raises a DownForMaintenanceError when app is in maintenance mode on TR requests" do
|
5
5
|
tr_data = Braintree::TransparentRedirect.create_customer_data({:redirect_url => "http://example.com"}.merge({}))
|
6
|
-
query_string_response = SpecHelper.simulate_form_post_for_tr(Braintree::Configuration.base_merchant_url + "/test/maintenance"
|
6
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, {}, Braintree::Configuration.base_merchant_url + "/test/maintenance")
|
7
7
|
expect do
|
8
8
|
Braintree::Customer.create_from_transparent_redirect(query_string_response)
|
9
9
|
end.to raise_error(Braintree::DownForMaintenanceError)
|
@@ -12,10 +12,225 @@ describe Braintree::TransparentRedirect do
|
|
12
12
|
it "raises an AuthenticationError when authentication fails on TR requests" do
|
13
13
|
SpecHelper.using_configuration(:private_key => "incorrect") do
|
14
14
|
tr_data = Braintree::TransparentRedirect.create_customer_data({:redirect_url => "http://example.com"}.merge({}))
|
15
|
-
query_string_response = SpecHelper.simulate_form_post_for_tr(Braintree::Customer.create_customer_url
|
15
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, {}, Braintree::Customer.create_customer_url)
|
16
16
|
expect do
|
17
17
|
Braintree::Customer.create_from_transparent_redirect(query_string_response)
|
18
18
|
end.to raise_error(Braintree::AuthenticationError)
|
19
19
|
end
|
20
20
|
end
|
21
|
+
|
22
|
+
describe "self.confirm" do
|
23
|
+
context "transaction" do
|
24
|
+
it "successfully confirms a transaction create" do
|
25
|
+
params = {
|
26
|
+
:transaction => {
|
27
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
28
|
+
:credit_card => {
|
29
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
30
|
+
:expiration_date => "05/2009"
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
tr_data_params = {
|
35
|
+
:transaction => {
|
36
|
+
:type => "sale"
|
37
|
+
}
|
38
|
+
}
|
39
|
+
tr_data = Braintree::TransparentRedirect.transaction_data({:redirect_url => "http://example.com"}.merge(tr_data_params))
|
40
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, params)
|
41
|
+
result = Braintree::TransparentRedirect.confirm(query_string_response)
|
42
|
+
|
43
|
+
result.success?.should == true
|
44
|
+
transaction = result.transaction
|
45
|
+
transaction.type.should == "sale"
|
46
|
+
transaction.amount.should == BigDecimal.new("1000.00")
|
47
|
+
transaction.credit_card_details.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
|
48
|
+
transaction.credit_card_details.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
|
49
|
+
transaction.credit_card_details.expiration_date.should == "05/2009"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "returns an error when there's an error" do
|
53
|
+
params = {
|
54
|
+
:transaction => {
|
55
|
+
:amount => Braintree::Test::TransactionAmounts::Authorize,
|
56
|
+
:credit_card => {
|
57
|
+
:number => "abc",
|
58
|
+
:expiration_date => "05/2009"
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
tr_data_params = {
|
63
|
+
:transaction => {
|
64
|
+
:type => "sale"
|
65
|
+
}
|
66
|
+
}
|
67
|
+
tr_data = Braintree::TransparentRedirect.transaction_data({:redirect_url => "http://example.com"}.merge(tr_data_params))
|
68
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, params)
|
69
|
+
result = Braintree::TransparentRedirect.confirm(query_string_response)
|
70
|
+
|
71
|
+
result.success?.should == false
|
72
|
+
result.errors.for(:transaction).for(:credit_card).on(:number).size.should > 0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "customer" do
|
77
|
+
it "successfully confirms a customer create" do
|
78
|
+
params = {
|
79
|
+
:customer => {
|
80
|
+
:first_name => "John",
|
81
|
+
}
|
82
|
+
}
|
83
|
+
tr_data_params = {
|
84
|
+
:customer => {
|
85
|
+
:last_name => "Doe",
|
86
|
+
}
|
87
|
+
}
|
88
|
+
tr_data = Braintree::TransparentRedirect.create_customer_data({:redirect_url => "http://example.com"}.merge(tr_data_params))
|
89
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, params)
|
90
|
+
result = Braintree::TransparentRedirect.confirm(query_string_response)
|
91
|
+
|
92
|
+
result.success?.should == true
|
93
|
+
customer = result.customer
|
94
|
+
customer.first_name.should == "John"
|
95
|
+
customer.last_name.should == "Doe"
|
96
|
+
end
|
97
|
+
|
98
|
+
it "successfully confirms a customer update" do
|
99
|
+
customer = Braintree::Customer.create(
|
100
|
+
:first_name => "Joe",
|
101
|
+
:last_name => "Cool"
|
102
|
+
).customer
|
103
|
+
|
104
|
+
params = {
|
105
|
+
:customer => {
|
106
|
+
:first_name => "John",
|
107
|
+
}
|
108
|
+
}
|
109
|
+
tr_data_params = {
|
110
|
+
:customer_id => customer.id,
|
111
|
+
:customer => {
|
112
|
+
:last_name => "Uncool",
|
113
|
+
}
|
114
|
+
}
|
115
|
+
tr_data = Braintree::TransparentRedirect.update_customer_data({:redirect_url => "http://example.com"}.merge(tr_data_params))
|
116
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, params)
|
117
|
+
result = Braintree::TransparentRedirect.confirm(query_string_response)
|
118
|
+
|
119
|
+
result.success?.should == true
|
120
|
+
customer = Braintree::Customer.find(customer.id)
|
121
|
+
customer.first_name.should == "John"
|
122
|
+
customer.last_name.should == "Uncool"
|
123
|
+
end
|
124
|
+
|
125
|
+
it "returns an error result when there are errors" do
|
126
|
+
params = {
|
127
|
+
:customer => {
|
128
|
+
:first_name => "John",
|
129
|
+
}
|
130
|
+
}
|
131
|
+
tr_data_params = {
|
132
|
+
:customer => {
|
133
|
+
:last_name => "Doe",
|
134
|
+
:email => "invalid"
|
135
|
+
}
|
136
|
+
}
|
137
|
+
tr_data = Braintree::TransparentRedirect.create_customer_data({:redirect_url => "http://example.com"}.merge(tr_data_params))
|
138
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, params)
|
139
|
+
result = Braintree::TransparentRedirect.confirm(query_string_response)
|
140
|
+
|
141
|
+
result.success?.should == false
|
142
|
+
result.errors.for(:customer).on(:email).size.should > 0
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context "credit_card" do
|
147
|
+
it "successfully confirms a credit_card create" do
|
148
|
+
customer = Braintree::Customer.create(:first_name => "John", :last_name => "Doe").customer
|
149
|
+
|
150
|
+
params = {
|
151
|
+
:credit_card => {
|
152
|
+
:cardholder_name => "John Doe"
|
153
|
+
}
|
154
|
+
}
|
155
|
+
tr_data_params = {
|
156
|
+
:credit_card => {
|
157
|
+
:customer_id => customer.id,
|
158
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
159
|
+
:expiration_date => "10/10"
|
160
|
+
}
|
161
|
+
}
|
162
|
+
tr_data = Braintree::TransparentRedirect.create_credit_card_data(
|
163
|
+
{:redirect_url => "http://example.com"}.merge(tr_data_params)
|
164
|
+
)
|
165
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, params)
|
166
|
+
result = Braintree::TransparentRedirect.confirm(query_string_response)
|
167
|
+
|
168
|
+
result.success?.should == true
|
169
|
+
credit_card = result.credit_card
|
170
|
+
credit_card.cardholder_name.should == "John Doe"
|
171
|
+
credit_card.bin.should == Braintree::Test::CreditCardNumbers::Visa[0, 6]
|
172
|
+
credit_card.last_4.should == Braintree::Test::CreditCardNumbers::Visa[-4..-1]
|
173
|
+
credit_card.expiration_date.should == "10/2010"
|
174
|
+
end
|
175
|
+
|
176
|
+
it "successfully confirms a credit_card update" do
|
177
|
+
customer = Braintree::Customer.create(:first_name => "John", :last_name => "Doe").customer
|
178
|
+
credit_card = Braintree::CreditCard.create(
|
179
|
+
:customer_id => customer.id,
|
180
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
181
|
+
:expiration_date => "10/10"
|
182
|
+
).credit_card
|
183
|
+
|
184
|
+
params = {
|
185
|
+
:credit_card => {
|
186
|
+
:cardholder_name => "John Doe"
|
187
|
+
}
|
188
|
+
}
|
189
|
+
tr_data_params = {
|
190
|
+
:payment_method_token => credit_card.token,
|
191
|
+
:credit_card => {
|
192
|
+
:number => Braintree::Test::CreditCardNumbers::MasterCard,
|
193
|
+
:expiration_date => "11/11"
|
194
|
+
}
|
195
|
+
}
|
196
|
+
tr_data = Braintree::TransparentRedirect.update_credit_card_data(
|
197
|
+
{:redirect_url => "http://example.com"}.merge(tr_data_params)
|
198
|
+
)
|
199
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, params)
|
200
|
+
result = Braintree::TransparentRedirect.confirm(query_string_response)
|
201
|
+
|
202
|
+
result.success?.should == true
|
203
|
+
credit_card = result.credit_card
|
204
|
+
credit_card.cardholder_name.should == "John Doe"
|
205
|
+
credit_card.bin.should == Braintree::Test::CreditCardNumbers::MasterCard[0, 6]
|
206
|
+
credit_card.last_4.should == Braintree::Test::CreditCardNumbers::MasterCard[-4..-1]
|
207
|
+
credit_card.expiration_date.should == "11/2011"
|
208
|
+
end
|
209
|
+
|
210
|
+
it "returns an error result where there are errors" do
|
211
|
+
customer = Braintree::Customer.create(:first_name => "John", :last_name => "Doe").customer
|
212
|
+
|
213
|
+
params = {
|
214
|
+
:credit_card => {
|
215
|
+
:cardholder_name => "John Doe"
|
216
|
+
}
|
217
|
+
}
|
218
|
+
tr_data_params = {
|
219
|
+
:credit_card => {
|
220
|
+
:customer_id => customer.id,
|
221
|
+
:number => Braintree::Test::CreditCardNumbers::Visa,
|
222
|
+
:expiration_date => "123"
|
223
|
+
}
|
224
|
+
}
|
225
|
+
tr_data = Braintree::TransparentRedirect.create_credit_card_data(
|
226
|
+
{:redirect_url => "http://example.com"}.merge(tr_data_params)
|
227
|
+
)
|
228
|
+
query_string_response = SpecHelper.simulate_form_post_for_tr(tr_data, params)
|
229
|
+
result = Braintree::TransparentRedirect.confirm(query_string_response)
|
230
|
+
|
231
|
+
result.success?.should == false
|
232
|
+
result.errors.for(:credit_card).size.should > 0
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
21
236
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,6 +4,7 @@ unless defined?(SPEC_HELPER_LOADED)
|
|
4
4
|
project_root = File.expand_path(File.dirname(__FILE__) + "/..")
|
5
5
|
require "rubygems"
|
6
6
|
gem "libxml-ruby", ENV["LIBXML_VERSION"] || "1.1.3"
|
7
|
+
require "libxml"
|
7
8
|
gem "builder", ENV["BUILDER_VERSION"] || "2.1.2"
|
8
9
|
braintree_lib = "#{project_root}/lib"
|
9
10
|
$LOAD_PATH << braintree_lib
|
@@ -16,6 +17,14 @@ unless defined?(SPEC_HELPER_LOADED)
|
|
16
17
|
Braintree::Configuration.logger = Logger.new("/dev/null")
|
17
18
|
Braintree::Configuration.logger.level = Logger::INFO
|
18
19
|
|
20
|
+
module Kernel
|
21
|
+
alias_method :original_warn, :warn
|
22
|
+
def warn(message)
|
23
|
+
return if message =~ /^\[DEPRECATED\]/
|
24
|
+
original_warn(message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
19
28
|
module SpecHelper
|
20
29
|
|
21
30
|
DefaultMerchantAccountId = "sandbox_credit_card"
|
@@ -39,7 +48,7 @@ unless defined?(SPEC_HELPER_LOADED)
|
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
42
|
-
def self.simulate_form_post_for_tr(
|
51
|
+
def self.simulate_form_post_for_tr(tr_data_string, form_data_hash, url=Braintree::TransparentRedirect.url)
|
43
52
|
response = nil
|
44
53
|
Net::HTTP.start("localhost", Braintree::Configuration.port) do |http|
|
45
54
|
request = Net::HTTP::Post.new("/" + url.split("/", 4)[3])
|
@@ -71,6 +80,45 @@ unless defined?(SPEC_HELPER_LOADED)
|
|
71
80
|
end
|
72
81
|
end
|
73
82
|
end
|
83
|
+
|
84
|
+
module CustomMatchers
|
85
|
+
class ParseTo
|
86
|
+
def initialize(hash)
|
87
|
+
@expected_hash = hash
|
88
|
+
end
|
89
|
+
|
90
|
+
def matches?(xml_string)
|
91
|
+
@libxml_parse = Braintree::Xml::Parser.hash_from_xml(xml_string, Braintree::Xml::Libxml)
|
92
|
+
@rexml_parse = Braintree::Xml::Parser.hash_from_xml(xml_string, Braintree::Xml::Rexml)
|
93
|
+
if @libxml_parse != @expected_hash
|
94
|
+
@results = @libxml_parse
|
95
|
+
@failed_parser = "libxml"
|
96
|
+
false
|
97
|
+
elsif @rexml_parse != @expected_hash
|
98
|
+
@results = @rexml_parse
|
99
|
+
@failed_parser = "rexml"
|
100
|
+
false
|
101
|
+
else
|
102
|
+
true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def failure_message
|
107
|
+
"xml parsing failed for #{@failed_parser}, expected #{@expected_hash.inspect} but was #{@results.inspect}"
|
108
|
+
end
|
109
|
+
|
110
|
+
def negative_failure_message
|
111
|
+
raise NotImplementedError
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def parse_to(hash)
|
116
|
+
ParseTo.new(hash)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
Spec::Runner.configure do |config|
|
121
|
+
config.include CustomMatchers
|
122
|
+
end
|
74
123
|
end
|
75
124
|
|
76
|
-
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
|
@@ -19,7 +19,7 @@ describe Braintree::CreditCard do
|
|
19
19
|
:expiration_year,
|
20
20
|
:number,
|
21
21
|
:token,
|
22
|
-
{:options => [:make_default, :verify_card]},
|
22
|
+
{:options => [:make_default, :verification_merchant_account_id, :verify_card]},
|
23
23
|
{:billing_address => [
|
24
24
|
:company,
|
25
25
|
:country_name,
|
@@ -46,7 +46,7 @@ describe Braintree::CreditCard do
|
|
46
46
|
:expiration_year,
|
47
47
|
:number,
|
48
48
|
:token,
|
49
|
-
{:options => [:make_default, :verify_card]},
|
49
|
+
{:options => [:make_default, :verification_merchant_account_id, :verify_card]},
|
50
50
|
{:billing_address => [
|
51
51
|
:company,
|
52
52
|
:country_name,
|
@@ -111,25 +111,6 @@ describe Braintree::CreditCard do
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
describe "expired?" do
|
115
|
-
it "is true if the payment method is this year and the month has passed" do
|
116
|
-
SpecHelper.stub_time_dot_now(Time.mktime(2009, 10, 20)) do
|
117
|
-
expired_pm = Braintree::CreditCard._new(:expiration_month => "09", :expiration_year => "2009")
|
118
|
-
expired_pm.expired?.should == true
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
it "is true if the payment method is in a previous year" do
|
123
|
-
expired_pm = Braintree::CreditCard._new(:expiration_month => "12", :expiration_year => (Time.now.year - 1).to_s)
|
124
|
-
expired_pm.expired?.should == true
|
125
|
-
end
|
126
|
-
|
127
|
-
it "is false if the payment method is not expired" do
|
128
|
-
not_expired_pm = Braintree::CreditCard._new(:expiration_month => "01", :expiration_year => (Time.now.year + 1).to_s)
|
129
|
-
not_expired_pm.expired?.should == false
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
114
|
describe "inspect" do
|
134
115
|
it "includes the token first" do
|
135
116
|
output = Braintree::CreditCard._new(:token => "cc123").inspect
|
@@ -10,9 +10,10 @@ describe Braintree::CreditCardVerification do
|
|
10
10
|
:avs_street_address_response_code => "I",
|
11
11
|
:cvv_response_code => "I",
|
12
12
|
:processor_response_code => "2000",
|
13
|
-
:processor_response_text => "Do Not Honor"
|
13
|
+
:processor_response_text => "Do Not Honor",
|
14
|
+
:merchant_account_id => "some_id"
|
14
15
|
)
|
15
|
-
verification.inspect.should == %(#<Braintree::CreditCardVerification status: "verified", processor_response_code: "2000", processor_response_text: "Do Not Honor", cvv_response_code: "I", avs_error_response_code: "I", avs_postal_code_response_code: "I", avs_street_address_response_code: "I">)
|
16
|
+
verification.inspect.should == %(#<Braintree::CreditCardVerification status: "verified", processor_response_code: "2000", processor_response_text: "Do Not Honor", cvv_response_code: "I", avs_error_response_code: "I", avs_postal_code_response_code: "I", avs_street_address_response_code: "I", merchant_account_id: "some_id">)
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
@@ -48,6 +48,86 @@ describe Braintree::Customer do
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
describe "self.create_signature" do
|
52
|
+
it "should be what we expect" do
|
53
|
+
Braintree::Customer._create_signature.should == [
|
54
|
+
:company,
|
55
|
+
:email,
|
56
|
+
:fax,
|
57
|
+
:first_name,
|
58
|
+
:id,
|
59
|
+
:last_name,
|
60
|
+
:phone,
|
61
|
+
:website,
|
62
|
+
{:credit_card => [
|
63
|
+
:cardholder_name,
|
64
|
+
:cvv,
|
65
|
+
:expiration_date,
|
66
|
+
:expiration_month,
|
67
|
+
:expiration_year,
|
68
|
+
:number,
|
69
|
+
:token,
|
70
|
+
{:options => [:make_default, :verification_merchant_account_id, :verify_card]},
|
71
|
+
{:billing_address => [
|
72
|
+
:company,
|
73
|
+
:country_name,
|
74
|
+
:extended_address,
|
75
|
+
:first_name,
|
76
|
+
:last_name,
|
77
|
+
:locality,
|
78
|
+
:postal_code,
|
79
|
+
:region,
|
80
|
+
:street_address
|
81
|
+
]}
|
82
|
+
]},
|
83
|
+
{:custom_fields => :_any_key_}
|
84
|
+
]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "self.update_signature" do
|
89
|
+
it "should be what we expect" do
|
90
|
+
Braintree::Customer._update_signature.should == [
|
91
|
+
:company,
|
92
|
+
:email,
|
93
|
+
:fax,
|
94
|
+
:first_name,
|
95
|
+
:id,
|
96
|
+
:last_name,
|
97
|
+
:phone,
|
98
|
+
:website,
|
99
|
+
{:credit_card => [
|
100
|
+
:cardholder_name,
|
101
|
+
:cvv,
|
102
|
+
:expiration_date,
|
103
|
+
:expiration_month,
|
104
|
+
:expiration_year,
|
105
|
+
:number,
|
106
|
+
:token,
|
107
|
+
{:options => [
|
108
|
+
:make_default,
|
109
|
+
:verification_merchant_account_id,
|
110
|
+
:verify_card,
|
111
|
+
:update_existing_token
|
112
|
+
]},
|
113
|
+
{:billing_address => [
|
114
|
+
:company,
|
115
|
+
:country_name,
|
116
|
+
:extended_address,
|
117
|
+
:first_name,
|
118
|
+
:last_name,
|
119
|
+
:locality,
|
120
|
+
:postal_code,
|
121
|
+
:region,
|
122
|
+
:street_address,
|
123
|
+
{:options => [:update_existing]}
|
124
|
+
]}
|
125
|
+
]},
|
126
|
+
{:custom_fields => :_any_key_}
|
127
|
+
]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
51
131
|
describe "self.create_from_transparent_redirect" do
|
52
132
|
it "raises an exception if the query string is forged" do
|
53
133
|
expect do
|