pushpad 1.4.0 → 1.6.0
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/.github/workflows/ci.yml +2 -2
- data/LICENSE.txt +1 -1
- data/README.md +32 -0
- data/lib/pushpad/notification.rb +2 -1
- data/lib/pushpad/sender.rb +90 -0
- data/lib/pushpad/subscription.rb +4 -3
- data/lib/pushpad.rb +1 -0
- data/pushpad.gemspec +1 -1
- data/spec/pushpad/notification_spec.rb +2 -0
- data/spec/pushpad/sender_spec.rb +199 -0
- data/spec/pushpad/subscription_spec.rb +2 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79880c6abcf0f8ecda48ad0df65bb07ee440660f58fb5fd60d898ceb162d5263
|
4
|
+
data.tar.gz: aa148bdaf14910ea7041867163d3f524682be1e54533d6153c790326961c7edc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e0b08f9dc1b48b61fc4fc12f8a0a6a22872de66d4e61736792a5548b2f4795b36e5f9275589cfd8d717baf86278908b0833305bbb6fd1ab8fac75150a47d177
|
7
|
+
data.tar.gz: '08d16dc17ec9b9a5e2454f254fde072880c2eb50f84b298b882362d36c9b40dc8957b75fcb8935b5e045279c76a1da7de4fbaea685d8e9dedfed365d2993f093'
|
data/.github/workflows/ci.yml
CHANGED
@@ -10,9 +10,9 @@ jobs:
|
|
10
10
|
strategy:
|
11
11
|
fail-fast: false
|
12
12
|
matrix:
|
13
|
-
ruby-version: ['3.0', '3.1', '3.2', '3.3']
|
13
|
+
ruby-version: ['3.0', '3.1', '3.2', '3.3', '3.4']
|
14
14
|
steps:
|
15
|
-
- uses: actions/checkout@
|
15
|
+
- uses: actions/checkout@v5
|
16
16
|
- name: Set up Ruby
|
17
17
|
uses: ruby/setup-ruby@v1
|
18
18
|
with:
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2016-
|
3
|
+
Copyright (c) 2016-2025 Pushpad (https://pushpad.xyz)
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -350,6 +350,38 @@ project.update(name: 'The New Project Name')
|
|
350
350
|
project.delete
|
351
351
|
```
|
352
352
|
|
353
|
+
## Managing senders
|
354
|
+
|
355
|
+
Senders are usually created manually from the Pushpad dashboard. However you can also create senders from code.
|
356
|
+
|
357
|
+
```ruby
|
358
|
+
attributes = {
|
359
|
+
# required attributes
|
360
|
+
name: "My sender",
|
361
|
+
|
362
|
+
# optional configurations
|
363
|
+
# do not include these fields if you want to generate them automatically
|
364
|
+
vapid_private_key: "-----BEGIN EC PRIVATE KEY----- ...",
|
365
|
+
vapid_public_key: "-----BEGIN PUBLIC KEY----- ..."
|
366
|
+
}
|
367
|
+
|
368
|
+
sender = Pushpad::Sender.create(attributes)
|
369
|
+
```
|
370
|
+
|
371
|
+
You can also find, update and delete senders:
|
372
|
+
|
373
|
+
```ruby
|
374
|
+
Pushpad::Sender.find_all.each do |s|
|
375
|
+
puts "Sender #{s.id}: #{s.name}"
|
376
|
+
end
|
377
|
+
|
378
|
+
sender = Pushpad::Sender.find 987
|
379
|
+
|
380
|
+
sender.update(name: 'The New Sender Name')
|
381
|
+
|
382
|
+
sender.delete
|
383
|
+
```
|
384
|
+
|
353
385
|
## License
|
354
386
|
|
355
387
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/lib/pushpad/notification.rb
CHANGED
@@ -16,10 +16,11 @@ module Pushpad
|
|
16
16
|
end
|
17
17
|
|
18
18
|
attr_accessor :body, :title, :target_url, :icon_url, :badge_url, :image_url, :ttl, :require_interaction, :silent, :urgent, :custom_data, :custom_metrics, :actions, :starred, :send_at
|
19
|
-
attr_reader :id, :created_at, :scheduled_count, :successfully_sent_count, :opened_count
|
19
|
+
attr_reader :id, :project_id, :created_at, :scheduled_count, :successfully_sent_count, :opened_count
|
20
20
|
|
21
21
|
def initialize(options)
|
22
22
|
@id = options[:id]
|
23
|
+
@project_id = options[:project_id]
|
23
24
|
@created_at = options[:created_at] && Time.parse(options[:created_at])
|
24
25
|
@scheduled_count = options[:scheduled_count]
|
25
26
|
@successfully_sent_count = options[:successfully_sent_count]
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Pushpad
|
2
|
+
class Sender
|
3
|
+
class CreateError < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
class FindError < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
class UpdateError < RuntimeError
|
10
|
+
end
|
11
|
+
|
12
|
+
class DeleteError < RuntimeError
|
13
|
+
end
|
14
|
+
|
15
|
+
ATTRIBUTES = :id, :name, :vapid_private_key, :vapid_public_key, :created_at
|
16
|
+
|
17
|
+
attr_reader *ATTRIBUTES
|
18
|
+
|
19
|
+
def initialize(options)
|
20
|
+
@id = options[:id]
|
21
|
+
@name = options[:name]
|
22
|
+
@vapid_private_key = options[:vapid_private_key]
|
23
|
+
@vapid_public_key = options[:vapid_public_key]
|
24
|
+
@created_at = options[:created_at] && Time.parse(options[:created_at])
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.create(attributes)
|
28
|
+
endpoint = "https://pushpad.xyz/api/v1/senders"
|
29
|
+
response = Request.post(endpoint, attributes.to_json)
|
30
|
+
|
31
|
+
unless response.code == "201"
|
32
|
+
raise CreateError, "Response #{response.code} #{response.message}: #{response.body}"
|
33
|
+
end
|
34
|
+
|
35
|
+
new(JSON.parse(response.body, symbolize_names: true))
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.find(id)
|
39
|
+
response = Request.get("https://pushpad.xyz/api/v1/senders/#{id}")
|
40
|
+
|
41
|
+
unless response.code == "200"
|
42
|
+
raise FindError, "Response #{response.code} #{response.message}: #{response.body}"
|
43
|
+
end
|
44
|
+
|
45
|
+
new(JSON.parse(response.body, symbolize_names: true))
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.find_all
|
49
|
+
response = Request.get("https://pushpad.xyz/api/v1/senders")
|
50
|
+
|
51
|
+
unless response.code == "200"
|
52
|
+
raise FindError, "Response #{response.code} #{response.message}: #{response.body}"
|
53
|
+
end
|
54
|
+
|
55
|
+
JSON.parse(response.body, symbolize_names: true).map do |attributes|
|
56
|
+
new(attributes)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def update(attributes)
|
61
|
+
raise "You must set id" unless id
|
62
|
+
|
63
|
+
endpoint = "https://pushpad.xyz/api/v1/senders/#{id}"
|
64
|
+
response = Request.patch(endpoint, attributes.to_json)
|
65
|
+
|
66
|
+
unless response.code == "200"
|
67
|
+
raise UpdateError, "Response #{response.code} #{response.message}: #{response.body}"
|
68
|
+
end
|
69
|
+
|
70
|
+
updated = self.class.new(JSON.parse(response.body, symbolize_names: true))
|
71
|
+
|
72
|
+
ATTRIBUTES.each do |attr|
|
73
|
+
self.instance_variable_set("@#{attr}", updated.instance_variable_get("@#{attr}"))
|
74
|
+
end
|
75
|
+
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def delete
|
80
|
+
raise "You must set id" unless id
|
81
|
+
|
82
|
+
response = Request.delete("https://pushpad.xyz/api/v1/senders/#{id}")
|
83
|
+
|
84
|
+
unless response.code == "204"
|
85
|
+
raise DeleteError, "Response #{response.code} #{response.message}: #{response.body}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
data/lib/pushpad/subscription.rb
CHANGED
@@ -15,10 +15,11 @@ module Pushpad
|
|
15
15
|
class DeleteError < RuntimeError
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :id, :endpoint, :p256dh, :auth, :uid, :tags, :last_click_at, :created_at
|
18
|
+
attr_reader :id, :project_id, :endpoint, :p256dh, :auth, :uid, :tags, :last_click_at, :created_at
|
19
19
|
|
20
20
|
def initialize(options)
|
21
21
|
@id = options[:id]
|
22
|
+
@project_id = options[:project_id]
|
22
23
|
@endpoint = options[:endpoint]
|
23
24
|
@p256dh = options[:p256dh]
|
24
25
|
@auth = options[:auth]
|
@@ -89,7 +90,7 @@ module Pushpad
|
|
89
90
|
end
|
90
91
|
|
91
92
|
def update(attributes, options = {})
|
92
|
-
project_id = options[:project_id] || Pushpad.project_id
|
93
|
+
project_id = project_id || options[:project_id] || Pushpad.project_id
|
93
94
|
raise "You must set project_id" unless project_id
|
94
95
|
|
95
96
|
raise "You must set id" unless id
|
@@ -109,7 +110,7 @@ module Pushpad
|
|
109
110
|
end
|
110
111
|
|
111
112
|
def delete(options = {})
|
112
|
-
project_id = options[:project_id] || Pushpad.project_id
|
113
|
+
project_id = project_id || options[:project_id] || Pushpad.project_id
|
113
114
|
raise "You must set project_id" unless project_id
|
114
115
|
|
115
116
|
raise "You must set id" unless id
|
data/lib/pushpad.rb
CHANGED
data/pushpad.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "pushpad"
|
3
|
-
spec.version = '1.
|
3
|
+
spec.version = '1.6.0'
|
4
4
|
spec.authors = ["Pushpad"]
|
5
5
|
spec.email = ["support@pushpad.xyz"]
|
6
6
|
spec.summary = "Web push notifications for Chrome, Firefox, Opera, Edge and Safari using Pushpad."
|
@@ -62,6 +62,7 @@ module Pushpad
|
|
62
62
|
it "returns notification with attributes from json response" do
|
63
63
|
attributes = {
|
64
64
|
id: 5,
|
65
|
+
project_id: 123,
|
65
66
|
title: "Foo Bar",
|
66
67
|
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
67
68
|
target_url: "https://example.com",
|
@@ -118,6 +119,7 @@ module Pushpad
|
|
118
119
|
it "returns notifications of project with attributes from json response" do
|
119
120
|
attributes = {
|
120
121
|
id: 5,
|
122
|
+
project_id: 123,
|
121
123
|
title: "Foo Bar",
|
122
124
|
body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
123
125
|
target_url: "https://example.com",
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Pushpad
|
4
|
+
describe Sender do
|
5
|
+
|
6
|
+
def stub_senders_post(attributes = {})
|
7
|
+
stub_request(:post, "https://pushpad.xyz/api/v1/senders").
|
8
|
+
with(body: hash_including(attributes)).
|
9
|
+
to_return(status: 201, body: attributes.to_json)
|
10
|
+
end
|
11
|
+
|
12
|
+
def stub_failing_senders_post
|
13
|
+
stub_request(:post, "https://pushpad.xyz/api/v1/senders").
|
14
|
+
to_return(status: 422)
|
15
|
+
end
|
16
|
+
|
17
|
+
def stub_sender_get(attributes)
|
18
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/senders/#{attributes[:id]}").
|
19
|
+
to_return(status: 200, body: attributes.to_json)
|
20
|
+
end
|
21
|
+
|
22
|
+
def stub_failing_sender_get(attributes)
|
23
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/senders/#{attributes[:id]}").
|
24
|
+
to_return(status: 404)
|
25
|
+
end
|
26
|
+
|
27
|
+
def stub_senders_get(list)
|
28
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/senders").
|
29
|
+
to_return(status: 200, body: list.to_json)
|
30
|
+
end
|
31
|
+
|
32
|
+
def stub_failing_senders_get
|
33
|
+
stub_request(:get, "https://pushpad.xyz/api/v1/senders").
|
34
|
+
to_return(status: 401)
|
35
|
+
end
|
36
|
+
|
37
|
+
def stub_sender_patch(id, attributes)
|
38
|
+
stub_request(:patch, "https://pushpad.xyz/api/v1/senders/#{id}").
|
39
|
+
with(body: hash_including(attributes)).
|
40
|
+
to_return(status: 200, body: attributes.to_json)
|
41
|
+
end
|
42
|
+
|
43
|
+
def stub_failing_sender_patch(id)
|
44
|
+
stub_request(:patch, "https://pushpad.xyz/api/v1/senders/#{id}").
|
45
|
+
to_return(status: 422)
|
46
|
+
end
|
47
|
+
|
48
|
+
def stub_sender_delete(id)
|
49
|
+
stub_request(:delete, "https://pushpad.xyz/api/v1/senders/#{id}").
|
50
|
+
to_return(status: 204)
|
51
|
+
end
|
52
|
+
|
53
|
+
def stub_failing_sender_delete(id)
|
54
|
+
stub_request(:delete, "https://pushpad.xyz/api/v1/senders/#{id}").
|
55
|
+
to_return(status: 403)
|
56
|
+
end
|
57
|
+
|
58
|
+
describe ".create" do
|
59
|
+
it "creates a new sender with the given attributes and returns it" do
|
60
|
+
attributes = {
|
61
|
+
name: "My sender"
|
62
|
+
}
|
63
|
+
stub = stub_senders_post(attributes)
|
64
|
+
|
65
|
+
sender = Sender.create(attributes)
|
66
|
+
expect(sender).to have_attributes(attributes)
|
67
|
+
|
68
|
+
expect(stub).to have_been_requested
|
69
|
+
end
|
70
|
+
|
71
|
+
it "fails with CreateError if response status code is not 201" do
|
72
|
+
attributes = { name: "" }
|
73
|
+
stub_failing_senders_post
|
74
|
+
|
75
|
+
expect {
|
76
|
+
Sender.create(attributes)
|
77
|
+
}.to raise_error(Sender::CreateError)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe ".find" do
|
82
|
+
it "returns sender with attributes from json response" do
|
83
|
+
attributes = {
|
84
|
+
id: 182,
|
85
|
+
name: "My sender",
|
86
|
+
vapid_private_key: "-----BEGIN EC PRIVATE KEY----- ...",
|
87
|
+
vapid_public_key: "-----BEGIN PUBLIC KEY----- ...",
|
88
|
+
created_at: "2016-07-06T11:28:21.266Z"
|
89
|
+
}
|
90
|
+
stub_sender_get(attributes)
|
91
|
+
|
92
|
+
sender = Sender.find(182)
|
93
|
+
|
94
|
+
attributes.delete(:created_at)
|
95
|
+
expect(sender).to have_attributes(attributes)
|
96
|
+
expect(sender.created_at.utc.to_s).to eq(Time.utc(2016, 7, 6, 11, 28, 21.266).to_s)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "fails with FindError if response status code is not 200" do
|
100
|
+
attributes = { id: 362 }
|
101
|
+
stub_failing_sender_get(attributes)
|
102
|
+
|
103
|
+
expect {
|
104
|
+
Sender.find(362)
|
105
|
+
}.to raise_error(Sender::FindError)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe ".find_all" do
|
110
|
+
it "returns senders with attributes from json response" do
|
111
|
+
attributes = {
|
112
|
+
id: 182,
|
113
|
+
name: "My sender",
|
114
|
+
vapid_private_key: "-----BEGIN EC PRIVATE KEY----- ...",
|
115
|
+
vapid_public_key: "-----BEGIN PUBLIC KEY----- ...",
|
116
|
+
created_at: "2016-07-06T11:28:21.266Z"
|
117
|
+
}
|
118
|
+
stub_senders_get([attributes])
|
119
|
+
|
120
|
+
senders = Sender.find_all
|
121
|
+
|
122
|
+
attributes.delete(:created_at)
|
123
|
+
expect(senders[0]).to have_attributes(attributes)
|
124
|
+
expect(senders[0].created_at.utc.to_s).to eq(Time.utc(2016, 7, 6, 11, 28, 21.266).to_s)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "fails with FindError if response status code is not 200" do
|
128
|
+
stub_failing_senders_get
|
129
|
+
|
130
|
+
expect {
|
131
|
+
Sender.find_all
|
132
|
+
}.to raise_error(Sender::FindError)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "works properly when there are no results" do
|
136
|
+
stub_senders_get([])
|
137
|
+
|
138
|
+
senders = Sender.find_all
|
139
|
+
|
140
|
+
expect(senders).to eq([])
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "#update" do
|
145
|
+
it "updates a sender with the given attributes and returns it" do
|
146
|
+
attributes = {
|
147
|
+
name: "The New Sender Name"
|
148
|
+
}
|
149
|
+
stub = stub_sender_patch(5, attributes)
|
150
|
+
|
151
|
+
sender = Sender.new(id: 5)
|
152
|
+
sender.update attributes
|
153
|
+
expect(sender).to have_attributes(attributes)
|
154
|
+
|
155
|
+
expect(stub).to have_been_requested
|
156
|
+
end
|
157
|
+
|
158
|
+
it "fails with UpdateError if response status code is not 200" do
|
159
|
+
attributes = { name: "" }
|
160
|
+
stub_failing_sender_patch(5)
|
161
|
+
|
162
|
+
sender = Sender.new(id: 5)
|
163
|
+
|
164
|
+
expect {
|
165
|
+
sender.update attributes
|
166
|
+
}.to raise_error(Sender::UpdateError)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "fails with helpful error message when id is missing" do
|
170
|
+
expect {
|
171
|
+
Sender.new(id: nil).update({})
|
172
|
+
}.to raise_error(/must set id/)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "#delete" do
|
177
|
+
it "deletes a sender" do
|
178
|
+
stub = stub_sender_delete(5)
|
179
|
+
|
180
|
+
sender = Sender.new(id: 5)
|
181
|
+
res = sender.delete
|
182
|
+
expect(res).to be_nil
|
183
|
+
|
184
|
+
expect(stub).to have_been_requested
|
185
|
+
end
|
186
|
+
|
187
|
+
it "fails with DeleteError if response status code is not 204" do
|
188
|
+
stub_failing_sender_delete(5)
|
189
|
+
|
190
|
+
sender = Sender.new(id: 5)
|
191
|
+
|
192
|
+
expect {
|
193
|
+
sender.delete
|
194
|
+
}.to raise_error(Sender::DeleteError)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
@@ -164,6 +164,7 @@ module Pushpad
|
|
164
164
|
it "returns subscription with attributes from json response" do
|
165
165
|
attributes = {
|
166
166
|
id: 5,
|
167
|
+
project_id: 123,
|
167
168
|
endpoint: "https://example.com/push/f7Q1Eyf7EyfAb1",
|
168
169
|
p256dh: "BCQVDTlYWdl05lal3lG5SKr3VxTrEWpZErbkxWrzknHrIKFwihDoZpc_2sH6Sh08h-CacUYI-H8gW4jH-uMYZQ4=",
|
169
170
|
auth: "cdKMlhgVeSPzCXZ3V7FtgQ==",
|
@@ -204,6 +205,7 @@ module Pushpad
|
|
204
205
|
it "returns subscriptions of project with attributes from json response" do
|
205
206
|
attributes = {
|
206
207
|
id: 1169,
|
208
|
+
project_id: 123,
|
207
209
|
endpoint: "https://example.com/push/f7Q1Eyf7EyfAb1",
|
208
210
|
p256dh: "BCQVDTlYWdl05lal3lG5SKr3VxTrEWpZErbkxWrzknHrIKFwihDoZpc_2sH6Sh08h-CacUYI-H8gW4jH-uMYZQ4=",
|
209
211
|
auth: "cdKMlhgVeSPzCXZ3V7FtgQ==",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pushpad
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pushpad
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -56,11 +56,13 @@ files:
|
|
56
56
|
- lib/pushpad/notification.rb
|
57
57
|
- lib/pushpad/project.rb
|
58
58
|
- lib/pushpad/request.rb
|
59
|
+
- lib/pushpad/sender.rb
|
59
60
|
- lib/pushpad/subscription.rb
|
60
61
|
- pushpad.gemspec
|
61
62
|
- spec/pushpad/notification_spec.rb
|
62
63
|
- spec/pushpad/project_spec.rb
|
63
64
|
- spec/pushpad/request_spec.rb
|
65
|
+
- spec/pushpad/sender_spec.rb
|
64
66
|
- spec/pushpad/subscription_spec.rb
|
65
67
|
- spec/pushpad_spec.rb
|
66
68
|
- spec/spec_helper.rb
|
@@ -83,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
85
|
- !ruby/object:Gem::Version
|
84
86
|
version: '0'
|
85
87
|
requirements: []
|
86
|
-
rubygems_version: 3.5.
|
88
|
+
rubygems_version: 3.5.22
|
87
89
|
signing_key:
|
88
90
|
specification_version: 4
|
89
91
|
summary: Web push notifications for Chrome, Firefox, Opera, Edge and Safari using
|
@@ -92,6 +94,7 @@ test_files:
|
|
92
94
|
- spec/pushpad/notification_spec.rb
|
93
95
|
- spec/pushpad/project_spec.rb
|
94
96
|
- spec/pushpad/request_spec.rb
|
97
|
+
- spec/pushpad/sender_spec.rb
|
95
98
|
- spec/pushpad/subscription_spec.rb
|
96
99
|
- spec/pushpad_spec.rb
|
97
100
|
- spec/spec_helper.rb
|