notifly 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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