0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-06 13:08:40 +08:00
discourse/spec/jobs/deliver_push_notification_spec.rb
Alan Guo Xiang Tan 6df9b0b357
DEV: Prefer RSpec primitives for test setup (#42122)
RSpec setup becomes harder to follow at either extreme: trivial fixture
wrappers hide lifecycle and intent, while forcing every named operation
inline repeats low-level protocol and configuration details.

This change documents and applies a test-setup hierarchy:

- use `fab!`, `let`, `let!`, `subject`, and inline `Fabricate` according
to lifecycle and role;
- use a small example-group method when parameterized behavior gives one
spec useful vocabulary;
- move helpers into auto-loaded `spec/support` only when they are shared
across spec files;
- use fabricators and page objects for the data shapes and system-test
interfaces they own.

Core and plugin support files are loaded centrally by `rails_helper`, so
plugin-specific support loaders are unnecessary. The migration specs
encountered during the sweep are removed according to repository policy;
production migrations are unchanged.
2026-07-30 11:17:22 +08:00

190 lines
6.3 KiB
Ruby
Vendored

# frozen_string_literal: true
RSpec.describe Jobs::DeliverPushNotification do
fab!(:user)
fab!(:post)
let(:payload) do
{
"notification_type" => 1,
"post_url" => "/t/#{post.topic_id}/#{post.post_number}",
"excerpt" => "Hello you",
}
end
before do
freeze_time
SiteSetting.push_notification_time_window_mins = 5
end
describe "time window gate" do
fab!(:time_window_push_subscription) { Fabricate(:push_subscription, user: user) }
it "does not deliver when user is missing" do
PushNotificationPusher.expects(:push).never
HubPushNotificationPusher.expects(:push).never
Jobs::DeliverPushNotification.new.execute(user_id: -999, payload: payload)
end
it "does not deliver when user was recently seen" do
user.update!(last_seen_at: 1.minute.ago)
PushNotificationPusher.expects(:push).never
HubPushNotificationPusher.expects(:push).never
Jobs::DeliverPushNotification.new.execute(user_id: user.id, payload: payload)
end
it "delivers when user is offline" do
user.update!(last_seen_at: 10.minutes.ago)
PushNotificationPusher.expects(:push).with(user, payload)
HubPushNotificationPusher.expects(:push).with(user, payload)
Jobs::DeliverPushNotification.new.execute(user_id: user.id, payload: payload)
end
it "delivers when bypass_time_window is true despite user being active" do
user.update!(last_seen_at: 1.minute.ago)
PushNotificationPusher.expects(:push).with(user, payload)
HubPushNotificationPusher.expects(:push).with(user, payload)
Jobs::DeliverPushNotification.new.execute(
user_id: user.id,
bypass_time_window: true,
payload: payload,
)
end
end
describe "web push delivery" do
before { user.update!(last_seen_at: 10.minutes.ago) }
it "calls PushNotificationPusher when user has push subscriptions" do
Fabricate(:push_subscription, user: user)
PushNotificationPusher.expects(:push).with(user, payload).once
Jobs::DeliverPushNotification.new.execute(user_id: user.id, payload: payload)
end
it "does not call PushNotificationPusher when user has no push subscriptions" do
PushNotificationPusher.expects(:push).never
Jobs::DeliverPushNotification.new.execute(user_id: user.id, payload: payload)
end
end
describe "hub push delivery" do
before { user.update!(last_seen_at: 10.minutes.ago) }
it "calls HubPushNotificationPusher" do
HubPushNotificationPusher.expects(:push).with(user, payload).once
Jobs::DeliverPushNotification.new.execute(user_id: user.id, payload: payload)
end
end
describe "both mechanisms" do
it "delivers via both pushers for the same user" do
user.update!(last_seen_at: 10.minutes.ago)
Fabricate(:push_subscription, user: user)
PushNotificationPusher.expects(:push).with(user, payload).once
HubPushNotificationPusher.expects(:push).with(user, payload).once
Jobs::DeliverPushNotification.new.execute(user_id: user.id, payload: payload)
end
end
describe "content localization" do
fab!(:topic) { Fabricate(:topic, title: "Original topic title") }
fab!(:localized_post) { Fabricate(:post, topic: topic, raw: "Original post content") }
let(:localizable_payload) do
{
"notification_type" => 1,
"post_url" => "/t/#{topic.id}/#{localized_post.post_number}",
"topic_title" => topic.title,
"topic_id" => topic.id,
"post_id" => localized_post.id,
"excerpt" => "Original post content",
"username" => "system",
"post_number" => localized_post.post_number,
}
end
before do
SiteSetting.content_localization_enabled = true
SiteSetting.allow_user_locale = true
user.update!(last_seen_at: 10.minutes.ago, locale: "ja")
end
it "localizes payload before delivering to web push" do
Fabricate(:push_subscription, user: user)
Fabricate(
:topic_localization,
topic: topic,
locale: "ja",
title: "ローカライズされたトピック",
fancy_title: "ローカライズされたトピック",
)
Fabricate(
:post_localization,
post: localized_post,
locale: "ja",
raw: "ローカライズされた投稿",
cooked: "<p>ローカライズされた投稿</p>",
)
PushNotificationPusher
.expects(:push)
.with { |u, p| p[:topic_title] == "ローカライズされたトピック" && p[:excerpt] == "ローカライズされた投稿" }
.once
Jobs::DeliverPushNotification.new.execute(user_id: user.id, payload: localizable_payload)
end
it "localizes payload before delivering to hub push" do
SiteSetting.allowed_user_api_push_urls = "https://hub.example.com/push"
client = Fabricate(:user_api_key_client)
Fabricate(
:user_api_key,
user: user,
scopes: ["notifications"].map { |name| UserApiKeyScope.new(name: name) },
push_url: "https://hub.example.com/push",
user_api_key_client_id: client.id,
)
Fabricate(
:topic_localization,
topic: topic,
locale: "ja",
title: "ローカライズされたトピック",
fancy_title: "ローカライズされたトピック",
)
body = nil
stub_request(:post, "https://hub.example.com/push").to_return do |request|
body = JSON.parse(request.body)
{ status: 200 }
end
Jobs::DeliverPushNotification.new.execute(user_id: user.id, payload: localizable_payload)
expect(body["notifications"].first["topic_title"]).to eq("ローカライズされたトピック")
end
it "does not localize when content_localization_enabled is false" do
SiteSetting.content_localization_enabled = false
Fabricate(:push_subscription, user: user)
Fabricate(
:topic_localization,
topic: topic,
locale: "ja",
title: "ローカライズされたトピック",
fancy_title: "ローカライズされたトピック",
)
PushNotificationPusher
.expects(:push)
.with do |u, p|
p[:topic_title] == "Original topic title" || p["topic_title"] == "Original topic title"
end
.once
Jobs::DeliverPushNotification.new.execute(user_id: user.id, payload: localizable_payload)
end
end
end