slack-notifier 1.5.1 → 2.4.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 +5 -5
- data/lib/slack-notifier/config.rb +43 -0
- data/lib/slack-notifier/payload_middleware/at.rb +36 -0
- data/lib/slack-notifier/payload_middleware/base.rb +34 -0
- data/lib/slack-notifier/payload_middleware/channels.rb +21 -0
- data/lib/slack-notifier/payload_middleware/format_attachments.rb +44 -0
- data/lib/slack-notifier/payload_middleware/format_message.rb +20 -0
- data/lib/slack-notifier/payload_middleware/stack.rb +50 -0
- data/lib/slack-notifier/payload_middleware.rb +24 -0
- data/lib/slack-notifier/util/escape.rb +16 -0
- data/lib/slack-notifier/util/http_client.rb +64 -0
- data/lib/slack-notifier/util/link_formatter.rb +80 -0
- data/lib/slack-notifier/version.rb +3 -1
- data/lib/slack-notifier.rb +38 -60
- data/spec/end_to_end_spec.rb +95 -0
- data/spec/integration/ping_integration_test.rb +14 -5
- data/spec/lib/slack-notifier/config_spec.rb +71 -0
- data/spec/lib/slack-notifier/payload_middleware/at_spec.rb +25 -0
- data/spec/lib/slack-notifier/payload_middleware/base_spec.rb +76 -0
- data/spec/lib/slack-notifier/payload_middleware/channels_spec.rb +20 -0
- data/spec/lib/slack-notifier/payload_middleware/format_attachments_spec.rb +48 -0
- data/spec/lib/slack-notifier/payload_middleware/format_message_spec.rb +27 -0
- data/spec/lib/slack-notifier/payload_middleware/stack_spec.rb +119 -0
- data/spec/lib/slack-notifier/payload_middleware_spec.rb +33 -0
- data/spec/lib/slack-notifier/util/http_client_spec.rb +55 -0
- data/spec/lib/slack-notifier/util/link_formatter_spec.rb +163 -0
- data/spec/lib/slack-notifier_spec.rb +63 -128
- data/spec/spec_helper.rb +20 -5
- metadata +39 -13
- data/lib/slack-notifier/default_http_client.rb +0 -51
- data/lib/slack-notifier/link_formatter.rb +0 -62
- data/spec/lib/slack-notifier/default_http_client_spec.rb +0 -37
- data/spec/lib/slack-notifier/link_formatter_spec.rb +0 -78
@@ -1,7 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# encoding: utf-8
|
2
|
-
require_relative '../../lib/slack-notifier'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
require_relative "../../lib/slack-notifier"
|
5
|
+
|
6
|
+
ruby = if defined?(JRUBY_VERSION)
|
7
|
+
"jruby #{JRUBY_VERSION}"
|
8
|
+
else
|
9
|
+
"ruby #{RUBY_VERSION}"
|
10
|
+
end
|
11
|
+
puts "testing with #{ruby}"
|
12
|
+
|
13
|
+
notifier = Slack::Notifier.new ENV["SLACK_WEBHOOK_URL"], username: "notifier"
|
14
|
+
notifier.ping "hello", channel: ["#general", "#random"]
|
15
|
+
notifier.ping "hello/こんにちは from notifier test script on #{ruby}\225"
|
16
|
+
notifier.ping attachments: [{ color: "#1BF5AF", fallback: "fallback", text: "attachment" }]
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Slack::Notifier::Config do
|
4
|
+
describe "#http_client" do
|
5
|
+
it "is Util::HTTPClient if not set" do
|
6
|
+
subject = described_class.new
|
7
|
+
expect(subject.http_client).to eq Slack::Notifier::Util::HTTPClient
|
8
|
+
end
|
9
|
+
|
10
|
+
it "sets a new client class if given one" do
|
11
|
+
new_client = class_double("Slack::Notifier::Util::HTTPClient", post: nil)
|
12
|
+
subject = described_class.new
|
13
|
+
subject.http_client new_client
|
14
|
+
expect(subject.http_client).to eq new_client
|
15
|
+
end
|
16
|
+
|
17
|
+
it "raises an ArgumentError if given class does not respond to ::post" do
|
18
|
+
subject = described_class.new
|
19
|
+
expect do
|
20
|
+
subject.http_client :nope
|
21
|
+
end.to raise_error ArgumentError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#defaults" do
|
26
|
+
it "is an empty hash by default" do
|
27
|
+
subject = described_class.new
|
28
|
+
expect(subject.defaults).to eq({})
|
29
|
+
end
|
30
|
+
|
31
|
+
it "sets a hash to default if given" do
|
32
|
+
subject = described_class.new
|
33
|
+
subject.defaults foo: :bar
|
34
|
+
expect(subject.defaults).to eq foo: :bar
|
35
|
+
end
|
36
|
+
|
37
|
+
it "raises ArgumentError if not given a hash" do
|
38
|
+
subject = described_class.new
|
39
|
+
expect do
|
40
|
+
subject.defaults :nope
|
41
|
+
end.to raise_error ArgumentError
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#middleware" do
|
46
|
+
it "is [:format_message, :format_attachments, :at] if not set" do
|
47
|
+
subject = described_class.new
|
48
|
+
|
49
|
+
expect(subject.middleware).to eq %i[format_message format_attachments at channels]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "takes an array or a splat of args" do
|
53
|
+
subject = described_class.new
|
54
|
+
|
55
|
+
subject.middleware :layer, :two
|
56
|
+
expect(subject.middleware).to eq %i[layer two]
|
57
|
+
|
58
|
+
subject.middleware %i[one layer]
|
59
|
+
expect(subject.middleware).to eq %i[one layer]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "allows passing options to middleware stack" do
|
63
|
+
subject = described_class.new
|
64
|
+
subject.middleware one: { opts: :for_one },
|
65
|
+
two: { opts: :for_two }
|
66
|
+
|
67
|
+
expect(subject.middleware).to eq one: { opts: :for_one },
|
68
|
+
two: { opts: :for_two }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Slack::Notifier::PayloadMiddleware::At do
|
4
|
+
it "can handle array at" do
|
5
|
+
subject = described_class.new(:notifier)
|
6
|
+
payload = { text: "hello", at: %i[john ken here] }
|
7
|
+
|
8
|
+
expect(subject.call(payload)).to eq text: "<@john> <@ken> <!here> hello"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can handle single at option" do
|
12
|
+
subject = described_class.new(:notifier)
|
13
|
+
payload = { text: "hello", at: :alice }
|
14
|
+
|
15
|
+
expect(subject.call(payload)).to eq text: "<@alice> hello"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "generates :text in payload if given :at & no :text" do
|
19
|
+
subject = described_class.new(:notifier)
|
20
|
+
input_payload = { at: [:here], attachments: [{ text: "hello" }] }
|
21
|
+
output_payload = { text: "<!here> ", attachments: [{ text: "hello" }] }
|
22
|
+
|
23
|
+
expect(subject.call(input_payload)).to eq output_payload
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Slack::Notifier::PayloadMiddleware::Base do
|
4
|
+
before(:each) do
|
5
|
+
@registry_backup = Slack::Notifier::PayloadMiddleware.registry.dup
|
6
|
+
Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
|
7
|
+
end
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
# cleanup middleware registry
|
11
|
+
Slack::Notifier::PayloadMiddleware.registry
|
12
|
+
Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
|
13
|
+
|
14
|
+
# cleanup object constants
|
15
|
+
Object.send(:remove_const, :Subject) if Object.constants.include?(:Subject)
|
16
|
+
Slack::Notifier::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "::middleware_name" do
|
20
|
+
it "registers class w/ given name" do
|
21
|
+
class Subject < Slack::Notifier::PayloadMiddleware::Base
|
22
|
+
end
|
23
|
+
|
24
|
+
expect(Slack::Notifier::PayloadMiddleware)
|
25
|
+
.to receive(:register).with(Subject, :subject)
|
26
|
+
|
27
|
+
class Subject
|
28
|
+
middleware_name :subject
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "uses symbolized name to register" do
|
33
|
+
class Subject < Slack::Notifier::PayloadMiddleware::Base
|
34
|
+
end
|
35
|
+
|
36
|
+
expect(Slack::Notifier::PayloadMiddleware)
|
37
|
+
.to receive(:register).with(Subject, :subject)
|
38
|
+
|
39
|
+
class Subject
|
40
|
+
middleware_name "subject"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "::options" do
|
46
|
+
it "allows setting default options for a middleware" do
|
47
|
+
class Subject < Slack::Notifier::PayloadMiddleware::Base
|
48
|
+
options foo: :bar
|
49
|
+
end
|
50
|
+
|
51
|
+
subject = Subject.new(:notifier)
|
52
|
+
expect(subject.options).to eq foo: :bar
|
53
|
+
|
54
|
+
subject = Subject.new(:notifier, foo: :baz)
|
55
|
+
expect(subject.options).to eq foo: :baz
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#initialize" do
|
60
|
+
it "sets given notifier as notifier" do
|
61
|
+
expect(described_class.new(:notifier).notifier).to eq :notifier
|
62
|
+
end
|
63
|
+
|
64
|
+
it "sets given options as opts" do
|
65
|
+
expect(described_class.new(:notifier, opts: :options).options).to eq opts: :options
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#call" do
|
70
|
+
it "raises NoMethodError (expects subclass to define)" do
|
71
|
+
expect do
|
72
|
+
described_class.new(:notifier).call
|
73
|
+
end.to raise_exception NoMethodError
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Slack::Notifier::PayloadMiddleware::Channels do
|
4
|
+
it "leaves string channels alone" do
|
5
|
+
subject = described_class.new(:notifier)
|
6
|
+
payload = { text: "hello", channel: "hodor" }
|
7
|
+
|
8
|
+
expect(subject.call(payload)).to eq text: "hello", channel: "hodor"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "splits payload into multiple if given an array of channels" do
|
12
|
+
subject = described_class.new(:notifier)
|
13
|
+
payload = { text: "hello", channel: %w[foo hodor] }
|
14
|
+
|
15
|
+
expect(subject.call(payload)).to eq [
|
16
|
+
{ text: "hello", channel: "foo" },
|
17
|
+
{ text: "hello", channel: "hodor" }
|
18
|
+
]
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Slack::Notifier::PayloadMiddleware::FormatAttachments do
|
4
|
+
it "passes the text of attachments through linkformatter with options[:formats]" do
|
5
|
+
subject = described_class.new(:notifier, formats: [:html])
|
6
|
+
expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
|
7
|
+
.with("hello", formats: [:html])
|
8
|
+
subject.call(attachments: [{ text: "hello" }])
|
9
|
+
end
|
10
|
+
|
11
|
+
it "searches through string or symbol keys" do
|
12
|
+
subject = described_class.new(:notifier)
|
13
|
+
expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
|
14
|
+
.with("hello", formats: %i[html markdown])
|
15
|
+
subject.call("attachments" => [{ "text" => "hello" }])
|
16
|
+
|
17
|
+
subject = described_class.new(:notifier)
|
18
|
+
expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
|
19
|
+
.with("hello", formats: %i[html markdown])
|
20
|
+
subject.call(attachments: [{ text: "hello" }])
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can handle a single attachment" do
|
24
|
+
subject = described_class.new(:notifier)
|
25
|
+
expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
|
26
|
+
.with("hello", formats: %i[html markdown])
|
27
|
+
subject.call(attachments: { text: "hello" })
|
28
|
+
end
|
29
|
+
|
30
|
+
it "wraps attachment into array if given as a single hash" do
|
31
|
+
params = {
|
32
|
+
attachments: { text: "hello" }
|
33
|
+
}
|
34
|
+
payload = {
|
35
|
+
attachments: [{ text: "hello" }]
|
36
|
+
}
|
37
|
+
subject = described_class.new(:notifier)
|
38
|
+
|
39
|
+
expect(subject.call(params)).to eq payload
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns the payload unmodified if not :attachments key" do
|
43
|
+
payload = { foo: :bar }
|
44
|
+
subject = described_class.new(:notifier)
|
45
|
+
|
46
|
+
expect(subject.call(payload)).to eq payload
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Slack::Notifier::PayloadMiddleware::FormatMessage do
|
4
|
+
it "passes the text through linkformatter with options[:formats]" do
|
5
|
+
subject = described_class.new(:notifier, formats: [:html])
|
6
|
+
expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
|
7
|
+
.with("hello", formats: [:html])
|
8
|
+
subject.call(text: "hello")
|
9
|
+
|
10
|
+
subject = described_class.new(:notifier)
|
11
|
+
expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
|
12
|
+
.with("hello", formats: %i[html markdown])
|
13
|
+
subject.call(text: "hello")
|
14
|
+
|
15
|
+
subject = described_class.new(:notifier, formats: [:markdown])
|
16
|
+
expect(Slack::Notifier::Util::LinkFormatter).to receive(:format)
|
17
|
+
.with("hello", formats: [:markdown])
|
18
|
+
subject.call(text: "hello")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns the payload unmodified if not :text key" do
|
22
|
+
payload = { foo: :bar }
|
23
|
+
subject = described_class.new(:notifier)
|
24
|
+
|
25
|
+
expect(subject.call(payload)).to eq payload
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Slack::Notifier::PayloadMiddleware::Stack do
|
4
|
+
let(:return_one) do
|
5
|
+
double(call: 1)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:return_one_twice) do
|
9
|
+
double(call: [1, 1])
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:return_two) do
|
13
|
+
double(call: 2)
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:return_three) do
|
17
|
+
double(call: 3)
|
18
|
+
end
|
19
|
+
|
20
|
+
before(:each) do
|
21
|
+
# setup our middleware in the registry
|
22
|
+
@registry_backup = Slack::Notifier::PayloadMiddleware.registry.dup
|
23
|
+
Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
|
24
|
+
|
25
|
+
Slack::Notifier::PayloadMiddleware.register return_one, :return_one
|
26
|
+
Slack::Notifier::PayloadMiddleware.register return_one_twice, :return_one_twice
|
27
|
+
Slack::Notifier::PayloadMiddleware.register return_two, :return_two
|
28
|
+
Slack::Notifier::PayloadMiddleware.register return_three, :return_three
|
29
|
+
end
|
30
|
+
|
31
|
+
after(:each) do
|
32
|
+
# cleanup middleware registry
|
33
|
+
Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
|
34
|
+
Slack::Notifier::PayloadMiddleware.send(:instance_variable_set, :@registry, @registry_backup)
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "::initialize" do
|
38
|
+
it "sets notifier to given notifier" do
|
39
|
+
expect(described_class.new(:notifier).notifier).to eq :notifier
|
40
|
+
end
|
41
|
+
|
42
|
+
it "has empty stack" do
|
43
|
+
expect(described_class.new(:notifier).stack).to match_array []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#set" do
|
48
|
+
it "initializes each middleware w/ the notifier instance" do
|
49
|
+
expect(return_one).to receive(:new).with(:notifier)
|
50
|
+
expect(return_two).to receive(:new).with(:notifier)
|
51
|
+
|
52
|
+
described_class.new(:notifier).set(:return_one, :return_two)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "creates the stack in an array" do
|
56
|
+
allow(return_one).to receive(:new).and_return(return_one)
|
57
|
+
allow(return_two).to receive(:new).and_return(return_two)
|
58
|
+
|
59
|
+
subject = described_class.new(:notifier)
|
60
|
+
subject.set(:return_one, :return_two)
|
61
|
+
|
62
|
+
expect(subject.stack).to be_a Array
|
63
|
+
expect(subject.stack.first.call).to eq 1
|
64
|
+
expect(subject.stack.last.call).to eq 2
|
65
|
+
end
|
66
|
+
|
67
|
+
it "creates a stack from hashes passing them as opts" do
|
68
|
+
expect(return_one).to receive(:new).with(:notifier, opts: :for_one)
|
69
|
+
expect(return_two).to receive(:new).with(:notifier, opts: :for_two)
|
70
|
+
|
71
|
+
subject = described_class.new(:notifier)
|
72
|
+
subject.set return_one: { opts: :for_one },
|
73
|
+
return_two: { opts: :for_two }
|
74
|
+
end
|
75
|
+
|
76
|
+
it "raises if a middleware is missing" do
|
77
|
+
expect do
|
78
|
+
described_class.new(:notifier).set(:missing)
|
79
|
+
end.to raise_exception KeyError
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#call" do
|
84
|
+
it "calls the middleware in order, passing return of each to the next" do
|
85
|
+
allow(return_one).to receive(:new).and_return(return_one)
|
86
|
+
allow(return_two).to receive(:new).and_return(return_two)
|
87
|
+
allow(return_three).to receive(:new).and_return(return_three)
|
88
|
+
|
89
|
+
subject = described_class.new(:notifier)
|
90
|
+
subject.set(:return_one, :return_three, :return_two)
|
91
|
+
|
92
|
+
expect(return_one).to receive(:call).with(5)
|
93
|
+
expect(return_three).to receive(:call).with(1)
|
94
|
+
expect(return_two).to receive(:call).with(3)
|
95
|
+
|
96
|
+
expect(subject.call(5)).to eq [2]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "allows any middleware to return an array but other's don't need special behavior" do
|
100
|
+
allow(return_one_twice).to receive(:new).and_return(return_one_twice)
|
101
|
+
allow(return_two).to receive(:new).and_return(return_two)
|
102
|
+
|
103
|
+
subject = described_class.new(:notifier)
|
104
|
+
subject.set(:return_one_twice, :return_two)
|
105
|
+
|
106
|
+
expect(subject.call(5)).to eq [2, 2]
|
107
|
+
end
|
108
|
+
|
109
|
+
it "handles multiple middleware splitting payload" do
|
110
|
+
allow(return_one_twice).to receive(:new).and_return(return_one_twice)
|
111
|
+
allow(return_two).to receive(:new).and_return(return_two)
|
112
|
+
|
113
|
+
subject = described_class.new(:notifier)
|
114
|
+
subject.set(:return_one_twice, :return_one_twice, :return_two)
|
115
|
+
|
116
|
+
expect(subject.call(5)).to eq [2, 2, 2, 2]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Slack::Notifier::PayloadMiddleware do
|
4
|
+
before(:each) do
|
5
|
+
@registry_backup = described_class.registry.dup
|
6
|
+
Slack::Notifier::PayloadMiddleware.send(:remove_instance_variable, :@registry)
|
7
|
+
end
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
described_class.send(:remove_instance_variable, :@registry)
|
11
|
+
described_class.send(:instance_variable_set, :@registry, @registry_backup)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "::registry" do
|
15
|
+
it "returns a hash if nothing set" do
|
16
|
+
expect(described_class.registry).to eq({})
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns memoized version if already set" do
|
20
|
+
described_class.instance_variable_set(:@registry, "hodor")
|
21
|
+
expect(described_class.registry).to eq "hodor"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "::register" do
|
26
|
+
it "adds given class to key in registry" do
|
27
|
+
MyClass = Struct.new(:myclass)
|
28
|
+
described_class.register MyClass, :my_class
|
29
|
+
|
30
|
+
expect(described_class.registry[:my_class]).to eq MyClass
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Slack::Notifier::Util::HTTPClient do
|
4
|
+
describe "::post" do
|
5
|
+
it "initializes Util::HTTPClient with the given uri and params then calls" do
|
6
|
+
http_post_double = instance_double("Slack::Notifier::Util::HTTPClient")
|
7
|
+
|
8
|
+
expect(described_class)
|
9
|
+
.to receive(:new).with("uri", "params")
|
10
|
+
.and_return(http_post_double)
|
11
|
+
expect(http_post_double).to receive(:call)
|
12
|
+
|
13
|
+
described_class.post "uri", "params"
|
14
|
+
end
|
15
|
+
|
16
|
+
# http_post is really tested in the integration spec,
|
17
|
+
# where the internals are run through
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#initialize" do
|
21
|
+
it "allows setting of options for Net::HTTP" do
|
22
|
+
net_http_double = instance_double("Net::HTTP")
|
23
|
+
http_client = described_class.new URI.parse("http://example.com"),
|
24
|
+
http_options: { open_timeout: 5 }
|
25
|
+
|
26
|
+
allow(Net::HTTP).to receive(:new).and_return(net_http_double)
|
27
|
+
allow(net_http_double).to receive(:use_ssl=)
|
28
|
+
allow(net_http_double).to receive(:request).with(anything) do
|
29
|
+
Net::HTTPOK.new("GET", "200", "OK")
|
30
|
+
end
|
31
|
+
|
32
|
+
expect(net_http_double).to receive(:open_timeout=).with(5)
|
33
|
+
|
34
|
+
http_client.call
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#call" do
|
39
|
+
it "raises an error when the response is unsuccessful" do
|
40
|
+
net_http_double = instance_double("Net::HTTP")
|
41
|
+
http_client = described_class.new URI.parse("http://example.com"), {}
|
42
|
+
bad_request = Net::HTTPBadRequest.new("GET", "400", "Bad Request")
|
43
|
+
|
44
|
+
allow(bad_request).to receive(:body).and_return("something_bad")
|
45
|
+
allow(Net::HTTP).to receive(:new).and_return(net_http_double)
|
46
|
+
allow(net_http_double).to receive(:use_ssl=)
|
47
|
+
allow(net_http_double).to receive(:request).with(anything) do
|
48
|
+
bad_request
|
49
|
+
end
|
50
|
+
|
51
|
+
expect { http_client.call }.to raise_error(Slack::Notifier::APIError,
|
52
|
+
/something_bad \(HTTP Code 400\)/)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
# rubocop:disable Metrics/LineLength
|
5
|
+
RSpec.describe Slack::Notifier::Util::LinkFormatter do
|
6
|
+
describe "initialize & formatted" do
|
7
|
+
it "can be initialized without format args" do
|
8
|
+
subject = described_class.new("Hello World")
|
9
|
+
expect(subject.formatted()).to eq("Hello World")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can be initialized with format args" do
|
13
|
+
subject = described_class.new("Hello World", formats: [:html])
|
14
|
+
expect(subject.formatted()).to eq("Hello World")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
describe "::format" do
|
18
|
+
it "formats html links" do
|
19
|
+
formatted = described_class.format("Hello World, enjoy <a href='http://example.com'>this</a>.")
|
20
|
+
expect(formatted).to include("<http://example.com|this>")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "formats markdown links" do
|
24
|
+
formatted = described_class.format("Hello World, enjoy [this](http://example.com).")
|
25
|
+
expect(formatted).to include("<http://example.com|this>")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "formats markdown links in brackets" do
|
29
|
+
formatted = described_class.format("Hello World, enjoy [[this](http://example.com) in brackets].")
|
30
|
+
expect(formatted).to eq("Hello World, enjoy [<http://example.com|this> in brackets].")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "formats markdown links with no title" do
|
34
|
+
formatted = described_class.format("Hello World, enjoy [](http://example.com).")
|
35
|
+
expect(formatted).to include("<http://example.com>")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "handles multiple html links" do
|
39
|
+
formatted = described_class.format("Hello World, enjoy <a href='http://example.com'>this</a><a href='http://example2.com'>this2</a>.")
|
40
|
+
expect(formatted).to include("<http://example.com|this>")
|
41
|
+
expect(formatted).to include("<http://example2.com|this2>")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "handles multiple markdown links" do
|
45
|
+
formatted = described_class.format("Hello World, enjoy [this](http://example.com)[this2](http://example2.com).")
|
46
|
+
expect(formatted).to include("<http://example.com|this>")
|
47
|
+
expect(formatted).to include("<http://example2.com|this2>")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "handles mixed html & markdown links" do
|
51
|
+
formatted = described_class.format("Hello World, enjoy [this](http://example.com)<a href='http://example2.com'>this2</a>.")
|
52
|
+
expect(formatted).to include("<http://example.com|this>")
|
53
|
+
expect(formatted).to include("<http://example2.com|this2>")
|
54
|
+
end
|
55
|
+
|
56
|
+
if "".respond_to? :scrub
|
57
|
+
context "when on ruby 2.1+ or have string-scrub installed" do
|
58
|
+
it "handles invalid unicode sequences" do
|
59
|
+
expect do
|
60
|
+
described_class.format("This sequence is invalid: \255")
|
61
|
+
end.not_to raise_error
|
62
|
+
end
|
63
|
+
|
64
|
+
it "replaces invalid unicode sequences with the unicode replacement character" do
|
65
|
+
formatted = described_class.format("\255")
|
66
|
+
expect(formatted).to eq "\uFFFD"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "doesn't replace valid Japanese" do
|
72
|
+
formatted = described_class.format("こんにちは")
|
73
|
+
expect(formatted).to eq "こんにちは"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "handles mailto links in markdown" do
|
77
|
+
formatted = described_class.format("[John](mailto:john@example.com)")
|
78
|
+
expect(formatted).to eq "<mailto:john@example.com|John>"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "handles mailto links in html" do
|
82
|
+
formatted = described_class.format("<a href='mailto:john@example.com'>John</a>")
|
83
|
+
expect(formatted).to eq "<mailto:john@example.com|John>"
|
84
|
+
end
|
85
|
+
|
86
|
+
it "handles links with trailing parentheses" do
|
87
|
+
formatted = described_class.format("Hello World, enjoy [foo(bar)](http://example.com/foo(bar))<a href='http://example.com/bar(foo)'>bar(foo)</a>")
|
88
|
+
expect(formatted).to include("http://example.com/foo(bar)|foo(bar)")
|
89
|
+
expect(formatted).to include("http://example.com/bar(foo)|bar(foo)")
|
90
|
+
end
|
91
|
+
|
92
|
+
it "formats a number of differently formatted links" do
|
93
|
+
input_output = {
|
94
|
+
"Hello World, enjoy [this](http://example.com)." =>
|
95
|
+
"Hello World, enjoy <http://example.com|this>.",
|
96
|
+
|
97
|
+
"Hello World, enjoy [[this](http://example.com) in brackets]." =>
|
98
|
+
"Hello World, enjoy [<http://example.com|this> in brackets].",
|
99
|
+
|
100
|
+
"Hello World, enjoy ([this](http://example.com) in parens)." =>
|
101
|
+
"Hello World, enjoy (<http://example.com|this> in parens).",
|
102
|
+
|
103
|
+
"Hello World, enjoy [](http://example.com)." =>
|
104
|
+
"Hello World, enjoy <http://example.com>.",
|
105
|
+
|
106
|
+
"Hello World, enjoy [link with query](http://example.com?foo=bar)." =>
|
107
|
+
"Hello World, enjoy <http://example.com?foo=bar|link with query>.",
|
108
|
+
|
109
|
+
"Hello World, enjoy [link with fragment](http://example.com/#foo-bar)." =>
|
110
|
+
"Hello World, enjoy <http://example.com/#foo-bar|link with fragment>.",
|
111
|
+
|
112
|
+
"Hello World, enjoy [link with parens](http://example.com/foo(bar)/baz)." =>
|
113
|
+
"Hello World, enjoy <http://example.com/foo(bar)/baz|link with parens>.",
|
114
|
+
|
115
|
+
"Hello World, enjoy [link with query](http://example.com/(parens)?foo=bar)." =>
|
116
|
+
"Hello World, enjoy <http://example.com/(parens)?foo=bar|link with query>.",
|
117
|
+
|
118
|
+
"Hello World, enjoy [link with parens](http://example.com/baz?bang=foo(bar))." =>
|
119
|
+
"Hello World, enjoy <http://example.com/baz?bang=foo(bar)|link with parens>.",
|
120
|
+
|
121
|
+
"Hello World, enjoy [link with fragment](http://example.com/(parens)#foo-bar)." =>
|
122
|
+
"Hello World, enjoy <http://example.com/(parens)#foo-bar|link with fragment>.",
|
123
|
+
|
124
|
+
"Hello World, enjoy [link with fragment](http://example.com/#foo-bar=(baz))." =>
|
125
|
+
"Hello World, enjoy <http://example.com/#foo-bar=(baz)|link with fragment>.",
|
126
|
+
|
127
|
+
"Hello World, enjoy [this](http://example.com?foo=bar)[this2](http://example2.com)." =>
|
128
|
+
"Hello World, enjoy <http://example.com?foo=bar|this><http://example2.com|this2>.",
|
129
|
+
|
130
|
+
"Hello World, enjoy [this](http://example.com?foo=bar) [this2](http://example2.com/#fragment)." =>
|
131
|
+
"Hello World, enjoy <http://example.com?foo=bar|this> <http://example2.com/#fragment|this2>.",
|
132
|
+
|
133
|
+
"Hello World, enjoy [this](http://example.com)<a href='http://example2.com'>this2</a>." =>
|
134
|
+
"Hello World, enjoy <http://example.com|this><http://example2.com|this2>.",
|
135
|
+
|
136
|
+
"Hello world, [John](mailto:john@example.com)." =>
|
137
|
+
"Hello world, <mailto:john@example.com|John>.",
|
138
|
+
|
139
|
+
"Hello World, enjoy [foo(bar)](http://example.com/foo(bar))<a href='http://example.com/bar(foo)'>bar(foo)</a>" =>
|
140
|
+
"Hello World, enjoy <http://example.com/foo(bar)|foo(bar)><http://example.com/bar(foo)|bar(foo)>"
|
141
|
+
}
|
142
|
+
|
143
|
+
input_output.each do |input, output|
|
144
|
+
expect(described_class.format(input)).to eq output
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context "with a configured stack" do
|
149
|
+
it "only formats html if html is the only item in formats" do
|
150
|
+
formatted = described_class.format("Hello World, enjoy [this](http://example.com)<a href='http://example2.com'>this2</a>.", formats: [:html])
|
151
|
+
expect(formatted).to eq "Hello World, enjoy [this](http://example.com)<http://example2.com|this2>."
|
152
|
+
end
|
153
|
+
it "only formats markdown if markdown is the only item in formats" do
|
154
|
+
formatted = described_class.format("Hello World, enjoy [this](http://example.com)<a href='http://example2.com'>this2</a>.", formats: [:markdown])
|
155
|
+
expect(formatted).to eq "Hello World, enjoy <http://example.com|this><a href='http://example2.com'>this2</a>."
|
156
|
+
end
|
157
|
+
it "doesn't format if formats is empty" do
|
158
|
+
formatted = described_class.format("Hello World, enjoy [this](http://example.com)<a href='http://example2.com'>this2</a>.", formats: [])
|
159
|
+
expect(formatted).to eq "Hello World, enjoy [this](http://example.com)<a href='http://example2.com'>this2</a>."
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|