subscriptions_spec.rb 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. RSpec.describe 'API V1 Push Subscriptions' do
  4. let(:user) { Fabricate(:user) }
  5. let(:endpoint) { 'https://fcm.googleapis.com/fcm/send/fiuH06a27qE:APA91bHnSiGcLwdaxdyqVXNDR9w1NlztsHb6lyt5WDKOC_Z_Q8BlFxQoR8tWFSXUIDdkyw0EdvxTu63iqamSaqVSevW5LfoFwojws8XYDXv_NRRLH6vo2CdgiN4jgHv5VLt2A8ah6lUX' }
  6. let(:keys) do
  7. {
  8. p256dh: 'BEm_a0bdPDhf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=',
  9. auth: 'eH_C8rq2raXqlcBVDa1gLg==',
  10. }
  11. end
  12. let(:create_payload) do
  13. {
  14. subscription: {
  15. endpoint: endpoint,
  16. keys: keys,
  17. },
  18. }.with_indifferent_access
  19. end
  20. let(:alerts_payload) do
  21. {
  22. data: {
  23. policy: 'all',
  24. alerts: {
  25. follow: true,
  26. follow_request: true,
  27. favourite: false,
  28. reblog: true,
  29. mention: false,
  30. poll: true,
  31. status: false,
  32. },
  33. },
  34. }.with_indifferent_access
  35. end
  36. let(:scopes) { 'push' }
  37. let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
  38. let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
  39. shared_examples 'validation error' do
  40. it 'returns a validation error' do
  41. subject
  42. expect(response).to have_http_status(422)
  43. expect(response.content_type)
  44. .to start_with('application/json')
  45. expect(endpoint_push_subscriptions.count).to eq(0)
  46. expect(endpoint_push_subscription).to be_nil
  47. end
  48. end
  49. describe 'POST /api/v1/push/subscription' do
  50. subject { post '/api/v1/push/subscription', params: create_payload, headers: headers }
  51. it 'saves push subscriptions and returns expected JSON' do
  52. subject
  53. expect(endpoint_push_subscription)
  54. .to have_attributes(
  55. endpoint: eq(create_payload[:subscription][:endpoint]),
  56. key_p256dh: eq(create_payload[:subscription][:keys][:p256dh]),
  57. key_auth: eq(create_payload[:subscription][:keys][:auth]),
  58. user_id: eq(user.id),
  59. access_token_id: eq(token.id)
  60. )
  61. expect(response.parsed_body.with_indifferent_access)
  62. .to include(
  63. { endpoint: create_payload[:subscription][:endpoint], alerts: {}, policy: 'all' }
  64. )
  65. end
  66. it 'replaces old subscription on repeat calls' do
  67. 2.times { subject }
  68. expect(endpoint_push_subscriptions.count)
  69. .to eq(1)
  70. end
  71. context 'with invalid endpoint URL' do
  72. let(:endpoint) { 'app://example.foo' }
  73. it_behaves_like 'validation error'
  74. end
  75. context 'with invalid p256dh key' do
  76. let(:keys) do
  77. {
  78. p256dh: 'BEm_invalidf0SOsrnB2-ategf1hHoCnpXgQsFj5JCkcoMrMt2WHoPfEYOYPzOIs9mZE8ZUaD7VA5vouy0kEkr8=',
  79. auth: 'eH_C8rq2raXqlcBVDa1gLg==',
  80. }
  81. end
  82. it_behaves_like 'validation error'
  83. end
  84. context 'with invalid base64 p256dh key' do
  85. let(:keys) do
  86. {
  87. p256dh: 'not base64',
  88. auth: 'eH_C8rq2raXqlcBVDa1gLg==',
  89. }
  90. end
  91. it_behaves_like 'validation error'
  92. end
  93. end
  94. describe 'PUT /api/v1/push/subscription' do
  95. subject { put '/api/v1/push/subscription', params: alerts_payload, headers: headers }
  96. before { create_subscription_with_token }
  97. it 'changes data policy and alert settings and returns expected JSON' do
  98. expect { subject }
  99. .to change { endpoint_push_subscription.reload.data }
  100. .from(nil)
  101. .to(include('policy' => alerts_payload[:data][:policy]))
  102. %w(follow follow_request favourite reblog mention poll status).each do |type|
  103. expect(endpoint_push_subscription.data['alerts']).to include(
  104. type.to_s => eq(alerts_payload[:data][:alerts][type.to_sym].to_s)
  105. )
  106. end
  107. expect(response.parsed_body.with_indifferent_access)
  108. .to include(
  109. endpoint: create_payload[:subscription][:endpoint],
  110. alerts: alerts_payload[:data][:alerts],
  111. policy: alerts_payload[:data][:policy]
  112. )
  113. end
  114. end
  115. describe 'DELETE /api/v1/push/subscription' do
  116. subject { delete '/api/v1/push/subscription', headers: headers }
  117. before { create_subscription_with_token }
  118. it 'removes the subscription' do
  119. expect { subject }
  120. .to change { endpoint_push_subscription }.to(nil)
  121. end
  122. end
  123. private
  124. def endpoint_push_subscriptions
  125. Web::PushSubscription.where(
  126. endpoint: create_payload[:subscription][:endpoint]
  127. )
  128. end
  129. def endpoint_push_subscription
  130. endpoint_push_subscriptions.first
  131. end
  132. def create_subscription_with_token
  133. Fabricate(
  134. :web_push_subscription,
  135. endpoint: create_payload[:subscription][:endpoint],
  136. access_token_id: token.id
  137. )
  138. end
  139. end