marty 8.0.0 → 8.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +7 -0
- data/app/assets/javascripts/marty/cable.js +12 -0
- data/app/assets/stylesheets/marty/codemirror/notifications.css +4 -0
- data/app/channels/application_cable/channel.rb +4 -0
- data/app/channels/application_cable/connection.rb +17 -0
- data/app/channels/marty/notification_channel.rb +8 -0
- data/app/components/marty/auth_app.rb +54 -6
- data/app/components/marty/auth_app/client/auth_app.js +53 -0
- data/app/components/marty/main_auth_app.rb +47 -1
- data/app/components/marty/notifications/config_view.rb +56 -0
- data/app/components/marty/notifications/deliveries_view.rb +50 -0
- data/app/components/marty/notifications/grid_view.rb +56 -0
- data/app/components/marty/notifications/window.rb +23 -0
- data/app/components/marty/promise_view.rb +13 -1
- data/app/components/marty/promise_view/client/promise_view.js +18 -0
- data/app/components/marty/{schedule_jobs_dashboard/client/schedule_jobs_dashboard.js → schedule_jobs_grid/client/schedule_jobs_grid.js} +0 -0
- data/app/components/marty/simple_app/client/simple_app.js +5 -1
- data/app/components/marty/users/user_view.rb +177 -0
- data/app/controllers/marty/application_controller.rb +13 -0
- data/app/models/marty/data_grid.rb +1 -1
- data/app/models/marty/notifications.rb +4 -0
- data/app/models/marty/notifications/config.rb +25 -0
- data/app/models/marty/notifications/delivery.rb +56 -0
- data/app/models/marty/notifications/event_type.rb +11 -0
- data/app/models/marty/notifications/notification.rb +25 -0
- data/app/models/marty/promise.rb +1 -0
- data/app/models/marty/user.rb +14 -0
- data/app/services/marty/notifications/create.rb +39 -0
- data/app/services/marty/notifications/create_deliveries.rb +25 -0
- data/app/services/marty/notifications/process_delivery.rb +11 -0
- data/app/services/marty/notifications/processors/email.rb +13 -0
- data/app/services/marty/notifications/processors/sms.rb +13 -0
- data/app/services/marty/notifications/processors/web.rb +27 -0
- data/app/services/marty/promises/cancel.rb +37 -0
- data/app/services/marty/promises/delorean/create.rb +4 -0
- data/app/services/marty/promises/ruby/create.rb +4 -1
- data/app/views/marty/diagnostic/op.html.erb +4 -0
- data/db/migrate/514_remove_marty_events.rb +1 -1
- data/db/migrate/519_create_marty_notifications_event_types.rb +16 -0
- data/db/migrate/520_create_marty_notifications.rb +11 -0
- data/db/migrate/521_create_marty_notifications_deliveries.rb +22 -0
- data/db/migrate/522_create_marty_notifications_config.rb +21 -0
- data/db/sql/lookup_grid_distinct_v1.sql +6 -6
- data/lib/marty.rb +2 -0
- data/lib/marty/diagnostic/version.rb +36 -26
- data/lib/marty/engine.rb +7 -1
- data/lib/marty/mcfly_model.rb +27 -6
- data/lib/marty/railtie.rb +1 -0
- data/lib/marty/version.rb +1 -1
- data/marty.gemspec +3 -0
- data/spec/controllers/diagnostic/controller_spec.rb +1 -1
- data/spec/dummy/app/models/gemini/fannie_bup.rb +27 -13
- data/spec/dummy/app/models/gemini/helper.rb +62 -0
- data/spec/features/notifications_spec.rb +224 -0
- data/spec/job_helper.rb +14 -1
- data/spec/lib/mcfly_model_spec.rb +14 -7
- data/spec/models/promise_spec.rb +121 -0
- data/spec/services/notifications/create_spec.rb +82 -0
- metadata +73 -3
data/lib/marty/engine.rb
CHANGED
@@ -14,7 +14,13 @@ module Marty
|
|
14
14
|
|
15
15
|
config.assets.precompile += [
|
16
16
|
'marty/application.js',
|
17
|
-
'marty/
|
17
|
+
'marty/cable.js',
|
18
|
+
'marty/application.css',
|
19
|
+
'marty/dark_mode.css'
|
18
20
|
]
|
21
|
+
|
22
|
+
config.action_cable.disable_request_forgery_protection = true
|
23
|
+
# Can be overriden by config/cable.yml in Rails app
|
24
|
+
ActionCable.server.config.cable ||= { 'adapter' => 'postgresql' }
|
19
25
|
end
|
20
26
|
end
|
data/lib/marty/mcfly_model.rb
CHANGED
@@ -6,10 +6,16 @@ module Mcfly::Model
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module ClassMethods
|
9
|
-
def
|
9
|
+
def openstruct_if_necessary(q, private)
|
10
10
|
!private && q.is_a?(ActiveRecord::Base) ? make_openstruct(q) : q
|
11
11
|
end
|
12
12
|
|
13
|
+
def hash_if_necessary(q, to_hash)
|
14
|
+
return make_hash(q) if to_hash && q.is_a?(ActiveRecord::Base)
|
15
|
+
|
16
|
+
q
|
17
|
+
end
|
18
|
+
|
13
19
|
def base_mcfly_lookup(name, options = {}, &block)
|
14
20
|
delorean_options = {
|
15
21
|
# private: options.fetch(:private, false),
|
@@ -41,7 +47,14 @@ module Mcfly::Model
|
|
41
47
|
|
42
48
|
q = q.first if q.respond_to?(:first) && options[:mode] == :first
|
43
49
|
|
44
|
-
|
50
|
+
if options[:to_hash]
|
51
|
+
next hash_if_necessary(
|
52
|
+
q,
|
53
|
+
options.fetch(:to_hash, false)
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
openstruct_if_necessary(q, options[:private])
|
45
58
|
end
|
46
59
|
end
|
47
60
|
|
@@ -55,7 +68,7 @@ module Mcfly::Model
|
|
55
68
|
|
56
69
|
def gen_mcfly_lookup(name, attrs, options = {})
|
57
70
|
raise "bad options #{options.keys}" unless
|
58
|
-
|
71
|
+
(options.keys - [:mode, :cache, :private, :to_hash]).empty?
|
59
72
|
|
60
73
|
mode = options.fetch(:mode, :first)
|
61
74
|
|
@@ -134,7 +147,7 @@ module Mcfly::Model
|
|
134
147
|
|
135
148
|
pc_name = "pc_#{name}".to_sym
|
136
149
|
|
137
|
-
gen_mcfly_lookup(pc_name, pc_attrs, options + { private: true })
|
150
|
+
gen_mcfly_lookup(pc_name, pc_attrs, options + { private: true, to_hash: false })
|
138
151
|
|
139
152
|
lpi = attrs.keys.index rel_attr
|
140
153
|
|
@@ -142,7 +155,7 @@ module Mcfly::Model
|
|
142
155
|
raise "need #{rel_attr} argument" unless lpi
|
143
156
|
|
144
157
|
# cache if mode is not nil
|
145
|
-
|
158
|
+
to_hash = options.fetch(:to_hash, false)
|
146
159
|
|
147
160
|
# cache if mode is not explicitly set to nil or cache is true
|
148
161
|
cache = options.fetch(:cache) { options.fetch(:mode, :first) }
|
@@ -165,7 +178,15 @@ module Mcfly::Model
|
|
165
178
|
send(cat_attr_id)
|
166
179
|
|
167
180
|
q = send(pc_name, ts, *args)
|
168
|
-
|
181
|
+
|
182
|
+
if to_hash
|
183
|
+
next hash_if_necessary(
|
184
|
+
q,
|
185
|
+
options.fetch(:to_hash, false)
|
186
|
+
)
|
187
|
+
end
|
188
|
+
|
189
|
+
openstruct_if_necessary(q, options[:private])
|
169
190
|
end
|
170
191
|
end
|
171
192
|
end
|
data/lib/marty/railtie.rb
CHANGED
data/lib/marty/version.rb
CHANGED
data/marty.gemspec
CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.files = `git ls-files`.split($\)
|
28
28
|
s.licenses = ['MIT']
|
29
29
|
# used for signing aws ec2 requests
|
30
|
+
s.add_dependency 'actioncable'
|
30
31
|
s.add_dependency 'aws-sigv4'
|
31
32
|
# Only pinning this because there's no other way around it for Axlsx.
|
32
33
|
# DO NOT unpin this.
|
@@ -43,5 +44,7 @@ Gem::Specification.new do |s|
|
|
43
44
|
s.add_dependency 'pg'
|
44
45
|
s.add_dependency 'redis'
|
45
46
|
s.add_dependency 'rubyzip'
|
47
|
+
s.add_dependency 'state_machines'
|
48
|
+
s.add_dependency 'state_machines-activerecord'
|
46
49
|
s.add_dependency 'zip-zip'
|
47
50
|
end
|
@@ -29,63 +29,77 @@ module Gemini
|
|
29
29
|
gen_mcfly_lookup :lookup, {
|
30
30
|
entity: true,
|
31
31
|
note_rate: false
|
32
|
-
}
|
32
|
+
}, to_hash: true
|
33
|
+
|
33
34
|
gen_mcfly_lookup :lookup_p, {
|
34
35
|
entity: true,
|
35
36
|
note_rate: false
|
36
|
-
},
|
37
|
+
}, to_hash: false
|
38
|
+
|
37
39
|
gen_mcfly_lookup :clookup, {
|
38
40
|
entity: true,
|
39
41
|
note_rate: false
|
40
|
-
}, cache: true
|
42
|
+
}, cache: true, to_hash: true
|
43
|
+
|
41
44
|
gen_mcfly_lookup :clookup_p, {
|
42
45
|
entity: true,
|
43
46
|
note_rate: false
|
44
|
-
}, cache: true,
|
47
|
+
}, cache: true, to_hash: false
|
48
|
+
|
45
49
|
gen_mcfly_lookup :lookupn, {
|
46
50
|
entity: true,
|
47
51
|
note_rate: false
|
48
|
-
}, mode: nil
|
52
|
+
}, mode: nil, to_hash: true
|
53
|
+
|
49
54
|
gen_mcfly_lookup :lookupn_p, {
|
50
55
|
entity: true,
|
51
56
|
note_rate: false
|
52
|
-
},
|
57
|
+
}, to_hash: false, mode: nil
|
58
|
+
|
53
59
|
gen_mcfly_lookup :clookupn, {
|
54
60
|
entity: true,
|
55
61
|
note_rate: false
|
56
|
-
}, cache: true, mode: nil
|
62
|
+
}, cache: true, mode: nil, to_hash: true
|
63
|
+
|
57
64
|
gen_mcfly_lookup :clookupn_p, {
|
58
65
|
entity: true,
|
59
66
|
note_rate: false
|
60
|
-
}, cache: true,
|
67
|
+
}, cache: true, to_hash: false, mode: nil
|
61
68
|
|
62
|
-
mcfly_lookup :a_func, sig: 3 do
|
69
|
+
mcfly_lookup :a_func, sig: 3, to_hash: true do
|
63
70
|
|pt, e_id, bc_id|
|
64
71
|
where(entity_id: e_id, bud_category_id: bc_id).
|
65
72
|
order(:settlement_mm)
|
66
73
|
end
|
67
74
|
|
68
|
-
mcfly_lookup :b_func, sig: [3, 4] do
|
75
|
+
mcfly_lookup :b_func, sig: [3, 4], to_hash: true do
|
76
|
+
|pt, e_id, bc_id, mm = nil|
|
77
|
+
q = where(entity_id: e_id, bud_category_id: bc_id)
|
78
|
+
q = q.where(settlement_mm: mm) if mm
|
79
|
+
q.order(:settlement_mm).first
|
80
|
+
end
|
81
|
+
|
82
|
+
mcfly_lookup :c_func, sig: [3, 4], to_hash: false do
|
69
83
|
|pt, e_id, bc_id, mm = nil|
|
70
84
|
q = where(entity_id: e_id, bud_category_id: bc_id)
|
71
85
|
q = q.where(settlement_mm: mm) if mm
|
72
86
|
q.order(:settlement_mm).first
|
73
87
|
end
|
74
88
|
|
75
|
-
mcfly_lookup :a_func_p, sig: 3,
|
89
|
+
mcfly_lookup :a_func_p, sig: 3, to_hash: false do
|
76
90
|
|pt, e_id, bc_id|
|
77
91
|
where(entity_id: e_id, bud_category_id: bc_id).
|
78
92
|
order(:settlement_mm)
|
79
93
|
end
|
80
94
|
|
81
|
-
mcfly_lookup :b_func_p, sig: [3, 4],
|
95
|
+
mcfly_lookup :b_func_p, sig: [3, 4], to_hash: false do
|
82
96
|
|pt, e_id, bc_id, mm = nil|
|
83
97
|
q = where(entity_id: e_id, bud_category_id: bc_id)
|
84
98
|
q = q.where(settlement_mm: mm) if mm
|
85
99
|
q.order(:settlement_mm)
|
86
100
|
end
|
87
101
|
|
88
|
-
cached_mcfly_lookup :ca_func, sig: 3 do
|
102
|
+
cached_mcfly_lookup :ca_func, sig: 3, to_hash: true do
|
89
103
|
|pt, e_id, bc_id|
|
90
104
|
where(entity_id: e_id, bud_category_id: bc_id).
|
91
105
|
order(:settlement_mm)
|
@@ -34,6 +34,68 @@ class Gemini::Helper
|
|
34
34
|
idh.values.map { |h| h['result'] }
|
35
35
|
end
|
36
36
|
|
37
|
+
def self.pr_wait(ids)
|
38
|
+
idh = ids.each_with_object({}) do |id, h|
|
39
|
+
h[id] = false
|
40
|
+
end
|
41
|
+
timeout = 60
|
42
|
+
all_done = false
|
43
|
+
loop do
|
44
|
+
idh.each do |id, v|
|
45
|
+
next if v
|
46
|
+
p = Marty::Promise.uncached { Marty::Promise.find_by(id: id) }
|
47
|
+
idh[id] = p.result if p.status
|
48
|
+
end
|
49
|
+
all_done = idh.values.all? { |v| v }
|
50
|
+
break if all_done || timeout == 0
|
51
|
+
timeout -= 1
|
52
|
+
sleep 1
|
53
|
+
end
|
54
|
+
raise "DID NOT FINISH" unless all_done
|
55
|
+
idh.values.map { |h| h['result'] }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.promise_test(job_title)
|
59
|
+
sleep 5
|
60
|
+
pps = [1, 2, 3].map do |id|
|
61
|
+
new_title = job_title + ' ' + id.to_s
|
62
|
+
Marty::Promises::Ruby::Create.call(
|
63
|
+
module_name: 'Gemini::Helper',
|
64
|
+
method_name: 'promise_test_1',
|
65
|
+
method_args: [new_title],
|
66
|
+
params: {
|
67
|
+
p_title: new_title,
|
68
|
+
_user_id: 1,
|
69
|
+
_parent_id: ENV['__promise_id']&.to_i
|
70
|
+
}.compact
|
71
|
+
).as_json.values.first.first
|
72
|
+
end
|
73
|
+
pr_wait(pps)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.promise_test_1(job_title)
|
77
|
+
pps = [1, 2, 3].map do |id|
|
78
|
+
new_title = job_title + ' ' + id.to_s
|
79
|
+
sleep 2
|
80
|
+
Marty::Promises::Ruby::Create.call(
|
81
|
+
module_name: 'Gemini::Helper',
|
82
|
+
method_name: 'promise_test_2',
|
83
|
+
method_args: [new_title],
|
84
|
+
params: {
|
85
|
+
p_title: new_title,
|
86
|
+
_user_id: 1,
|
87
|
+
_parent_id: ENV['__promise_id']&.to_i
|
88
|
+
}.compact
|
89
|
+
).as_json.values.first.first
|
90
|
+
end
|
91
|
+
pr_wait(pps)
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.promise_test_2(job_title)
|
95
|
+
sleep(5, job_title)
|
96
|
+
job_title
|
97
|
+
end
|
98
|
+
|
37
99
|
# Just for testing
|
38
100
|
delorean_fn :to_csv, sig: [1, 2] do
|
39
101
|
|*args|
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
feature 'Notifications spec', js: true do
|
4
|
+
before do
|
5
|
+
populate_test_users
|
6
|
+
|
7
|
+
::Marty::Notifications::Config.create!(
|
8
|
+
event_type: event_type,
|
9
|
+
recipient: user1,
|
10
|
+
delivery_type: :web,
|
11
|
+
state: :on,
|
12
|
+
text: 'Please contact the customer'
|
13
|
+
)
|
14
|
+
|
15
|
+
Marty::Notifications::Create.call(
|
16
|
+
event_type: event_type,
|
17
|
+
text: 'Test limit is 1000'
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:user1) do
|
22
|
+
Marty::User.find_by(login: :marty)
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:user2) do
|
26
|
+
Marty::User.find_by(login: :viewer1)
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:event_type) do
|
30
|
+
'API reached the limit'
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:notification_grid) do
|
34
|
+
netzke_find 'grid_view'
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'as admin' do
|
38
|
+
before do
|
39
|
+
log_in_as('marty')
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'Notifications pop-up' do
|
43
|
+
it 'shows notifications' do
|
44
|
+
notification_link = find 'a[data-qtip="Show notifications"]'
|
45
|
+
expect(notification_link.text).to eq '1'
|
46
|
+
|
47
|
+
notification_link.click
|
48
|
+
|
49
|
+
wait_for_ajax
|
50
|
+
|
51
|
+
expect(notification_grid.row_count).to eq 1
|
52
|
+
values = notification_grid.get_row_vals 1
|
53
|
+
|
54
|
+
expect(values['notification__event_type']).to eq 'API reached the limit'
|
55
|
+
|
56
|
+
expect(values['text']).to eq(
|
57
|
+
'Test limit is 1000, Please contact the customer'
|
58
|
+
)
|
59
|
+
|
60
|
+
expect(values['error_text']).to eq ''
|
61
|
+
|
62
|
+
close_btn = find 'div[data-qtip="Close dialog"]'
|
63
|
+
close_btn.click
|
64
|
+
|
65
|
+
# Check that no unread notifications left
|
66
|
+
notification_link = find 'a[data-qtip="Show notifications"]'
|
67
|
+
expect(notification_link.text).to eq ''
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'Configuration grid' do
|
72
|
+
before do
|
73
|
+
press('System')
|
74
|
+
press('Notifications')
|
75
|
+
press('User Notification Rules')
|
76
|
+
|
77
|
+
wait_for_ajax
|
78
|
+
end
|
79
|
+
|
80
|
+
let(:grid) do
|
81
|
+
netzke_find 'notifications_config_view'
|
82
|
+
end
|
83
|
+
|
84
|
+
let(:state_select) do
|
85
|
+
netzke_find('state', 'combobox')
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:event_type_select) do
|
89
|
+
netzke_find('event_type', 'combobox')
|
90
|
+
end
|
91
|
+
|
92
|
+
let(:recipient_select) do
|
93
|
+
netzke_find('recipient__name', 'combobox')
|
94
|
+
end
|
95
|
+
|
96
|
+
let(:delivery_type_select) do
|
97
|
+
netzke_find('delivery_type', 'combobox')
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'allows to view and edit configuration' do
|
101
|
+
expect(grid.row_count).to eq 1
|
102
|
+
|
103
|
+
by 'turns the rule off' do
|
104
|
+
values = grid.get_row_vals 1
|
105
|
+
expect(values['state']).to eq 'on'
|
106
|
+
|
107
|
+
grid.select_row 1
|
108
|
+
press 'Edit'
|
109
|
+
|
110
|
+
state_select.select_values 'off'
|
111
|
+
|
112
|
+
press 'OK'
|
113
|
+
|
114
|
+
wait_for_ajax
|
115
|
+
|
116
|
+
values = grid.get_row_vals 1
|
117
|
+
expect(values['state']).to eq 'off'
|
118
|
+
end
|
119
|
+
|
120
|
+
and_by 'adds new rule' do
|
121
|
+
press 'Add'
|
122
|
+
|
123
|
+
event_type_select.select_values 'API reached the limit'
|
124
|
+
|
125
|
+
recipient_select.click
|
126
|
+
recipient_select.select_values 'admin1 admin1'
|
127
|
+
|
128
|
+
delivery_type_select.select_values 'web'
|
129
|
+
|
130
|
+
fill_in :text, with: 'example text'
|
131
|
+
|
132
|
+
press 'OK'
|
133
|
+
|
134
|
+
wait_for_ajax
|
135
|
+
|
136
|
+
expect(grid.row_count).to eq 2
|
137
|
+
|
138
|
+
values = grid.get_row_vals 1
|
139
|
+
expect(values['state']).to eq 'on'
|
140
|
+
expect(values['text']).to eq 'example text'
|
141
|
+
expect(values['recipient__name']).to eq 'admin1 admin1'
|
142
|
+
end
|
143
|
+
|
144
|
+
and_by "doesn't allow to duplicate the rule with the same delivery_type" do
|
145
|
+
press 'Add'
|
146
|
+
|
147
|
+
event_type_select.select_values 'API reached the limit'
|
148
|
+
|
149
|
+
recipient_select.click
|
150
|
+
recipient_select.select_values 'admin1 admin1'
|
151
|
+
|
152
|
+
delivery_type_select.select_values 'web'
|
153
|
+
|
154
|
+
fill_in :text, with: 'example text'
|
155
|
+
|
156
|
+
press 'OK'
|
157
|
+
|
158
|
+
expect(page).to have_content 'Delivery type has already been taken'
|
159
|
+
|
160
|
+
press 'Cancel'
|
161
|
+
end
|
162
|
+
|
163
|
+
and_by 'deletes rule' do
|
164
|
+
row_count = grid.row_count
|
165
|
+
|
166
|
+
grid.select_row 1
|
167
|
+
press 'Delete'
|
168
|
+
press 'Yes'
|
169
|
+
|
170
|
+
wait_for_ajax
|
171
|
+
|
172
|
+
expect(grid.row_count).to eq(row_count - 1)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'as viewer' do
|
179
|
+
before do
|
180
|
+
::Marty::Notifications::Config.create!(
|
181
|
+
event_type: event_type,
|
182
|
+
recipient: user2,
|
183
|
+
delivery_type: :web,
|
184
|
+
state: :on,
|
185
|
+
text: 'Please notify your manager'
|
186
|
+
)
|
187
|
+
|
188
|
+
Marty::Notifications::Create.call(
|
189
|
+
event_type: event_type,
|
190
|
+
text: 'Test limit is 1000'
|
191
|
+
)
|
192
|
+
|
193
|
+
log_in_as('viewer1')
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'shows notifications' do
|
197
|
+
notification_link = find 'a[data-qtip="Show notifications"]'
|
198
|
+
expect(notification_link.text).to eq '1'
|
199
|
+
|
200
|
+
notification_link.click
|
201
|
+
|
202
|
+
wait_for_ajax
|
203
|
+
|
204
|
+
expect(notification_grid.row_count).to eq 1
|
205
|
+
values = notification_grid.get_row_vals 1
|
206
|
+
|
207
|
+
expect(values['notification__event_type']).to eq 'API reached the limit'
|
208
|
+
|
209
|
+
expect(values['text']).to eq(
|
210
|
+
'Test limit is 1000, Please notify your manager'
|
211
|
+
)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "doesn't have access to notifications config" do
|
215
|
+
visit '#notifications_config_view'
|
216
|
+
expect(page).to have_content "You don't have permissions to read data"
|
217
|
+
end
|
218
|
+
|
219
|
+
it "doesn't have access to all notification messages" do
|
220
|
+
visit '#notifications_deliveries_view'
|
221
|
+
expect(page).to have_content "You don't have permissions to read data"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|