omniauth-identity 3.0.4 → 3.0.9

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.
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- RSpec.describe(OmniAuth::Identity::Models::ActiveRecord, db: true) do
3
+ require 'sqlite3'
4
+ require 'active_record'
5
+ require 'anonymous_active_record'
6
+
7
+ class TestIdentity < OmniAuth::Identity::Models::ActiveRecord; end
8
+
9
+ RSpec.describe(OmniAuth::Identity::Models::ActiveRecord, sqlite3: true) do
4
10
  describe 'model', type: :model do
5
11
  subject(:model_klass) do
6
12
  AnonymousActiveRecord.generate(
@@ -8,23 +14,27 @@ RSpec.describe(OmniAuth::Identity::Models::ActiveRecord, db: true) do
8
14
  columns: OmniAuth::Identity::Model::SCHEMA_ATTRIBUTES | %w[provider password_digest],
9
15
  connection_params: { adapter: 'sqlite3', encoding: 'utf8', database: ':memory:' }
10
16
  ) do
17
+ auth_key :email
11
18
  def flower
12
19
  '🌸'
13
20
  end
14
21
  end
15
22
  end
16
23
 
17
- it 'delegates locate to the where query method' do
18
- allow(model_klass).to receive(:where).with('ham_sandwich' => 'open faced', 'category' => 'sandwiches',
19
- 'provider' => 'identity').and_return(['wakka'])
20
- expect(model_klass.locate('ham_sandwich' => 'open faced', 'category' => 'sandwiches')).to eq('wakka')
24
+ include_context 'persistable model'
25
+
26
+ describe '::table_name' do
27
+ it 'does not use STI rules for its table name' do
28
+ expect(TestIdentity.table_name).to eq('test_identities')
29
+ end
21
30
  end
22
- end
23
31
 
24
- describe '#table_name' do
25
- class TestIdentity < OmniAuth::Identity::Models::ActiveRecord; end
26
- it 'does not use STI rules for its table name' do
27
- expect(TestIdentity.table_name).to eq('test_identities')
32
+ describe '::locate' do
33
+ it 'delegates locate to the where query method' do
34
+ allow(model_klass).to receive(:where).with('email' => 'open faced', 'category' => 'sandwiches',
35
+ 'provider' => 'identity').and_return(['wakka'])
36
+ expect(model_klass.locate('email' => 'open faced', 'category' => 'sandwiches')).to eq('wakka')
37
+ end
28
38
  end
29
39
  end
30
40
  end
@@ -1,23 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'sqlite3'
3
4
  require 'sequel'
4
- # Connect to an in-memory sqlite3 database.
5
+
5
6
  DB = Sequel.sqlite
6
- DB.create_table :sequel_test_identities do
7
- primary_key :id
8
- String :ham_sandwich, null: false
9
- String :password_digest, null: false
10
- end
11
7
 
12
- class SequelTestIdentity < Sequel::Model
13
- include OmniAuth::Identity::Models::Sequel
14
- auth_key :ham_sandwich
15
- end
8
+ RSpec.describe(OmniAuth::Identity::Models::Sequel, sqlite3: true) do
9
+ before(:all) do
10
+ # Connect to an in-memory sqlite3 database.
11
+ DB.create_table :sequel_test_identities do
12
+ primary_key :id
13
+ String :email, null: false
14
+ String :password_digest, null: false
15
+ end
16
+ end
17
+
18
+ before do
19
+ sequel_test_identity = Class.new(Sequel::Model(:sequel_test_identities)) do
20
+ include ::OmniAuth::Identity::Models::Sequel
21
+ auth_key :email
22
+ end
23
+ stub_const('SequelTestIdentity', sequel_test_identity)
24
+ end
25
+
26
+ describe 'model', type: :model do
27
+ subject(:model_klass) { SequelTestIdentity }
28
+
29
+ include_context 'persistable model'
16
30
 
17
- RSpec.describe(OmniAuth::Identity::Models::Sequel, db: true) do
18
- it 'delegates locate to the where query method' do
19
- allow(SequelTestIdentity).to receive(:where).with('ham_sandwich' => 'open faced',
20
- 'category' => 'sandwiches').and_return(['wakka'])
21
- expect(SequelTestIdentity.locate('ham_sandwich' => 'open faced', 'category' => 'sandwiches')).to eq('wakka')
31
+ describe '::locate' do
32
+ it 'delegates to the where query method' do
33
+ allow(model_klass).to receive(:where).with('email' => 'open faced',
34
+ 'category' => 'sandwiches').and_return(['wakka'])
35
+ expect(model_klass.locate('email' => 'open faced', 'category' => 'sandwiches')).to eq('wakka')
36
+ end
37
+ end
22
38
  end
