notifly 0.0.3 → 0.0.4

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +22 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +24 -0
  6. data/Gemfile.lock +199 -0
  7. data/README.md +32 -6
  8. data/Rakefile +40 -14
  9. data/VERSION +1 -0
  10. data/app/assets/images/notifly/.keep +0 -0
  11. data/bin/rails +12 -0
  12. data/lib/generators/notifly/install/install_generator.rb +4 -0
  13. data/lib/notifly/engine.rb +0 -10
  14. data/spec/controllers/notifly/notifications_controller_spec.rb +44 -0
  15. data/spec/dummy/README.rdoc +28 -0
  16. data/spec/dummy/Rakefile +6 -0
  17. data/spec/dummy/app/assets/images/.keep +0 -0
  18. data/spec/dummy/app/assets/javascripts/application.js +14 -0
  19. data/spec/dummy/app/assets/stylesheets/application.css +20 -0
  20. data/spec/dummy/app/controllers/application_controller.rb +13 -0
  21. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  22. data/spec/dummy/app/controllers/site_controller.rb +4 -0
  23. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  24. data/spec/dummy/app/mailers/.keep +0 -0
  25. data/spec/dummy/app/models/.keep +0 -0
  26. data/spec/dummy/app/models/concerns/.keep +0 -0
  27. data/spec/dummy/app/models/dummy_object.rb +19 -0
  28. data/spec/dummy/app/models/post.rb +21 -0
  29. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  30. data/spec/dummy/app/views/site/index.html.erb +2 -0
  31. data/spec/dummy/bin/bundle +3 -0
  32. data/spec/dummy/bin/rails +4 -0
  33. data/spec/dummy/bin/rake +4 -0
  34. data/spec/dummy/config.ru +4 -0
  35. data/spec/dummy/config/application.rb +29 -0
  36. data/spec/dummy/config/boot.rb +5 -0
  37. data/spec/dummy/config/database.exemple.yml +12 -0
  38. data/spec/dummy/config/database.travis.yml +4 -0
  39. data/spec/dummy/config/environment.rb +5 -0
  40. data/spec/dummy/config/environments/development.rb +37 -0
  41. data/spec/dummy/config/environments/production.rb +78 -0
  42. data/spec/dummy/config/environments/test.rb +39 -0
  43. data/spec/dummy/config/initializers/assets.rb +8 -0
  44. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  45. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  46. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  47. data/spec/dummy/config/initializers/inflections.rb +16 -0
  48. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  49. data/spec/dummy/config/initializers/session_store.rb +3 -0
  50. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  51. data/spec/dummy/config/locales/en.yml +23 -0
  52. data/spec/dummy/config/routes.rb +5 -0
  53. data/spec/dummy/config/secrets.yml +22 -0
  54. data/spec/dummy/db/migrate/20141031165049_create_dummy_objects.rb +9 -0
  55. data/spec/dummy/db/migrate/20141103191353_create_posts.rb +10 -0
  56. data/spec/dummy/db/migrate/20141104121318_add_dummy_to_post.rb +5 -0
  57. data/spec/dummy/db/schema.rb +54 -0
  58. data/spec/dummy/lib/assets/.keep +0 -0
  59. data/spec/dummy/log/.keep +0 -0
  60. data/spec/dummy/public/404.html +67 -0
  61. data/spec/dummy/public/422.html +67 -0
  62. data/spec/dummy/public/500.html +66 -0
  63. data/spec/dummy/public/favicon.ico +0 -0
  64. data/spec/dummy/spec/features/notifly/counter_spec.rb +38 -0
  65. data/spec/dummy/spec/features/notifly/loading_notifications_spec.rb +38 -0
  66. data/spec/dummy/spec/features/notifly/read_notifications_spec.rb +70 -0
  67. data/spec/dummy/spec/models/dummy_object_spec.rb +58 -0
  68. data/spec/dummy/spec/models/post_spec.rb +89 -0
  69. data/spec/models/notifly/notification_spec.rb +18 -0
  70. data/spec/rails_helper.rb +21 -0
  71. data/spec/spec_helper.rb +62 -0
  72. data/spec/support/shared_connection.rb +14 -0
  73. data/spec/support/suppress_log.rb +3 -0
  74. data/spec/support/wait_ajax.rb +53 -0
  75. data/vendor/assets/javascripts/twitter/bootstrap.js +181 -0
  76. data/vendor/assets/stylesheets/twitter/bootstrap.css +475 -0
  77. metadata +181 -11
  78. data/lib/notifly/version.rb +0 -3
