slack_message 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62f8b7feb3289a37b79cb887dc4e7846c037a8c72290138afe611682a066a884
4
- data.tar.gz: 73e391d721ace67ad31ae69b7a17eae3578d4f85a2bcd111a5cb1966b68c85cd
3
+ metadata.gz: '098b332b278741ef63ef105fc7e79cbc7ef131a03dca79b0ed40a1d86001cae1'
4
+ data.tar.gz: 40a4028d38c154fdb1d1835e0f536adc2e57671223290e43a139be1d70a359c3
5
5
  SHA512:
6
- metadata.gz: cb28febfda107047351955825d1cd84dafdf553147b9f0101573944f3d5290c6d3e84a4d1190e63888f6c8ba851ac70da9eb774f1a01a04372d19520b7df8779
7
- data.tar.gz: 3438883916204aec8a16a8dfa80b52506d4f640fc69161ad6e8efea1b5a136e97fc15f8b990c2529f3bbfb1f4380a989a0827cbe8f810af08a42bf3a2b6df382
6
+ metadata.gz: f99700c2fcb33cc7ad9e671f250dc23efffd47e6f4e36d9fdc7740c9ed1a8d4b224b523b6870b13cb3b164a0ae720f93824fae803368083919d776ec2c221236
7
+ data.tar.gz: 1fb9ccc9bf2f9b9fabca5e1cdcdbcde87100f1c056613f0af1450f344bc82adcc5f7366d2f6ab8fb54e34f241018464283c750f2a0d022a67112b9570fc1287e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.0.1] - 2021-12-22
4
+ - Major overhaul of error handling and expansion on which errors trigger
5
+ friendly messages for users.
6
+ - More additions to the docs, and working github pages integration.
7
+ - It's my birthday!
8
+
3
9
  ## [3.0.0] - 2021-12-19
4
10
  - Return a more structured object from successful message sends.
5
11
  - Add the ability to edit or delete a message.
data/README.md CHANGED
@@ -12,8 +12,14 @@ SlackMessage.post_to('#general') do
12
12
  text "We did it @here! :thumbsup:"
13
13
  end
14
14
  ```
15
+
16
+ ### The Docs
15
17
 
16
- #### Posting
18
+ You'll find much more information about how to use SlackMessage by visiting
19
+ [the docs](https://jmmastey.github.io/slack_message).
20
+
21
+
22
+ ### Posting
17
23
 
18
24
  SlackMessage is able to build all kinds of rich messages for you, and has been
19
25
  a real joy to use for the author at least. To understand a bit more about the
@@ -48,12 +54,7 @@ SlackMessage.post_to('#general') do
48
54
  end
49
55
  ```
50
56
 
