pillowfort 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +0 -1
- data/app/models/pillowfort/concerns/model_authentication.rb +7 -3
- data/lib/pillowfort/version.rb +1 -1
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/accounts.js +2 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/accounts.css +4 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/accounts_controller.rb +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/accounts_helper.rb +2 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/account.rb +3 -0
- data/spec/dummy/app/views/accounts/index.html.erb +2 -0
- data/spec/dummy/app/views/accounts/show.html.erb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +31 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +17 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +60 -0
- data/spec/dummy/config/secrets.yml +14 -0
- data/spec/dummy/db/migrate/20150127045508_create_accounts.rb +12 -0
- data/spec/dummy/db/schema.rb +25 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +2087 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/spec/controllers/accounts_controller_spec.rb +52 -0
- data/spec/dummy/spec/factories/accounts.rb +10 -0
- data/spec/dummy/spec/models/account_spec.rb +276 -0
- data/spec/dummy/spec/rails_helper.rb +52 -0
- data/spec/dummy/spec/spec_helper.rb +85 -0
- data/spec/dummy/spec/support/helpers/authentication_helper.rb +15 -0
- metadata +103 -3
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/404.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
62
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
63
|
+
</div>
|
64
|
+
<p>If you are the application owner check the logs for more information.</p>
|
65
|
+
</div>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/422.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>The change you wanted was rejected.</h1>
|
62
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
63
|
+
</div>
|
64
|
+
<p>If you are the application owner check the logs for more information.</p>
|
65
|
+
</div>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -0,0 +1,66 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/500.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>We're sorry, but something went wrong.</h1>
|
62
|
+
</div>
|
63
|
+
<p>If you are the application owner check the logs for more information.</p>
|
64
|
+
</div>
|
65
|
+
</body>
|
66
|
+
</html>
|
File without changes
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe AccountsController, :type => :controller do
|
4
|
+
describe 'its response' do
|
5
|
+
subject { response }
|
6
|
+
|
7
|
+
context 'when authenticated' do
|
8
|
+
let(:account) { FactoryGirl.create :account }
|
9
|
+
before { authenticate_with account }
|
10
|
+
|
11
|
+
describe 'unprotected #index' do
|
12
|
+
before { get :index }
|
13
|
+
it { should have_http_status :success }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'protected #show' do
|
17
|
+
before { get :show, id: 1 }
|
18
|
+
it { should have_http_status :success }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when not authenticated' do
|
23
|
+
describe 'unprotected #index' do
|
24
|
+
before { get :index }
|
25
|
+
it { should have_http_status :success }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'protected #show' do
|
29
|
+
before { get :show, id: 1 }
|
30
|
+
it { should have_http_status :unauthorized }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'its methods' do
|
36
|
+
describe '#current_account' do
|
37
|
+
it { should respond_to(:current_account) }
|
38
|
+
|
39
|
+
context 'when authenticated' do
|
40
|
+
let(:account) { FactoryGirl.create :account }
|
41
|
+
before do
|
42
|
+
authenticate_with account
|
43
|
+
get :show, id: 1
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should return the account when current_account is called' do
|
47
|
+
expect(subject.current_account).to eq(account)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
# ------------------------------------------------------------------------------
|
4
|
+
# Shared Examples
|
5
|
+
# ------------------------------------------------------------------------------
|
6
|
+
|
7
|
+
RSpec.shared_examples 'an auth token resetter' do
|
8
|
+
describe 'its affect on the auth_token' do
|
9
|
+
subject { account.auth_token }
|
10
|
+
|
11
|
+
describe 'before the call' do
|
12
|
+
it { should eq(auth_token) }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'after the call' do
|
16
|
+
before { call_the_method }
|
17
|
+
it { should_not eq(auth_token) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'its affect on the auth_token_expires_at' do
|
22
|
+
subject { account.auth_token_expires_at }
|
23
|
+
|
24
|
+
describe 'before the call' do
|
25
|
+
it { should eq(auth_token_expires_at) }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'after the call' do
|
29
|
+
before { call_the_method }
|
30
|
+
it { should be > auth_token_expires_at }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# ------------------------------------------------------------------------------
|
36
|
+
# The Spec!
|
37
|
+
# ------------------------------------------------------------------------------
|
38
|
+
|
39
|
+
RSpec.describe Account, :type => :model do
|
40
|
+
|
41
|
+
describe 'its validations' do
|
42
|
+
before { account.save }
|
43
|
+
subject { account.errors.messages }
|
44
|
+
|
45
|
+
describe 'email validations' do
|
46
|
+
let(:account) { FactoryGirl.build(:account, email: email) }
|
47
|
+
|
48
|
+
context 'presence_of' do
|
49
|
+
let(:email) { nil }
|
50
|
+
|
51
|
+
it { should include(email: ["can't be blank"]) }
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'uniqueness' do
|
55
|
+
let(:email) { 'foobar@baz.com' }
|
56
|
+
let(:dup_account) { FactoryGirl.build(:account, email: email) }
|
57
|
+
before { dup_account.save }
|
58
|
+
subject { dup_account.errors.messages}
|
59
|
+
|
60
|
+
it { should include(email: ["has already been taken"]) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'password validations' do
|
65
|
+
let(:account) { FactoryGirl.build(:account, password: password) }
|
66
|
+
|
67
|
+
context 'presence_of' do
|
68
|
+
let(:password) { nil }
|
69
|
+
|
70
|
+
it { should include(password: [/can't be blank/, /is too short/]) }
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'length of' do
|
74
|
+
context "when it's too short" do
|
75
|
+
let(:password) { "x"*3 }
|
76
|
+
|
77
|
+
it { should include(password: [/is too short/])}
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when it's too long" do
|
81
|
+
let(:password) { "x"*80 }
|
82
|
+
|
83
|
+
it { should include(password: [/is too long/])}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'the instance methods' do
|
90
|
+
let(:account) {
|
91
|
+
FactoryGirl.create :account,
|
92
|
+
auth_token: auth_token,
|
93
|
+
auth_token_expires_at: auth_token_expires_at
|
94
|
+
}
|
95
|
+
|
96
|
+
let(:auth_token) { 'abc123def456' }
|
97
|
+
let(:auth_token_expires_at) { 1.day.from_now }
|
98
|
+
|
99
|
+
describe '#ensure_auth_token' do
|
100
|
+
subject { account.auth_token }
|
101
|
+
before { account.ensure_auth_token }
|
102
|
+
|
103
|
+
context 'when the token is nil' do
|
104
|
+
let(:auth_token) { nil }
|
105
|
+
it { should_not be_nil }
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when the token is not nil' do
|
109
|
+
let(:auth_token) { 'deadbeef' }
|
110
|
+
it { should eq('deadbeef') }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#reset_auth_token' do
|
115
|
+
let(:call_the_method) { account.reset_auth_token }
|
116
|
+
it_behaves_like 'an auth token resetter'
|
117
|
+
|
118
|
+
describe 'its persistence' do
|
119
|
+
subject { account }
|
120
|
+
after { call_the_method }
|
121
|
+
it { should_not receive(:save) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#reset_auth_token!' do
|
126
|
+
let(:call_the_method) { account.reset_auth_token! }
|
127
|
+
it_behaves_like 'an auth token resetter'
|
128
|
+
|
129
|
+
describe 'its persistence' do
|
130
|
+
subject { account }
|
131
|
+
after { call_the_method }
|
132
|
+
it { should receive(:save) }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '#token_expired?' do
|
137
|
+
subject { account.token_expired? }
|
138
|
+
|
139
|
+
context 'when the token expiration is in the future' do
|
140
|
+
let(:auth_token_expires_at) { 1.minute.from_now }
|
141
|
+
it { should be_falsey }
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'when the token expiration is in the past' do
|
145
|
+
let(:auth_token_expires_at) { 1.minute.ago }
|
146
|
+
it { should be_truthy }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe '#password=' do
|
151
|
+
let!(:current_password) { account.password.to_s }
|
152
|
+
subject { account.password.to_s }
|
153
|
+
|
154
|
+
describe 'before the call' do
|
155
|
+
it { should == (current_password) }
|
156
|
+
end
|
157
|
+
|
158
|
+
describe 'after the call' do
|
159
|
+
before { account.password = 'fudge_knuckles_45' }
|
160
|
+
it { should_not eq(current_password) }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'the class methods' do
|
166
|
+
let(:email) { 'foobar@baz.com' }
|
167
|
+
let(:token) { 'deadbeef' }
|
168
|
+
let(:password) { 'admin4lolz' }
|
169
|
+
let(:auth_token_expires_at) { 1.day.from_now }
|
170
|
+
|
171
|
+
let!(:account) {
|
172
|
+
FactoryGirl.create :account,
|
173
|
+
email: email,
|
174
|
+
auth_token: token,
|
175
|
+
password: password,
|
176
|
+
auth_token_expires_at: auth_token_expires_at
|
177
|
+
}
|
178
|
+
|
179
|
+
describe '.authenticate_securely' do
|
180
|
+
let(:email_param) { email }
|
181
|
+
let(:token_param) { token }
|
182
|
+
let(:block) { ->(resource) {} }
|
183
|
+
|
184
|
+
subject { Account.authenticate_securely(email_param, token_param, &block) }
|
185
|
+
|
186
|
+
context 'when email is nil' do
|
187
|
+
let(:email_param) { nil }
|
188
|
+
it { should be_falsey }
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'when token is nil' do
|
192
|
+
let(:token_param) { nil }
|
193
|
+
it { should be_falsey }
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'when email and token are provided' do
|
197
|
+
|
198
|
+
context 'email case-sensitivity' do
|
199
|
+
describe 'when an uppercased email address is provided' do
|
200
|
+
let(:email_param) { email.upcase }
|
201
|
+
|
202
|
+
it 'should yield the matched account' do
|
203
|
+
expect { |b| Account.authenticate_securely(email_param, token_param, &b) }.to yield_with_args(account)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe 'when a downcased email address is provided' do
|
208
|
+
let(:email_param) { email.downcase }
|
209
|
+
|
210
|
+
it 'should yield the matched account' do
|
211
|
+
expect { |b| Account.authenticate_securely(email_param, token_param, &b) }.to yield_with_args(account)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context 'when the resource is located' do
|
217
|
+
|
218
|
+
context 'when the auth_token is expired' do
|
219
|
+
let(:auth_token_expires_at) { 1.week.ago }
|
220
|
+
|
221
|
+
it 'should reset the account auth_token' do
|
222
|
+
allow(Account).to receive(:find_by_email_case_insensitive) { account }
|
223
|
+
expect(account).to receive(:reset_auth_token!)
|
224
|
+
subject
|
225
|
+
end
|
226
|
+
|
227
|
+
it { should be_falsey }
|
228
|
+
end
|
229
|
+
|
230
|
+
context 'when the auth_token is current' do
|
231
|
+
|
232
|
+
context 'when the auth_token matches' do
|
233
|
+
it 'should yield the matched account' do
|
234
|
+
expect { |b| Account.authenticate_securely(email_param, token_param, &b) }.to yield_with_args(account)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
context 'when the auth_token does not match' do
|
239
|
+
it { should be_falsey }
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'when the resource is not located' do
|
245
|
+
it { should be_falsey }
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
describe '.find_and_authenticate' do
|
252
|
+
let(:email_param) { email }
|
253
|
+
let(:password_param) { password }
|
254
|
+
|
255
|
+
subject { Account.find_and_authenticate(email_param, password_param) }
|
256
|
+
|
257
|
+
|
258
|
+
context 'when the resource is located' do
|
259
|
+
|
260
|
+
context 'when the password matches' do
|
261
|
+
it { should eq(account) }
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'when the password does not match' do
|
265
|
+
let(:password_param) { "#{password}_bad" }
|
266
|
+
it { should be_falsey }
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context 'when the resource is not located' do
|
271
|
+
let(:email_param) { "#{email}_evil" }
|
272
|
+
it { should be_falsey }
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|