23
39
  end
@@ -1,10 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- RSpec.describe OmniAuth::Strategies::Identity do
3
+ require 'sqlite3'
4
+ require 'active_record'
5
+ require 'anonymous_active_record'
6
+
7
+ RSpec.describe OmniAuth::Strategies::Identity, sqlite3: true do
4
8
  attr_accessor :app
5
9
 
6
- let(:auth_hash) { last_response.headers['env']['omniauth.auth'] }
7
- let(:identity_hash) { last_response.headers['env']['omniauth.identity'] }
10
+ let(:env_hash) { last_response.headers['env'] }
11
+ let(:auth_hash) { env_hash['omniauth.auth'] }
12
+ let(:identity_hash) { env_hash['omniauth.identity'] }
8
13
  let(:identity_options) { {} }
9
14
  let(:anon_ar) do
10
15
  AnonymousActiveRecord.generate(
@@ -12,6 +17,7 @@ RSpec.describe OmniAuth::Strategies::Identity do
12
17
  columns: OmniAuth::Identity::Model::SCHEMA_ATTRIBUTES | %w[provider password_digest],
13
18
  connection_params: { adapter: 'sqlite3', encoding: 'utf8', database: ':memory:' }
14
19
  ) do
20
+ auth_key :email
15
21
  def balloon
16
22
  '🎈'
17
23
  end
@@ -193,7 +199,7 @@ RSpec.describe OmniAuth::Strategies::Identity do
193
199
  end
194
200
  end
195
201
 
196
- context 'with successful creation' do
202
+ context 'with good identity' do
197
203
  let(:properties) do