51
- ### The Docs
52
-
53
- You'll find much more information about how to use SlackMessage by visiting
54
- [the docs](https://jmmastey.github.io/slack_message).
55
-
56
- #### Opinionated Stances
57
+ ### Opinionated Stances
57
58
 
58
59
  This gem is intended to stay simple. Other Slack gems have lots of config
59
60
  options and abilities, which makes them powerful, but makes them a pain to use.
@@ -61,6 +62,8 @@ options and abilities, which makes them powerful, but makes them a pain to use.
61
62
  Accordingly, SlackMessage is developed with some strong opinions in mind:
62
63
 
63
64
  * SlackMessage has no dependencies. Your lockfile is enough of a mess already.
65
+ * A DSL that focuses on code that is easy to write, read, and maintain. Only
66
+ features that can be implemented with that in mind are included.
64
67
  * The code to build a message should look a lot like the message itself. Code
65
68
  that is simple to read and understand is a priority.
66
69
  * Webhooks are passé. Only Slack Apps are supported now.
@@ -71,28 +74,22 @@ Accordingly, SlackMessage is developed with some strong opinions in mind:
71
74
  to look it up as an email address.
72
75
  * A few little hacks on the block syntax, such as adding a `blank_line` (which
73
76
  doesn't exist in the API), or leading spaces.
74
- * Configuration is kept as simple as possible. But, as much heavy lifting as
75
- possible should occur just once via configuration and not on every call.
77
+ * Configuration is kept simple, with helpers for frequently reused bots.
76
78
 
77
79
  Some behaviors that are still planned but not yet added:
78
80
 
79
81
  * any interactive elements at all: https://api.slack.com/interactivity/handling
80
82
  * multiple recipients: https://api.slack.com/methods/conversations.open
81
- * more interesting return types for your message
82
- * richer text formatting (for instance, `ul` is currently a hack)
83
83
  * more mrkdwn syntax, like quotes or code blocks
84
- * more and better organized testing capability
84
+ * more and better organized testing capability (scheduled messages, editing, deleting)
85
85
  * posting ephemeral messages: https://api.slack.com/methods/chat.postEphemeral
86
- * some Rspec test harness for scheduled messages, editing, deleting (probably going to need a test overhaul)
87
86
 
88
- Contributing
89
- ------------
87
+ ### Contributing
90
88
 
91
89
  Contributions are very welcome. Fork, fix, submit pull. Since simplicity of API is a strong priority, so opening an issue to discuss possible interface changes would be wise.
92
90
 
93
91
  Contribution is expected to conform to the [Contributor Covenant](https://github.com/jmmastey/slack_message/blob/master/CODE_OF_CONDUCT.md).
94
92
 
95
- License
96
- ------------
93
+ ### License
97
94
 
98
95
  This software is released under the [MIT License](https://github.com/jmmastey/slack_message/blob/master/MIT-LICENSE).
@@ -95,18 +95,18 @@ end
95
95
  You will now see warnings detailing all params sent to the API.
96
96
 
97
97
  ```ruby
98
- {
99
- :channel=>"#general",
100
- :username=>"Builds",
101
- :blocks=>[
102
- {:type=>"section", :text=>{
103
- :type=>"mrkdwn",
104
- :text=>"Build Stability is Looking Ruff :dog:"
105
- }}
106
- ],
107
- :text=>"Build Issues",
108
- :post_at=>1639421171,
109
- }
98
+ {
99
+ :channel=>"#general",
100
+ :username=>"Builds",
101
+ :blocks=>[
102
+ {:type=>"section", :text=>{
103
+ :type=>"mrkdwn",
104
+ :text=>"Build Stability is Looking Ruff :dog:"
105
+ }}
106
+ ],
107
+ :text=>"Build Issues",
108
+ :post_at=>1639421171,
109
+ }
110
110
  ```
111
111
 
112
112
  Note this includes data that is not included in `SlackMessage.build`.
@@ -152,11 +152,54 @@ end
152
152
  # :style=>:danger}}]
153
153
  ```
154
154
 
155
- #### Lists and List Items
155
+ #### Ordered and Unordered Lists
156
156
 
157
- - list_item, ul, ol
157
+ The Slack API doesn't have native support for HTML-style ordered and unordered
158
+ lists, but there are convenience methods in SlackMessage to render a close
159
+ approximation.
158
160
 
159
- ### Including Multiple Sections
161
+ ```ruby
162
+ SlackMessage.build do
163
+ section do
164
+ text '*Pet Goodness Tiers*'
165
+
166
+ ol([
167
+ 'tiny pigs',
168
+ 'reptiles',
169
+ 'dogs',
170
+ 'cats',
171
+ ])
172
+ end
173
+
174
+ section do
175
+ text '_voted by_'
176
+ ul(['Joe', 'Emily', 'Sophia', 'Matt'])
177
+ end
178
+ end
179
+ ```
180
+
181
+ Because Slack automatically collapses leading whitespace, indention of lists is
182
+ handled using unicode emspaces. Bullets for unordered lists are also unicode
183
+ characters to avoid being read as markdown.
184
+
185
+ #### List Items (e.g. HTML dt & dd)
186
+
187
+ When trying to represent title / value lists, you can use the "list item" block
188
+ type to pass a set of values. Slack does not allow you to customize how many
189
+ items are shown per line, so you'll just have to work with it.
190
+
191
+ ```ruby
192
+ SlackMessage.build do
193
+ text 'Import results are available!'
194
+
195
+ list_item 'Import Date', Date.today.to_s
196
+ list_item 'Items Imported', 55_000
197
+ list_item 'Errors', 23
198
+ list_item 'Bad Values', errors.map(&:to_s)
199
+ end
200
+ ```
201
+
202
+ #### Including Multiple Sections
160
203
 
161
204
  Adding more sections is trivial. Simply declare each section and it will be
162
205
  separated in the rendered message. This can often occur when looping.
@@ -200,10 +243,10 @@ section. Because of how implicit sections are built, it may look like this works
200
243
  for simple messages. You may have troubles when you start adding more
201
244
  complicated elements to your messages.
202
245
 
203
- ### Images
204
- - image, accessory_image
246
+ #### Images
247
+ TODO: image, accessory_image
205
248
 
206
- ### Footers (Context)
249
+ #### Footers (Context)
207
250
 
208
251
  Slack allows you to add a small additional piece of text to your message, which
209
252
  will be rendered in italics and small text. It can support both links and emoji,
@@ -228,7 +271,7 @@ end
228
271
  Context does not belong to a section, and is per-message, not per-section.
229
272
  Specifying more than one context will simply overwrite previous calls.
230
273
 
231
- ### Bot Customization
274
+ #### Bot Customization
232
275
 
233
276
  By default - and with scheduled messages - Slack will use the name and icon of
234
277
  the Slack app whose API key you configured. As seen before, it's
@@ -253,7 +296,7 @@ The `bot_icon` can be specified as either an emoji (`:example:`), or a URL
253
296
  pointing to an image (`http://mysite.com/shipit.png`). Any other value seems to
254
297
  cause an error.
255
298
 
256
- ### Custom Notification Text
299
+ #### Custom Notification Text
257
300
 
258
301
  For users who have notifications turned on, Slack will provide a small message
259
302
  preview when you send them a message. By default, this preview will take the
data/docs/_config.yml ADDED
@@ -0,0 +1,6 @@
1
+ plugins:
2
+ - jekyll-relative-links
3
+ relative_links:
4
+ enabled: true
5
+ collections: true
6
+ theme: jekyll-theme-midnight
data/docs/index.md CHANGED
@@ -1,7 +1,49 @@
1
- * [Configuration](https://jmmastey.github.io/slack_message/01_configuration)
1
+ * [Getting Started / Configuration](https://jmmastey.github.io/slack_message/01_configuration)
2
2
  * [Posting a Message](https://jmmastey.github.io/slack_message/02_posting_a_message)
3
3
  * [The SlackMessage DSL](https://jmmastey.github.io/slack_message/03_message_dsl)
4
4
  * [Editing Messages](https://jmmastey.github.io/slack_message/04_editing_messages)
5
5
  * [Deleting Messages](https://jmmastey.github.io/slack_message/05_deleting_messages)
6
6
  * [Mentions / Notifying Users](https://jmmastey.github.io/slack_message/06_notifying_users)
7
7
  * [Testing](https://jmmastey.github.io/slack_message/07_testing)
8
+
9
+ SlackMessage is a gem that makes it easy to send messages to Slack from your
10
+ application. _Really_ easy.
11
+
12
+ ```ruby
13
+ SlackMessage.post_to('#general') do
14
+ text "We did it @here! :thumbsup:"
15
+ end
16
+ ```
17
+
18
+ And not just simple messages. You can compose complicated messages quickly in a
19
+ DSL that's focused on usability and maintainability. It can be tough to
20
+ maintain code in other similar gems, but not here.
21
+
22
+ ```ruby
23
+ SlackMessage.post_to('hello@joemastey.com') do
24
+ section do
25
+ text "A job has generated some output for you to review."
26
+ text 'And More' * 10
27
+ link_button "See Results", "https://google.com"
28
+ end
29
+
30
+ section do
31
+ text ":unlock-new: New Data Summary"
32
+
33
+ list_item "Date", "09/05/2021"
34
+ list_item "Total Imported", 45_004
35
+ list_item "Total Errors", 5
36
+ end
37
+
38
+ divider
39
+
40
+ section do
41
+ text "See more here: #{link('result', 'https://google.com')}"
42
+ end
43
+
44
+ context "Kicked off by <hello@joemastey.com> at **9:05am**"
45
+ end
46
+ ```
47
+
48
+ It has no dependencies and minimal configuration needs, so you can get up and
49
+ running quickly.
@@ -10,6 +10,10 @@ module SlackMessage::Api
10
10
  raise ArgumentError, "Tried to find profile by invalid email address '#{email}'"
11
11
  end
12
12
 
13
+ if SlackMessage::Configuration.debugging?
14
+ warn [email, profile].inspect
15
+ end
16
+
13
17
  response = look_up_user_by_email(email, profile)
14
18
 
15
19
  if response.code != "200"
@@ -24,14 +28,7 @@ module SlackMessage::Api
24
28
  raise SlackMessage::ApiError, "Unable to parse JSON response from Slack API\n#{response.body}"
25
29
  end
26
30
 
27
- if payload.include?("error") && payload["error"] == "invalid_auth"
28
- raise SlackMessage::ApiError, "Received an error because your authentication token isn't properly configured."
29
- elsif payload.include?("error") && payload["error"] == "users_not_found"
30
- raise SlackMessage::ApiError, "Couldn't find a user with the email '#{email}'."
31
- elsif payload.include?("error")
32
- raise SlackMessage::ApiError, "Received error response from Slack during user lookup:\n#{response.body}"
33
- end
34
-
31
+ SlackMessage::ErrorHandling.raise_user_lookup_errors(response, target, profile)
35
32
  payload["user"]["id"]
36
33
  end
37
34
 
@@ -69,26 +66,8 @@ module SlackMessage::Api
69
66
  end
70
67
 
71
68
  response = post_message(profile, params)
72
- body = JSON.parse(response.body)
73
- error = body.fetch("error", "")
74
-
75
- # TODO: if a scheduled message w/ a short timer is "time_in_past", warn the user?
76
-
77
- # let's try to be helpful about error messages
78
- if ["token_revoked", "token_expired", "invalid_auth", "not_authed"].include?(error)
79
- raise SlackMessage::ApiError, "Couldn't send slack message because the API key for profile '#{profile[:handle]}' is wrong."
80
- elsif ["no_permission", "ekm_access_denied"].include?(error)
81
- raise SlackMessage::ApiError, "Couldn't send slack message because the API key for profile '#{profile[:handle]}' isn't allowed to post messages."
82
- elsif error == "channel_not_found"
83
- raise SlackMessage::ApiError, "Tried to send Slack message to non-existent channel or user '#{target}'"
84
- elsif error == "invalid_arguments"
85
- raise SlackMessage::ApiError, "Tried to send Slack message with invalid payload."
86
- elsif response.code == "302"
87
- raise SlackMessage::ApiError, "Got 302 response while posting to Slack. Check your API key for profile '#{profile[:handle]}'."
88
- elsif response.code != "200"
89
- raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
90
- end
91
69
 
70
+ SlackMessage::ErrorHandling.raise_post_response_errors(response, params, profile)
92
71
  SlackMessage::Response.new(response, profile[:handle])
93
72
  end
94
73
 
@@ -97,7 +76,7 @@ module SlackMessage::Api
97
76
  channel: message.channel,
98
77
  ts: message.timestamp,
99
78
  blocks: payload.render,
100
- text: payload.custom_notification # TODO: ???
79
+ text: payload.custom_notification
101
80
  }
102
81
 
103
82
  if params[:blocks].length == 0
@@ -112,8 +91,7 @@ module SlackMessage::Api
112
91
  body = JSON.parse(response.body)
113
92
  error = body.fetch("error", "")
114
93
 
115
- # TODO: error messaging
116
-
94
+ SlackMessage::ErrorHandling.raise_post_response_errors(response, message, profile)
117
95
  SlackMessage::Response.new(response, profile[:handle])
118
96
  end
119
97
 
@@ -130,10 +108,13 @@ module SlackMessage::Api
130
108
  }
131
109
  end
132
110
 
133
- response = delete_message(profile, params)
111
+ if SlackMessage::Configuration.debugging?
112
+ warn params.inspect
113
+ end
134
114
 
135
- # TODO error handling (incl for already scheduled-and-sent messages)
115
+ response = delete_message(profile, params)
136
116
 
117
+ SlackMessage::ErrorHandling.raise_delete_response_errors(response, message, profile)
137
118
  response
138
119
  end
139
120
 
@@ -0,0 +1,124 @@
1
+ class SlackMessage::ErrorHandling
2
+ PERMISSIONS_ERRORS = ["token_revoked", "token_expired", "invalid_auth", "not_authed",
3
+ "team_access_not_granted", "no_permission", "missing_scope",
4
+ "not_allowed_token_type", "ekm_access_denied"]
5
+
6
+ def self.raise_post_response_errors(response, params, profile)
7
+ body = JSON.parse(response.body)
8
+ error = body.fetch("error", "")
9
+
10
+ if ["invalid_blocks", "invalid_blocks_format"].include?(error)
11
+ raise SlackMessage::ApiError, "Couldn't send Slack message because the serialized message had an invalid format"
12
+ elsif error == "channel_not_found"
13
+ raise SlackMessage::ApiError, "Tried to send Slack message to non-existent channel or user '#{params[:channel]}'"
14
+
15
+ # scheduling messages
16
+ elsif error == "invalid_time"
17
+ raise SlackMessage::ApiError, "Couldn't schedule Slack message because you requested an invalid time '#{params[:post_at]}'"
18
+ elsif error == "time_in_past"
19
+ raise SlackMessage::ApiError, "Couldn't schedule Slack message because you requested a time in the past (or too close to now) '#{params[:post_at]}'"
20
+ elsif error == "time_too_far"
21
+ raise SlackMessage::ApiError, "Couldn't schedule Slack message because you requested a time more than 120 days in the future '#{params[:post_at]}'"
22
+
23
+
24
+ elsif PERMISSIONS_ERRORS.include?(error)
25
+ raise SlackMessage::ApiError, "Couldn't send Slack message because the API key for profile '#{profile[:handle]}' is wrong, or the app has insufficient permissions (#{error})"
26
+ elsif error == "message_too_long"
27
+ raise SlackMessage::ApiError, "Tried to send Slack message, but the message was too long"
28
+ elsif error == "invalid_arguments"
29
+ raise SlackMessage::ApiError, "Tried to send Slack message with invalid payload"
30
+ elsif ["rate_limited", "ratelimited"].include?(error)
31
+ raise SlackMessage::ApiError, "Couldn't send Slack message because you've reached your rate limit"
32
+ elsif response.code == "302"
33
+ raise SlackMessage::ApiError, "Got 302 response while posting to Slack. Check your API key for profile '#{profile[:handle]}'"
34
+ elsif response.code != "200"
35
+ raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
36
+ elsif !(error.nil? || error == "")
37
+ raise SlackMessage::ApiError, "Received error response from Slack during message posting:\n#{response.body}"
38
+ end
39
+ end
40
+
41
+ def self.raise_update_response_errors(response, message, profile)
42
+ body = JSON.parse(response.body)
43
+ error = body.fetch("error", "")
44
+
45
+ if ["invalid_blocks", "invalid_blocks_format"].include?(error)
46
+ raise SlackMessage::ApiError, "Couldn't update Slack message because the serialized message had an invalid format"
47
+ elsif error == "channel_not_found"
48
+ raise SlackMessage::ApiError, "Tried to update Slack message to non-existent channel or user '#{message.channel}'"
49
+
50
+ elsif error == "message_not_found"
51
+ raise SlackMessage::ApiError, "Tried to update Slack message, but the message wasn't found (timestamp '#{message.timestamp}' for channel '#{message.channel}'"
52
+ elsif error == "cant_update_message"
53
+ raise SlackMessage::ApiError, "Couldn't update message because the message type isn't able to be updated, or #{profile[:handle]} isn't allowed to update it"
54
+ elsif error == "edit_window_closed"
55
+ raise SlackMessage::ApiError, "Couldn't update message because it's too old"
56
+
57
+
58
+ elsif PERMISSIONS_ERRORS.include?(error)
59
+ raise SlackMessage::ApiError, "Couldn't update Slack message because the API key for profile '#{profile[:handle]}' is wrong, or the app has insufficient permissions (#{error})"
60
+ elsif error == "message_too_long"
61
+ raise SlackMessage::ApiError, "Tried to update Slack message, but the message was too long"
62
+ elsif error == "invalid_arguments"
63
+ raise SlackMessage::ApiError, "Tried to update Slack message with invalid payload"
64
+ elsif ["rate_limited", "ratelimited"].include?(error)
65
+ raise SlackMessage::ApiError, "Couldn't update Slack message because you've reached your rate limit"
66
+ elsif response.code == "302"
67
+ raise SlackMessage::ApiError, "Got 302 response while updating a message. Check your API key for profile '#{profile[:handle]}'"
68
+ elsif response.code != "200"
69
+ raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
70
+ elsif !(error.nil? || error == "")
71
+ raise SlackMessage::ApiError, "Received error response from Slack during message update:\n#{response.body}"
72
+ end
73
+ end
74
+
75
+ def self.raise_delete_response_errors(response, message, profile)
76
+ body = JSON.parse(response.body)
77
+ error = body.fetch("error", "")
78
+
79
+ if error == "channel_not_found"
80
+ raise SlackMessage::ApiError, "Tried to delete Slack message in non-existent channel '#{message.channel}'"
81
+
82
+ elsif error == "invalid_scheduled_message_id"
83
+ raise SlackMessage::ApiError, "Can't delete message because the ID was invalid, or the message has already posted (#{message.scheduled_message_id})"
84
+ elsif error == "message_not_found"
85
+ raise SlackMessage::ApiError, "Tried to delete Slack message, but the message wasn't found (timestamp '#{message.timestamp}' for channel '#{message.channel}')"
86
+ elsif error == "cant_delete_message"
87
+ raise SlackMessage::ApiError, "Can't delete message because '#{profile[:handle]}' doesn't have permission to"
88
+ elsif error == "compliance_exports_prevent_deletion"
89
+ raise SlackMessage::ApiError, "Can't delete message because team compliance settings prevent it"
90
+
91
+
92
+ elsif PERMISSIONS_ERRORS.include?(error)
93
+ raise SlackMessage::ApiError, "Couldn't delete Slack message because the API key for profile '#{profile[:handle]}' is wrong, or the app has insufficient permissions (#{error})"
94
+ elsif ["rate_limited", "ratelimited"].include?(error)
95
+ raise SlackMessage::ApiError, "Couldn't delete Slack message because you've reached your rate limit"
96
+ elsif response.code == "302"
97
+ raise SlackMessage::ApiError, "Got 302 response while deleting a message. Check your API key for profile '#{profile[:handle]}'"
98
+ elsif response.code != "200"
99
+ raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
100
+ elsif !(error.nil? || error == "")
101
+ raise SlackMessage::ApiError, "Received error response from Slack during message delete:\n#{response.body}"
102
+ end
103
+ end
104
+
105
+ def self.raise_user_lookup_response_errors(payload)
106
+ error = payload["error"]
107
+
108
+ if error == "users_not_found"
109
+ raise SlackMessage::ApiError, "Couldn't find a user with the email '#{email}'"
110
+
111
+
112
+ elsif PERMISSIONS_ERRORS.include?(error)
113
+ raise SlackMessage::ApiError, "Couldn't look up users because the API key for profile '#{profile[:handle]}' is wrong, or the app has insufficient permissions (#{error})"
114
+ elsif error
115
+ raise SlackMessage::ApiError, "Received error response from Slack during user lookup:\n#{response.body}"
116
+ elsif response.code == "302"
117
+ raise SlackMessage::ApiError, "Got 302 response during user lookup. Check your API key for profile '#{profile[:handle]}'"
118
+ elsif response.code != "200"
119
+ raise SlackMessage::ApiError, "Got an error back from the Slack API (HTTP #{response.code}):\n#{response.body}"
120
+ elsif !(error.nil? || error == "")
121
+ raise SlackMessage::ApiError, "Received error response from Slack during user lookup:\n#{response.body}"
122
+ end
123
+ end
124
+ end
@@ -14,12 +14,15 @@ require 'rspec/mocks'
14
14
  # it can be cleaned up properly.
15
15
  #
16
16
 
17
- # TODO: testing for scheduled messages, editing and deleting
17
+ # TODO: test helpers for scheduled messages, editing and deleting, and
18
+ # notification text. And realistically, overhaul all this.
18
19
 
19
20
  module SlackMessage::RSpec
20
21
  extend RSpec::Matchers::DSL
21
22
 
22
23
  @@listeners = []
24
+ @@custom_response = {}
25
+ @@response_code = '200'
23
26
 
24
27
  def self.register_expectation_listener(expectation_instance)
25
28
  @@listeners << expectation_instance
@@ -29,6 +32,11 @@ module SlackMessage::RSpec
29
32
  @@listeners.delete(expectation_instance)
30
33
  end
31
34
 
35
+ def self.reset_custom_responses
36
+ @@custom_response = {}
37
+ @@response_code = '200'
38
+ end
39
+
32
40
  FauxResponse = Struct.new(:code, :body)
33
41
 
34
42
  def self.included(_)
@@ -38,22 +46,24 @@ module SlackMessage::RSpec
38
46
  listener.record_call(params.merge(profile: profile))
39
47
  end
40
48
 
41
- response = {"ok"=>true,
42
- "channel"=>"D12345678",
43
- "ts"=>"1635863996.002300",
44
- "message"=>
45
- {"type"=>"message", "subtype"=>"bot_message",
46
- "text"=>"foo",
47
- "ts"=>"1635863996.002300",
48
- "username"=>"SlackMessage",
49
- "icons"=>{"emoji"=>":successkid:"},
50
- "bot_id"=>"B1234567890",
51
- "blocks"=>
52
- [{"type"=>"section",
53
- "block_id"=>"hAh7",
54
- "text"=>{"type"=>"mrkdwn", "text"=>"foo", "verbatim"=>false}}]}}
55
-
56
- return FauxResponse.new('200', response.to_json)
49
+ response = {
50
+ "ok" => true,
51
+ "channel" => "C12345678",
52
+ "ts" => "1635863996.002300",
53
+ "message" => { "type"=>"message", "subtype"=>"bot_message",
54
+ "text"=>"foo",
55
+ "ts"=>"1635863996.002300",
56
+ "username"=>"SlackMessage",
57
+ "icons"=>{"emoji"=>":successkid:"},
58
+ "bot_id"=>"B1234567890",
59
+ "blocks"=> [{"type"=>"section",
60
+ "block_id"=>"hAh7",
61
+ "text"=>{"type"=>"mrkdwn", "text"=>"foo", "verbatim"=>false}}
62
+ ]
63
+ }
64
+ }.merge(@@custom_response).to_json
65
+
66
+ return FauxResponse.new(@@response_code, response)
57
67
  end
58
68
 
59
69
  SlackMessage::Api.undef_method(:look_up_user_by_email)
@@ -63,6 +73,18 @@ module SlackMessage::RSpec
63
73
  end
64
74
  end
65
75
 
76
+ def self.respond_with(response = {}, code: '200')
77
+ raise ArgumentError, "custom response must be a hash" unless response.is_a? Hash
78
+
79
+ @@custom_response = response
80
+ @@response_code = code
81
+ end
82
+
83
+ def self.reset_mock_response
84
+ @@custom_response = {}
85
+ @@response_code = '200'
86
+ end
87
+
66
88
  # w/ channel
67
89
  matcher :post_slack_message_to do |expected|
68
90
  match do |actual|
data/lib/slack_message.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  module SlackMessage
2
2
  require 'slack_message/response'
3
3
  require 'slack_message/dsl'
4
+ require 'slack_message/error_handling'
4
5
  require 'slack_message/api'
5
6
  require 'slack_message/configuration'
6
7
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'slack_message'
3
- gem.version = "3.0.0"
3
+ gem.version = "3.0.1"
4
4
  gem.summary = "A nice DSL for composing rich messages in Slack"
5
5
  gem.authors = ["Joe Mastey"]
6
6
  gem.email = 'hello@joemastey.com'
@@ -111,10 +111,6 @@ RSpec.describe SlackMessage do
111
111
  }.to post_slack_message_with_icon_matching(/thisperson/)
112
112
  end
113
113
 
114
- it "lets you assert notification text" do
115
- # TODO :|
116
- end
117
-
118
114
  it "can assert more generally too tbh" do
119
115
  expect {
120
116
  SlackMessage.post_to('#general') { text "foo" }
@@ -123,8 +119,6 @@ RSpec.describe SlackMessage do
123
119
  end
124
120
 
125
121
  describe "API convenience" do
126
- let(:profile) { SlackMessage::Configuration.profile(:default) }
127
-
128
122
  before do
129
123
  SlackMessage.configure do |config|
130
124
  config.clear_profiles!
@@ -158,5 +152,57 @@ RSpec.describe SlackMessage do
158
152
  end
159
153
  end
160
154
 
161
- # tests for actual sending methods? what would actually be useful?
155
+ describe "error handling" do
156
+ before do
157
+ SlackMessage.configure do |config|
158
+ config.clear_profiles!
159
+ config.add_profile(name: 'default profile', api_token: 'abc123')
160
+ config.add_profile(:schmoebot, name: 'Schmoe', api_token: 'abc123', icon: ':schmoebot:', default_channel: '#schmoes')
161
+ end
162
+ end
163
+
164
+ after do
165
+ SlackMessage::RSpec.reset_mock_response
166
+ end
167
+
168
+ it "raises nice error messages when API methods return errors" do
169
+ SlackMessage::RSpec.respond_with('error' => 'nuffin')
170
+
171
+ expect {
172
+ SlackMessage.post_to('#general') { text 'nuh uh' }
173
+ }.to raise_error(SlackMessage::ApiError)
174
+
175
+ expect {
176
+ SlackMessage.post_as(:schmoebot) { text 'nuh uh' }
177
+ }.to raise_error(SlackMessage::ApiError)
178
+ end
179
+
180
+ it "raises for redirects" do
181
+ SlackMessage::RSpec.respond_with(code: '302')
182
+
183
+ expect {
184
+ SlackMessage.post_to('#general') { text 'nuh uh' }
185
+ }.to raise_error(SlackMessage::ApiError)
186
+ end
187
+
188
+ it "raises errors w/ updates too" do
189
+ message = SlackMessage.post_to('#general') { text 'nuh uh' }
190
+
191
+ SlackMessage::RSpec.respond_with('error' => 'bad choice')
192
+
193
+ expect {
194
+ SlackMessage.update(message) { text 'nuh uh' }
195
+ }.to raise_error(SlackMessage::ApiError)
196
+ end
197
+
198
+ it "even raises errors during deletes" do
199
+ message = SlackMessage.post_to('#general') { text 'nuh uh' }
200
+
201
+ SlackMessage::RSpec.respond_with('error' => 'bad choice')
202
+
203
+ expect {
204
+ SlackMessage.delete(message) { text 'nuh uh' }
205
+ }.to raise_error(SlackMessage::ApiError)
206
+ end
207
+ end
162
208
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack_message
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Mastey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-20 00:00:00.000000000 Z
11
+ date: 2021-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -73,11 +73,13 @@ files:
73
73
  - docs/05_deleting_messages.md
74
74
  - docs/06_notifying_users.md
75
75
  - docs/07_testing.md
76
+ - docs/_config.yml
76
77
  - docs/index.md
77
78
  - lib/slack_message.rb
78
79
  - lib/slack_message/api.rb
79
80
  - lib/slack_message/configuration.rb
80
81
  - lib/slack_message/dsl.rb
82
+ - lib/slack_message/error_handling.rb
81
83
  - lib/slack_message/response.rb
82
84
  - lib/slack_message/rspec.rb
83
85
  - slack_message.gemspec