whatsapp_notifier 0.8.1 → 0.9.1
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/README.md +391 -102
- data/docs/CONFIGURATION.md +89 -0
- data/lib/whatsapp_notifier/client.rb +4 -0
- data/lib/whatsapp_notifier/error_code.rb +137 -0
- data/lib/whatsapp_notifier/errors.rb +21 -0
- data/lib/whatsapp_notifier/providers/base.rb +18 -0
- data/lib/whatsapp_notifier/providers/web_automation.rb +14 -3
- data/lib/whatsapp_notifier/services/web_automation/history.test.ts +68 -1
- data/lib/whatsapp_notifier/services/web_automation/history.ts +34 -7
- data/lib/whatsapp_notifier/services/web_automation/inbound.test.ts +120 -6
- data/lib/whatsapp_notifier/services/web_automation/inbound.ts +115 -16
- data/lib/whatsapp_notifier/services/web_automation/index.ts +59 -0
- data/lib/whatsapp_notifier/services/web_automation/metrics.test.ts +3 -0
- data/lib/whatsapp_notifier/services/web_automation/metrics.ts +3 -0
- data/lib/whatsapp_notifier/services/web_automation/sessions.test.ts +22 -0
- data/lib/whatsapp_notifier/services/web_automation/sessions.ts +19 -0
- data/lib/whatsapp_notifier/version.rb +1 -1
- data/lib/whatsapp_notifier/web_adapter.rb +6 -2
- data/lib/whatsapp_notifier.rb +11 -0
- data/spec/error_code_spec.rb +107 -0
- data/spec/providers/web_automation_spec.rb +62 -0
- data/spec/session_ready_spec.rb +114 -0
- data/spec/web_adapter_spec.rb +35 -0
- metadata +5 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
# WhatsAppNotifier.session_ready? — the one call hosts make before sending, so
|
|
4
|
+
# they stop each writing their own "authenticated == true, rescue to false".
|
|
5
|
+
RSpec.describe "session readiness" do
|
|
6
|
+
def configure(adapter)
|
|
7
|
+
WhatsAppNotifier.configure do |config|
|
|
8
|
+
config.provider = :web_automation
|
|
9
|
+
config.web_automation_enabled = true
|
|
10
|
+
config.web_adapter = adapter
|
|
11
|
+
config.logger = Logger.new(nil)
|
|
12
|
+
config.warn_on_risky_provider = false
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def adapter_returning(status)
|
|
17
|
+
adapter = double(send_message: { success: true, session: {} }, fetch_qr_code: "qr")
|
|
18
|
+
allow(adapter).to receive(:connection_status).and_return(status)
|
|
19
|
+
adapter
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def adapter_raising(error)
|
|
23
|
+
adapter = double(send_message: { success: true, session: {} }, fetch_qr_code: "qr")
|
|
24
|
+
allow(adapter).to receive(:connection_status).and_raise(error)
|
|
25
|
+
adapter
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "is true only when the service reports an authenticated session" do
|
|
29
|
+
configure(adapter_returning(state: "AUTHENTICATED", authenticated: true))
|
|
30
|
+
|
|
31
|
+
expect(WhatsAppNotifier.session_ready?(user_id: 7)).to be(true)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "is false when the session is not authenticated" do
|
|
35
|
+
configure(adapter_returning(state: "QR_REQUIRED", authenticated: false))
|
|
36
|
+
|
|
37
|
+
expect(WhatsAppNotifier.session_ready?(user_id: 7)).to be(false)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Truthy-but-not-true (a "yes" string from a sloppy adapter) must not read
|
|
41
|
+
# as ready — the check is deliberately exact.
|
|
42
|
+
it "is false for a truthy non-true authenticated value" do
|
|
43
|
+
configure(adapter_returning(authenticated: "yes"))
|
|
44
|
+
|
|
45
|
+
expect(WhatsAppNotifier.session_ready?(user_id: 7)).to be(false)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "is false when the adapter answers with something that is not a hash" do
|
|
49
|
+
configure(adapter_returning(nil))
|
|
50
|
+
|
|
51
|
+
expect(WhatsAppNotifier.session_ready?(user_id: 7)).to be(false)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# An unreachable status endpoint means the service is down, so sends can't
|
|
55
|
+
# succeed either — not ready, and logged rather than raised.
|
|
56
|
+
it "is false and logs when the status endpoint is unreachable" do
|
|
57
|
+
logger = double(warn: true)
|
|
58
|
+
configure(adapter_raising(Errno::ECONNREFUSED))
|
|
59
|
+
WhatsAppNotifier.configuration.logger = logger
|
|
60
|
+
|
|
61
|
+
expect(WhatsAppNotifier.session_ready?(user_id: 7)).to be(false)
|
|
62
|
+
expect(logger).to have_received(:warn).with(/session_ready\? failed/)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "survives a nil logger" do
|
|
66
|
+
configure(adapter_raising(Errno::ECONNREFUSED))
|
|
67
|
+
WhatsAppNotifier.configuration.logger = nil
|
|
68
|
+
|
|
69
|
+
expect(WhatsAppNotifier.session_ready?(user_id: 7)).to be(false)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# A ConfigurationError is a boot-time mistake in the HOST. Swallowing it
|
|
73
|
+
# would quietly park every campaign behind a "session down" backoff.
|
|
74
|
+
it "does not swallow a configuration error" do
|
|
75
|
+
configure(adapter_returning(authenticated: true))
|
|
76
|
+
WhatsAppNotifier.configuration.web_automation_enabled = false
|
|
77
|
+
|
|
78
|
+
expect { WhatsAppNotifier.session_ready?(user_id: 7) }
|
|
79
|
+
.to raise_error(WhatsAppNotifier::ConfigurationError, /disabled/)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "passes the user id through as status metadata" do
|
|
83
|
+
adapter = adapter_returning(authenticated: true)
|
|
84
|
+
configure(adapter)
|
|
85
|
+
|
|
86
|
+
WhatsAppNotifier.session_ready?(user_id: 42)
|
|
87
|
+
|
|
88
|
+
expect(adapter).to have_received(:connection_status).with(metadata: { user_id: 42 })
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "accepts a metadata hash instead of user_id" do
|
|
92
|
+
adapter = adapter_returning(authenticated: true)
|
|
93
|
+
configure(adapter)
|
|
94
|
+
|
|
95
|
+
WhatsAppNotifier.session_ready?(metadata: { user_id: 9, tenant: "x" })
|
|
96
|
+
|
|
97
|
+
expect(adapter).to have_received(:connection_status).with(metadata: { user_id: 9, tenant: "x" })
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "asks for the default session when neither is given" do
|
|
101
|
+
adapter = adapter_returning(authenticated: true)
|
|
102
|
+
configure(adapter)
|
|
103
|
+
|
|
104
|
+
WhatsAppNotifier.session_ready?
|
|
105
|
+
|
|
106
|
+
expect(adapter).to have_received(:connection_status).with(metadata: {})
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "is not implemented by a bare provider" do
|
|
110
|
+
provider = WhatsAppNotifier::Providers::Base.new(configuration: WhatsAppNotifier.configuration)
|
|
111
|
+
|
|
112
|
+
expect { provider.session_ready? }.to raise_error(NotImplementedError)
|
|
113
|
+
end
|
|
114
|
+
end
|
data/spec/web_adapter_spec.rb
CHANGED
|
@@ -104,6 +104,41 @@ RSpec.describe WhatsAppNotifier::WebAdapter do
|
|
|
104
104
|
end.to raise_error(/service request failed/)
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
+
# The status is what ErrorCode classifies on — re-deriving it from the
|
|
108
|
+
# message text would be a regex round-trip through our own string.
|
|
109
|
+
it "carries the HTTP status on the raised service error" do
|
|
110
|
+
allow(Net::HTTP).to receive(:start)
|
|
111
|
+
.and_return(http_failure(code: "401", body: JSON.generate({ error: "User not authenticated" })))
|
|
112
|
+
|
|
113
|
+
expect { adapter.send_message(payload: { to: "+1", body: "hi" }, session: {}) }
|
|
114
|
+
.to raise_error(WhatsAppNotifier::ServiceError) { |error|
|
|
115
|
+
expect(error.status.to_i).to eq(401)
|
|
116
|
+
# Pre-0.9.0 this was a bare RuntimeError; hosts rescue that class by
|
|
117
|
+
# name around media fetches and status polls.
|
|
118
|
+
expect(error).to be_a(RuntimeError)
|
|
119
|
+
# Wording unchanged from 0.8.x — hosts that fingerprinted it still match.
|
|
120
|
+
expect(error.message).to eq("service request failed (401): User not authenticated")
|
|
121
|
+
}
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Forward compatibility: a future service can name the failure itself and
|
|
125
|
+
# the gem stops guessing from text.
|
|
126
|
+
it "normalizes an error code the service supplied" do
|
|
127
|
+
response = http_success(body: { "success" => false, "errorCode" => "NUMBER_NOT_REGISTERED", "error" => "boom" })
|
|
128
|
+
allow(Net::HTTP).to receive(:start).and_return(response)
|
|
129
|
+
|
|
130
|
+
result = adapter.send_message(payload: { to: "+1", body: "hi" }, session: {})
|
|
131
|
+
|
|
132
|
+
expect(result).to include(success: false, error_code: :not_on_whatsapp, error_message: "boom")
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "leaves error_code nil when the service does not send one" do
|
|
136
|
+
response = http_success(body: { "success" => false, "error" => "boom" })
|
|
137
|
+
allow(Net::HTTP).to receive(:start).and_return(response)
|
|
138
|
+
|
|
139
|
+
expect(adapter.send_message(payload: { to: "+1", body: "hi" }, session: {})[:error_code]).to be_nil
|
|
140
|
+
end
|
|
141
|
+
|
|
107
142
|
it "handles empty and invalid response bodies gracefully" do
|
|
108
143
|
empty_body = instance_double(Net::HTTPOK, body: "", code: "200", is_a?: true)
|
|
109
144
|
invalid_body = instance_double(Net::HTTPInternalServerError, body: "raw-error", code: "500", is_a?: false)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: whatsapp_notifier
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kshitiz Sinha
|
|
@@ -56,6 +56,7 @@ files:
|
|
|
56
56
|
- app/controllers/whatsapp_notifier/sessions_controller.rb
|
|
57
57
|
- bin/whatsapp_notifier
|
|
58
58
|
- config/routes.rb
|
|
59
|
+
- docs/CONFIGURATION.md
|
|
59
60
|
- docs/bulk_messaging_policy.md
|
|
60
61
|
- docs/graphify.md
|
|
61
62
|
- docs/rails_setup.md
|
|
@@ -72,6 +73,7 @@ files:
|
|
|
72
73
|
- lib/whatsapp_notifier/configuration.rb
|
|
73
74
|
- lib/whatsapp_notifier/doctor.rb
|
|
74
75
|
- lib/whatsapp_notifier/engine.rb
|
|
76
|
+
- lib/whatsapp_notifier/error_code.rb
|
|
75
77
|
- lib/whatsapp_notifier/errors.rb
|
|
76
78
|
- lib/whatsapp_notifier/jobs/send_message_job.rb
|
|
77
79
|
- lib/whatsapp_notifier/notification.rb
|
|
@@ -107,6 +109,7 @@ files:
|
|
|
107
109
|
- spec/client_spec.rb
|
|
108
110
|
- spec/configuration_spec.rb
|
|
109
111
|
- spec/doctor_spec.rb
|
|
112
|
+
- spec/error_code_spec.rb
|
|
110
113
|
- spec/generators/install_service_generator_spec.rb
|
|
111
114
|
- spec/jobs/send_message_job_spec.rb
|
|
112
115
|
- spec/notification_spec.rb
|
|
@@ -116,6 +119,7 @@ files:
|
|
|
116
119
|
- spec/result_spec.rb
|
|
117
120
|
- spec/session/qr_service_spec.rb
|
|
118
121
|
- spec/session/store_spec.rb
|
|
122
|
+
- spec/session_ready_spec.rb
|
|
119
123
|
- spec/spec_helper.rb
|
|
120
124
|
- spec/web_adapter_spec.rb
|
|
121
125
|
- spec/whatsapp_notifier_spec.rb
|