File without changes
@@ -0,0 +1,38 @@
1
+ require 'rails_helper'
2
+
3
+ describe 'Notifly counter', :type => :feature, js: true do
4
+ before(:each) do
5
+ receiver = DummyObject.create! name: 'User'
6
+ Notifly::Notification.create! receiver: receiver, seen: true, read: false
7
+ Notifly::Notification.create! receiver: receiver, seen: false, read: false
8
+ Notifly::Notification.create! receiver: receiver, seen: false, read: false
9
+ Notifly::Notification.create! receiver: receiver, seen: false, read: false
10
+ Notifly::Notification.create! receiver: DummyObject.create!, seen: false, read: false
11
+ Notifly::Notification.create! receiver: DummyObject.create!, seen: false, read: false
12
+ Notifly.per_page = 2
13
+
14
+ visit root_path
15
+ end
16
+
17
+ after(:each) do
18
+ Notifly.per_page = 10
19
+ end
20
+
21
+ scenario 'seeing notifications' do
22
+ within("#notifly-counter") do
23
+ expect(page).to have_content '3'
24
+ end
25
+
26
+ wait_for_ajax { find('#notifly-icon').click }
27
+
28
+ within("#notifly-counter") do
29
+ expect(page).to have_content '1'
30
+ end
31
+
32
+ click_ajax_link 'More'
33
+
34
+ within("#notifly-counter") do
35
+ expect(page).to_not have_content '1'
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ require 'rails_helper'
2
+
3
+ describe 'Loading notifications', :type => :feature, js: true do
4
+ before(:each) do
5
+ @receiver = DummyObject.create! name: 'User'
6
+ 13.times { Notifly::Notification.create! receiver: @receiver, template: :default, read: false }
7
+ Notifly::Notification.create! receiver: DummyObject.create!, template: :default
8
+ Notifly::Notification.create! receiver: DummyObject.create!, template: :default
9
+ visit root_path
10
+ end
11
+
12
+ scenario 'loading notifications in background when user hover notifly' do
13
+ within("#notifly") do
14
+ expect(page).to_not have_css('div.notifly-notification', visible: false)
15
+ end
16
+
17
+ wait_for_ajax { find('#notifly-icon').click }
18
+
19
+ within('#notifly') do
20
+ expect(page).to have_css('div.notifly-notification', count: 10, visible: false)
21
+ end
22
+ end
23
+
24
+ scenario 'loading next page link' do
25
+ href_with_page = notifly.notifications_path(page: 2)
26
+ wait_for_ajax { find('#notifly-icon').click }
27
+ within('#notifly-notifications-footer') do
28
+ expect(page).to have_xpath("//a[@href=\"#{href_with_page}\"]")
29
+ end
30
+
31
+
32
+ click_ajax_link 'More'
33
+
34
+ within('#notifly-notifications-footer') do
35
+ expect(page).to_not have_xpath("//a[@href=\"#{href_with_page}\"]")
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,70 @@
1
+ require 'rails_helper'
2
+
3
+ describe 'Read notification', :type => :feature, js: true do
4
+ before do
5
+ @receiver = DummyObject.create! name: 'User'
6
+ @n_1 = Notifly::Notification.create! receiver: @receiver, read: false
7
+ @n_2 = Notifly::Notification.create! receiver: @receiver, read: false
8
+ @n_3 = Notifly::Notification.create! receiver: @receiver, read: false
9
+ Notifly.per_page = 2
10
+ end
11
+
12
+ after(:each) do
13
+ Notifly.per_page = 10
14
+ end
15
+
16
+ let(:open_notifly) do
17
+ visit root_path
18
+ wait_for_ajax { find('#notifly-icon').click }
19
+ end
20
+
21
+ context 'when read a specific notification' do
22
+ scenario 'read a notification' do
23
+ open_notifly
24
+
25
+ notification_id = "#notifly-notification-#{@n_2.id}"
26
+ expect(page).to have_selector ("#{notification_id}.notifly-notification-not-read")
27
+
28
+ within(notification_id) do
29
+ click_ajax_link 'read'
30
+ end
31
+
32
+ expect(page).to have_selector (notification_id)
33
+ expect(page).to_not have_selector ("#{notification_id}.notifly-notification-not-read")
34
+ end
35
+
36
+ scenario 'unread a notification' do
37
+ notification = Notifly::Notification.create! receiver: @receiver, read: true
38
+ notification_id = "#notifly-notification-#{notification.id}"
39
+ open_notifly
40
+ expect(page).to have_selector (notification_id)
41
+ expect(page).to_not have_selector ("#{notification_id}.notifly-notification-not-read")
42
+
43
+ within(notification_id) do
44
+ click_ajax_link 'unread'
45
+ end
46
+
47
+ expect(page).to have_selector ("#{notification_id}.notifly-notification-not-read")
48
+ end
49
+ end
50
+
51
+ scenario 'mark all read' do
52
+ open_notifly
53
+
54
+ expect(page).to have_selector ("#notifly-notification-#{@n_3.id}.notifly-notification-not-read")
55
+ expect(page).to have_selector ("#notifly-notification-#{@n_2.id}.notifly-notification-not-read")
56
+ expect(page).to_not have_selector ("#notifly-notification-#{@n_1.id}")
57
+
58
+ within('#notifly') do
59
+ click_ajax_link 'Mark as read'
60
+ click_ajax_link 'More'
61
+ end
62
+
63
+ expect(page).to have_selector ("#notifly-notification-#{@n_3.id}")
64
+ expect(page).to have_selector ("#notifly-notification-#{@n_2.id}")
65
+ expect(page).to have_selector ("#notifly-notification-#{@n_1.id}.notifly-notification-not-read")
66
+
67
+ expect(page).to_not have_selector ("#notifly-notification-#{@n_3.id}.notifly-notification-not-read")
68
+ expect(page).to_not have_selector ("#notifly-notification-#{@n_2.id}.notifly-notification-not-read")
69
+ end
70
+ end
@@ -0,0 +1,58 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe DummyObject, :type => :model do
4
+ it { is_expected.to have_many(:posts) }
5
+
6
+ describe 'Notifly' do
7
+ let(:smart) { DummyObject.create name: 'smart' }
8
+ let(:dummy) { DummyObject.create name: nil }
9
+ let(:notifications) { Notifly::Notification }
10
+
11
+ it 'should return the method return' do
12
+ expect(smart.buzz).to eql('buzz')
13
+ expect(dummy.buzz).to eql('buzz')
14
+
15
+ expect(smart.update(name: 'smart')).to be_truthy
16
+ expect(dummy.update(name: 'dummy')).to be_truthy
17
+ end
18
+
19
+ context 'when using ActiveRecord methods' do
20
+ describe 'class methods' do
21
+ describe '.create' do
22
+ it { expect { DummyObject.create name: 'dummy' }.
23
+ to_not change(notifications.where(template: :create), :count) }
24
+ it { expect { DummyObject.create name: 'smart' }.
25
+ to change(notifications.where(template: :create), :count).from(0).to(1) }
26
+ end
27
+ end
28
+
29
+ describe 'instance methods' do
30
+ before(:each) do
31
+ smart
32
+ dummy
33
+ notifications.delete_all
34
+ end
35
+
36
+ describe '#save' do
37
+ it { expect { smart.save! }.to change(notifications.
38
+ where(template: :save), :count).from(0).to(1) }
39
+ it { expect { dummy.save! }.to_not change(notifications.
40
+ where(template: :save), :count) }
41
+ end
42
+
43
+ describe '#update' do
44
+ it { expect { dummy.update!(name: 'smart') }.to change(notifications.
45
+ where(template: :update), :count).from(0).to(1) }
46
+ it { expect { smart.update!(name: 'dummy') }.to_not change(notifications.
47
+ where(template: :update), :count) }
48
+ end
49
+
50
+ describe '#destroy' do
51
+ it { expect { smart.destroy! }.to change(notifications, :count).
52
+ from(0).to(1) }
53
+ it { expect { dummy.destroy! }.to_not change(notifications, :count) }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,89 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Post, :type => :model do
4
+ it { is_expected.to belong_to(:dummy_object) }
5
+
6
+ describe 'Notifly' do
7
+ let(:dummy) { DummyObject.create! }
8
+ let(:post) { Post.create! dummy_object: dummy, published: false }
9
+ let(:notification) { Notifly::Notification.take }
10
+
11
+ describe 'initialization' do
12
+ it { expect(Post).to respond_to :notifly }
13
+ end
14
+
15
+ describe 'usage' do
16
+ it 'should create a notification when is published' do
17
+ expect(Notifly::Notification.count).to eql 0
18
+
19
+ expect { post.publish! }.to change(Notifly::Notification, :count).from(0).to(1)
20
+ expect(notification.receiver).to eql dummy
21
+ expect(notification.target).to eql post
22
+ expect(notification.template).to eql 'publish'
23
+ end
24
+
25
+ describe 'Notification fallback (data)' do
26
+ it 'should use Notifly::Notification#data for missing informations' do
27
+ post_attributes = post.attributes
28
+ expect { post.destroy }.to change(Notifly::Notification, :count).from(0).to(1)
29
+
30
+ expect(notification.receiver).to eql dummy
31
+ expect(notification.template).to eql 'destroy'
32
+ expect(notification.reload.data).to eql post_attributes
33
+ end
34
+ end
35
+
36
+ context 'when run notifly by order' do
37
+ context 'when post title starts with nil' do
38
+ it 'should send two notifications' do
39
+ expect { post.change_title }.to change(Notifly::Notification, :count).
40
+ from(0).to(2)
41
+
42
+ expect(Notifly::Notification.first.data['title']).to be_nil
43
+ expect(Notifly::Notification.last.data['title']).to eql 'NewTitle'
44
+ end
45
+ end
46
+
47
+ context 'when post title starts with TitleFoo' do
48
+ it 'should send two notifications' do
49
+ expect_any_instance_of(Post).to receive(:change_title) { nil }
50
+ post = Post.create! dummy_object: dummy, title: 'TitleFoo'
51
+
52
+ expect { post.change_title }.to_not change(Notifly::Notification, :count)
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '#notifly_notifications' do
59
+ it 'should show its notifications' do
60
+ dummy_notification = Notifly::Notification.create! receiver: dummy,
61
+ sender: post
62
+ post_notifications = (1..3).map do
63
+ Notifly::Notification.create! receiver: post, sender: dummy
64
+ end
65
+
66
+ expect(post.notifly_notifications).to include(*post_notifications)
67
+ expect(post.notifly_notifications).to_not include(dummy_notification)
68
+ end
69
+
70
+ it 'should query its notifications' do
71
+ dummy_2 = DummyObject.create
72
+ notification_1 = Notifly::Notification.create! receiver: post,
73
+ sender: dummy, template: 'destroy'
74
+ notification_2 = Notifly::Notification.create! receiver: post,
75
+ sender: dummy, target: dummy_2
76
+ notification_3 = Notifly::Notification.create! receiver: post,
77
+ sender: dummy, target: dummy_2
78
+
79
+ destroy_notifications = post.notifly_notifications.where(template: 'destroy')
80
+ dummy_2_notifications = post.notifly_notifications.where(target: dummy_2)
81
+
82
+ expect(destroy_notifications).to include(notification_1)
83
+ expect(destroy_notifications).to_not include(notification_2, notification_3)
84
+ expect(dummy_2_notifications).to include(notification_2, notification_3)
85
+ expect(dummy_2_notifications).to_not include(notification_1)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,18 @@
1
+ require 'rails_helper'
2
+
3
+ module Notifly
4
+ RSpec.describe Notification, :type => :model do
5
+ it { is_expected.to validate_presence_of(:receiver) }
6
+
7
+ describe '#data' do
8
+ it 'should save and repond with a hash' do
9
+ hash = { 'post' => Post.create!.attributes }
10
+
11
+ notification = Notifly::Notification.create! receiver: DummyObject.create,
12
+ template: :foo, data: hash
13
+
14
+ expect(notification.reload.data).to eql hash
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ ENV["RAILS_ENV"] ||= 'test'
3
+ require 'spec_helper'
4
+ require File.expand_path("../dummy/config/environment", __FILE__)
5
+ require 'rspec/rails'
6
+ require 'shoulda/matchers'
7
+ require 'capybara/rails'
8
+ require 'capybara/rspec'
9
+ require 'capybara/poltergeist'
10
+ Capybara.javascript_driver = :poltergeist
11
+
12
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
13
+
14
+ # Checks for pending migrations before tests are run.
15
+ ActiveRecord::Migration.maintain_test_schema!
16
+
17
+ RSpec.configure do |config|
18
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
19
+ config.use_transactional_fixtures = true
20
+ config.infer_spec_type_from_file_location!
21
+ end
@@ -0,0 +1,62 @@
1
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
2
+
3
+ RSpec.configure do |config|
4
+ if config.files_to_run.one?
5
+ config.default_formatter = 'doc'
6
+ end
7
+
8
+ config.expect_with :rspec do |expectations|
9
+ expectations.syntax = :expect
10
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
11
+ end
12
+
13
+ config.mock_with :rspec do |mocks|
14
+ mocks.syntax = :expect
15
+ mocks.verify_partial_doubles = true
16
+ end
17
+
18
+ # The settings below are suggested to provide a good initial experience
19
+ # with RSpec, but feel free to customize to your heart's content.
20
+ =begin
21
+ # These two settings work together to allow you to limit a spec run
22
+ # to individual examples or groups you care about by tagging them with
23
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
24
+ # get run.
25
+ config.filter_run :focus
26
+ config.run_all_when_everything_filtered = true
27
+
28
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
29
+ # For more details, see:
30
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
31
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
32
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
33
+ config.disable_monkey_patching!
34
+
35
+ # Many RSpec users commonly either run the entire suite or an individual
36
+ # file, and it's useful to allow more verbose output when running an
37
+ # individual spec file.
38
+ if config.files_to_run.one?
39
+ # Use the documentation formatter for detailed output,
40
+ # unless a formatter has already been configured
41
+ # (e.g. via a command-line flag).
42
+ config.default_formatter = 'doc'
43
+ end
44
+
45
+ # Print the 10 slowest examples and example groups at the
46
+ # end of the spec run, to help surface which specs are running
47
+ # particularly slow.
48
+ config.profile_examples = 10
49
+
50
+ # Run specs in random order to surface order dependencies. If you find an
51
+ # order dependency and want to debug it, you can fix the order by providing
52
+ # the seed, which is printed after each run.
53
+ # --seed 1234
54
+ config.order = :random
55
+
56
+ # Seed global randomization in this process using the `--seed` CLI option.
57
+ # Setting this allows you to use `--seed` to deterministically reproduce
58
+ # test failures related to randomization by passing the same `--seed` value
59
+ # as the one that triggered the failure.
60
+ Kernel.srand config.seed
61
+ =end
62
+ end
@@ -0,0 +1,14 @@
1
+ # http://helabs.com.br/blog/2013/02/06/testes-mais-rapidos-no-rspec
2
+
3
+ class ActiveRecord::Base
4
+ mattr_accessor :shared_connection
5
+ @@shared_connection = nil
6
+
7
+ def self.connection
8
+ @@shared_connection || retrieve_connection
9
+ end
10
+ end
11
+
12
+ # Forces all threads to share the same connection. This works on
13
+ # Capybara because it starts the web server in a thread.
14
+ ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
@@ -0,0 +1,3 @@
1
+ # http://helabs.com.br/blog/2013/02/06/testes-mais-rapidos-no-rspec
2
+
3
+ Rails.logger.level = 4 unless ENV['WITH_LOG']
@@ -0,0 +1,53 @@
1
+ # Ajax testing with ruby and capybara
2
+ #
3
+ # Add this to spec/support
4
+ #
5
+ # When a link or button starts an ajax request, instead of use Capybara
6
+ # click_link, click_button and click_link_or_button methods use click_ajax_link,
7
+ # click_ajax_button and click_ajax_link_or_button methods. You can still use
8
+ # capybara methods and right after it, call wait_for_ajax method.
9
+ #
10
+ # This methods will wait until Capybara.default_wait_time for the ajax request
11
+ # to finish before continue the normal tests flow.
12
+ #
13
+
14
+ require 'timeout'
15
+
16
+ module WaitForAjax
17
+ def click_ajax_link(locator, options = {})
18
+ click_link(locator, options)
19
+
20
+ wait_for_ajax
21
+ end
22
+
23
+ def click_ajax_button(locator, options = {})
24
+ click_button(locator, options)
25
+
26
+ wait_for_ajax
27
+ end
28
+
29
+ def click_ajax_link_or_button(locator, options = {})
30
+ click_link_or_button(locator, options)
31
+
32
+ wait_for_ajax
33
+ end
34
+
35
+ def wait_for_ajax(&block)
36
+ block.call if block
37
+
38
+ Timeout.timeout(Capybara.default_wait_time) do
39
+ loop do
40
+ sleep 0.1
41
+ break if finished_all_ajax_requests?
42
+ end
43
+ end
44
+ end
45
+
46
+ def finished_all_ajax_requests?
47
+ page.evaluate_script('jQuery.active').zero?
48
+ end
49
+ end
50
+
51
+ RSpec.configure do |config|
52
+ config.include WaitForAjax
53
+ end