198
204
  {
199
205
  name: 'Awesome Dude',
@@ -209,9 +215,66 @@ RSpec.describe OmniAuth::Strategies::Identity do
209
215
  expect(auth_hash['uid']).to match(/\d+/)
210
216
  expect(auth_hash['provider']).to eq('identity')
211
217
  end
218
+
219
+ context 'with on_validation proc' do
220
+ let(:identity_options) do
221
+ { model: anon_ar, on_validation: on_validation_proc }
222
+ end
223
+ let(:on_validation_proc) do
224
+ lambda { |_env|
225
+ false
226
+ }
227
+ end
228
+
229
+ context 'when validation fails' do
230
+ it 'does not set the env hash' do
231
+ post '/auth/identity/register', properties
232
+ expect(env_hash).to eq(nil)
233
+ end
234
+
235
+ it 'renders registration form' do
236
+ post '/auth/identity/register', properties
237
+ expect(last_response.body).to be_include(described_class.default_options[:registration_form_title])
238
+ end
239
+
240
+ it 'displays validation failure message' do
241
+ post '/auth/identity/register', properties
242
+ expect(last_response.body).to be_include(described_class.default_options[:validation_failure_message])
243
+ end
244
+ end
245
+
246
+ context 'when validation succeeds' do
247
+ let(:on_validation_proc) do
248
+ lambda { |_env|
249
+ true
250
+ }
251
+ end
252
+
253
+ it 'sets the auth hash' do
254
+ post '/auth/identity/register', properties
255
+ expect(auth_hash['uid']).to match(/\d+/)
256
+ expect(auth_hash['provider']).to eq('identity')
257
+ end
258
+
259
+ it 'does not render registration form' do
260
+ post '/auth/identity/register', properties
261
+ expect(last_response.body).not_to be_include(described_class.default_options[:registration_form_title])
262
+ end
263
+
264
+ it 'does not display validation failure message' do
265
+ post '/auth/identity/register', properties
266
+ expect(last_response.body).not_to be_include(described_class.default_options[:validation_failure_message])
267
+ end
268
+
269
+ it 'does not display registration failure message' do
270
+ post '/auth/identity/register', properties
271
+ expect(last_response.body).not_to be_include(described_class.default_options[:registration_failure_message])
272
+ end
273
+ end
274
+ end
212
275
  end
213
276
 
214
- context 'with invalid identity' do
277
+ context 'with bad identity' do
215
278
  let(:properties) do
216
279
  {
217
280
  name: 'Awesome Dude',
@@ -249,6 +312,62 @@ RSpec.describe OmniAuth::Strategies::Identity do
249
312
  expect(last_response.body).not_to be_include('One or more fields were invalid')
250
313
  end
251
314
  end
315
+
316
+ context 'with on_validation proc' do
317
+ let(:identity_options) do
318
+ { model: anon_ar, on_validation: on_validation_proc }
319
+ end
320
+ let(:on_validation_proc) do
321
+ lambda { |_env|
322
+ false
323
+ }
324
+ end
325
+
326
+ context 'when validation fails' do
327
+ it 'does not set the env hash' do
328
+ post '/auth/identity/register', properties
329
+ expect(env_hash).to eq(nil)
330
+ end
331
+
332
+ it 'renders registration form' do
333
+ post '/auth/identity/register', properties
334
+ expect(last_response.body).to be_include(described_class.default_options[:registration_form_title])
335
+ end
336
+
337
+ it 'displays validation failure message' do
338
+ post '/auth/identity/register', properties
339
+ expect(last_response.body).to be_include(described_class.default_options[:validation_failure_message])
340
+ end
341
+ end
342
+
343
+ context 'when validation succeeds' do
344
+ let(:on_validation_proc) do
345
+ lambda { |_env|
346
+ true
347
+ }
348
+ end
349
+
350
+ it 'does not set the env hash' do
351
+ post '/auth/identity/register', properties
352
+ expect(env_hash).to eq(nil)
353
+ end
354
+
355
+ it 'renders registration form' do
356
+ post '/auth/identity/register', properties
357
+ expect(last_response.body).to be_include(described_class.default_options[:registration_form_title])
358
+ end
359
+
360
+ it 'does not display validation failure message' do
361
+ post '/auth/identity/register', properties
362
+ expect(last_response.body).not_to be_include(described_class.default_options[:validation_failure_message])
363
+ end
364
+
365
+ it 'display registration failure message' do
366
+ post '/auth/identity/register', properties
367
+ expect(last_response.body).to be_include(described_class.default_options[:registration_failure_message])
368
+ end
369
+ end
370
+ end
252
371
  end
253
372
  end
254
373
  end
data/spec/spec_helper.rb CHANGED
@@ -1,21 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # NOTE: mongoid and no_brainer can't be loaded at the same time.
4
+ # If you try it, one or both of them will not work.
5
+ # This is why the ORM specs are split into a separate directory and run in separate threads.
6
+
7
+ ENV['RUBY_ENV'] = 'test' # Used by NoBrainer
8
+ ENV['MONGOID_ENV'] = 'test' # Used by Mongoid
9
+
3
10
  ruby_version = Gem::Version.new(RUBY_VERSION)
4
11
  require 'simplecov' if ruby_version >= Gem::Version.new('2.7') && RUBY_ENGINE == 'ruby'
5
12
 
6
13
  require 'rack/test'
7
- require 'mongoid-rspec'
8
- require 'sqlite3'
9
- require 'sequel'
10
- require 'anonymous_active_record'
14
+ require 'rspec/block_is_expected'
11
15
  require 'byebug' if RUBY_ENGINE == 'ruby'
12
16
 
13
17
  # This gem
14
18
  require 'omniauth/identity'
15
19
 
20
+ spec_root_matcher = %r{#{__dir__}/(.+)\.rb\Z}
21
+ Dir.glob(Pathname.new(__dir__).join('support/**/', '*.rb')).each { |f| require f.match(spec_root_matcher)[1] }
22
+
23
+ DEFAULT_PASSWORD = 'hang-a-left-at-the-diner'
24
+ DEFAULT_EMAIL = 'mojo@example.com'
25
+
16
26
  RSpec.configure do |config|
17
27
  config.include Rack::Test::Methods
18
- config.include Mongoid::Matchers, type: :model
28
+
29
+ # config.include ::Mongoid::Matchers, db: :mongodb
19
30
 
20
31
  # Enable flags like --only-failures and --next-failure
21
32
  config.example_status_persistence_file_path = '.rspec_status'
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples 'instance with instance methods' do
4
+ describe '#initialize' do
5
+ it 'does not raise an error' do
6
+ block_is_expected.not_to raise_error
7
+ end
8
+ end
9
+
10
+ describe '#uid' do
11
+ it 'defaults to #id' do
12
+ allow(instance).to receive(:respond_to?).with(:id).and_return(true)
13
+ allow(instance).to receive(:id).and_return 'wakka-do'
14
+ expect(instance.uid).to eq('wakka-do')
15
+ end
16
+
17
+ it 'stringifies it' do
18
+ allow(instance).to receive(:id).and_return 123
19
+ expect(instance.uid).to eq('123')
20
+ end
21
+
22
+ it 'raises NotImplementedError if #id is not defined' do
23
+ allow(instance).to receive(:respond_to?).with(:id).and_return(false)
24
+ expect { instance.uid }.to raise_error(NotImplementedError)
25
+ end
26
+ end
27
+
28
+ describe '#auth_key' do
29
+ it 'defaults to #email' do
30
+ allow(instance).to receive(:respond_to?).with(:email).and_return(true)
31
+ allow(instance).to receive(:email).and_return('bob@bob.com')
32
+ expect(instance.auth_key).to eq('bob@bob.com')
33
+ end
34
+
35
+ it 'uses the class .auth_key' do
36
+ instance.class.auth_key 'login'
37
+ allow(instance).to receive(:login).and_return 'bob'
38
+ expect(instance.auth_key).to eq('bob')
39
+ instance.class.auth_key nil
40
+ end
41
+ end
42
+
43
+ describe '#auth_key=' do
44
+ it 'defaults to setting email' do
45
+ allow(instance).to receive(:respond_to?).with(:email=).and_return(true)
46
+ expect(instance).to receive(:email=).with 'abc'
47
+
48
+ instance.auth_key = 'abc'
49
+ end
50
+
51
+ it 'uses a custom .auth_key if one is provided' do
52
+ instance.class.auth_key 'login'
53
+ allow(instance).to receive(:respond_to?).with(:login=).and_return(true)
54
+ expect(instance).to receive(:login=).with('abc')
55
+
56
+ instance.auth_key = 'abc'
57
+ end
58
+ end
59
+
60
+ describe '#info' do
61
+ it 'includes all attributes as they have been set' do
62
+ allow(instance).to receive(:name).and_return('Bob Bobson')
63
+ allow(instance).to receive(:nickname).and_return('bob')
64
+
65
+ expect(instance.info).to include({
66
+ 'name' => 'Bob Bobson',
67
+ 'nickname' => 'bob'
68
+ })
69
+ end
70
+
71
+ it 'uses firstname and lastname, over nickname, to set missing name' do
72
+ allow(instance).to receive(:first_name).and_return('shoeless')
73
+ allow(instance).to receive(:last_name).and_return('joe')
74
+ allow(instance).to receive(:nickname).and_return('george')
75
+ instance.info['name'] == 'shoeless joe'
76
+ end
77
+
78
+ it 'uses nickname to set missing name when first and last are not set' do
79
+ allow(instance).to receive(:nickname).and_return('bob')
80
+ instance.info['name'] == 'bob'
81
+ end
82
+
83
+ it 'does not overwrite a provided name' do
84
+ allow(instance).to receive(:name).and_return('Awesome Dude')
85
+ allow(instance).to receive(:first_name).and_return('Frank')
86
+ expect(instance.info['name']).to eq('Awesome Dude')
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples 'model with class methods' do
4
+ describe 'class definition' do
5
+ it 'does not raise an error' do
6
+ block_is_expected.not_to raise_error
7
+ end
8
+ end
9
+
10
+ describe '::authenticate' do
11
+ it 'calls locate and then authenticate' do
12
+ mocked_instance = double('ExampleModel', authenticate: 'abbadoo')
13
+ allow(model_klass).to receive(:locate).with('email' => 'example').and_return(mocked_instance)
14
+ expect(model_klass.authenticate({ 'email' => 'example' }, 'pass')).to eq('abbadoo')
15
+ end
16
+
17
+ it 'calls locate with additional scopes when provided' do
18
+ mocked_instance = double('ExampleModel', authenticate: 'abbadoo')
19
+ allow(model_klass).to receive(:locate).with('email' => 'example',
20
+ 'user_type' => 'admin').and_return(mocked_instance)
21
+ expect(model_klass.authenticate({ 'email' => 'example', 'user_type' => 'admin' }, 'pass')).to eq('abbadoo')
22
+ end
23
+
24
+ it 'recovers gracefully if locate is nil' do
25
+ allow(model_klass).to receive(:locate).and_return(nil)
26
+ expect(model_klass.authenticate('blah', 'foo')).to be false
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_context 'persistable model' do
4
+ include_context 'model with class methods'
5
+
6
+ describe 'instance methods' do
7
+ subject(:instance) { model_klass.new }
8
+
9
+ include_context 'instance with instance methods'
10
+
11
+ describe '#save' do
12
+ subject(:save) do
13
+ instance.email = DEFAULT_EMAIL
14
+ instance.password = DEFAULT_PASSWORD
15
+ instance.password_confirmation = DEFAULT_PASSWORD
16
+ instance.save
17
+ end
18
+
19
+ it 'does not raise an error' do
20
+ save
21
+ end
22
+ end
23
+ end
24
+ end