mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-27 16:06:48 +09:00
Only room pages posted the subscription again, so a browser that changed its password and closed the profile page went without notifications until it next opened a room. A small controller in the layout does it now, still once per session, and the bell is back to how it was. Two tabs posting at once after a password change could both miss the row and insert two, so the endpoint is looked up again under the same write lock as the session check.
75 lines
3.0 KiB
Ruby
75 lines
3.0 KiB
Ruby
require "application_system_test_case"
|
|
|
|
class PushSubscriptionResyncTest < ApplicationSystemTestCase
|
|
ENDPOINT = "https://fcm.googleapis.com/fcm/send/system-test"
|
|
|
|
setup do
|
|
stub_web_push_dns_resolution
|
|
fake_a_browser_push_subscription
|
|
end
|
|
|
|
teardown do
|
|
page.driver.browser.execute_cdp "Page.removeScriptToEvaluateOnNewDocument", identifier: @fake_subscription_script
|
|
page.execute_script("localStorage.clear()") if page.current_url.start_with?("http")
|
|
end
|
|
|
|
test "a browser posts its subscription again once per session, so it survives a password change" do
|
|
sign_in "david@37signals.com"
|
|
assert_subscription_registered
|
|
first_sync = subscription.updated_at
|
|
|
|
join_room rooms(:hq)
|
|
assert_equal first_sync, subscription.reload.updated_at, "posted again in the same session"
|
|
|
|
first_id = subscription.id
|
|
change_password
|
|
assert_subscription_registered
|
|
assert_not_equal first_id, subscription.id, "not removed and posted again by the profile page"
|
|
assert_not page.evaluate_script("localStorage.getItem('unsubscribed-for-test')")
|
|
end
|
|
|
|
test "a subscription the server refuses stays in the browser" do
|
|
stub_dns_resolution("169.254.169.254")
|
|
|
|
sign_in "david@37signals.com"
|
|
Timeout.timeout(5) { sleep 0.1 until page.evaluate_script("localStorage.getItem('push-subscription-synced-session')") }
|
|
join_room rooms(:hq)
|
|
|
|
assert_not Push::Subscription.exists?(endpoint: ENDPOINT)
|
|
assert_not page.evaluate_script("localStorage.getItem('unsubscribed-for-test')")
|
|
end
|
|
|
|
private
|
|
# Headless Chrome has no push service, so stand in for the subscription the service worker would hold. The
|
|
# browser is shared with other system tests, so teardown removes this again.
|
|
def fake_a_browser_push_subscription
|
|
@fake_subscription_script = page.driver.browser.execute_cdp("Page.addScriptToEvaluateOnNewDocument", source: <<~JS)["identifier"]
|
|
(() => {
|
|
Object.defineProperty(Notification, "permission", { get: () => "granted" })
|
|
const subscription = {
|
|
toJSON: () => ({ endpoint: "#{ENDPOINT}", keys: { p256dh: "p256dh-key", auth: "auth-key" } }),
|
|
unsubscribe: async () => { localStorage.setItem("unsubscribed-for-test", "true") }
|
|
}
|
|
navigator.serviceWorker.getRegistration = async () => ({ pushManager: { getSubscription: async () => subscription } })
|
|
})()
|
|
JS
|
|
end
|
|
|
|
def change_password
|
|
visit user_profile_url
|
|
find("input[name='user[password_challenge]']").fill_in with: "secret123456"
|
|
find("input[name='user[password]']").fill_in with: "a new secret123456"
|
|
find("input[name='user[password]']").send_keys :enter
|
|
assert_selector ".flash", text: "✓"
|
|
end
|
|
|
|
def assert_subscription_registered
|
|
assert_selector "[data-controller~=push-subscription-sync]", visible: :all
|
|
Timeout.timeout(5) { sleep 0.1 until Push::Subscription.exists?(endpoint: ENDPOINT, user: users(:david)) }
|
|
end
|
|
|
|
def subscription
|
|
Push::Subscription.find_by!(endpoint: ENDPOINT)
|
|
end
|
|
end
|