ぼざクリタグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

290 lines
7.2 KiB

  1. require 'rails_helper'
  2. require 'active_support/testing/time_helpers'
  3. RSpec.describe 'Theatres API', type: :request do
  4. include ActiveSupport::Testing::TimeHelpers
  5. around do |example|
  6. travel_to(Time.zone.parse('2026-03-18 21:00:00')) do
  7. example.run
  8. end
  9. end
  10. let(:member) { create(:user, :member, name: 'member user') }
  11. let(:other_user) { create(:user, :member, name: 'other user') }
  12. let!(:youtube_post) do
  13. Post.create!(
  14. title: 'youtube post',
  15. url: 'https://www.youtube.com/watch?v=spec123'
  16. )
  17. end
  18. let!(:other_post) do
  19. Post.create!(
  20. title: 'other post',
  21. url: 'https://example.com/posts/1'
  22. )
  23. end
  24. let!(:theatre) do
  25. Theatre.create!(
  26. name: 'spec theatre',
  27. opens_at: Time.zone.parse('2026-03-18 20:00:00'),
  28. kind: 0,
  29. created_by_user: member
  30. )
  31. end
  32. describe 'GET /theatres/:id' do
  33. subject(:do_request) do
  34. get "/theatres/#{theatre_id}"
  35. end
  36. context 'when theatre exists' do
  37. let(:theatre_id) { theatre.id }
  38. it 'returns theatre json' do
  39. do_request
  40. expect(response).to have_http_status(:ok)
  41. expect(json).to include(
  42. 'id' => theatre.id,
  43. 'name' => 'spec theatre'
  44. )
  45. expect(json).to have_key('opens_at')
  46. expect(json).to have_key('closes_at')
  47. expect(json).to have_key('created_at')
  48. expect(json).to have_key('updated_at')
  49. expect(json['created_by_user']).to include(
  50. 'id' => member.id,
  51. 'name' => 'member user'
  52. )
  53. end
  54. end
  55. context 'when theatre does not exist' do
  56. let(:theatre_id) { 999_999_999 }
  57. it 'returns 404' do
  58. do_request
  59. expect(response).to have_http_status(:not_found)
  60. end
  61. end
  62. end
  63. describe 'PUT /theatres/:id/watching' do
  64. subject(:do_request) do
  65. put "/theatres/#{theatre_id}/watching"
  66. end
  67. let(:theatre_id) { theatre.id }
  68. context 'when not logged in' do
  69. it 'returns 401' do
  70. sign_out
  71. do_request
  72. expect(response).to have_http_status(:unauthorized)
  73. end
  74. end
  75. context 'when theatre does not exist' do
  76. let(:theatre_id) { 999_999_999 }
  77. it 'returns 404' do
  78. sign_in_as(member)
  79. do_request
  80. expect(response).to have_http_status(:not_found)
  81. end
  82. end
  83. context 'when theatre has no host yet' do
  84. before do
  85. sign_in_as(member)
  86. end
  87. it 'creates watching row, assigns current user as host, and returns current theatre info' do
  88. expect { do_request }
  89. .to change { TheatreWatchingUser.count }.by(1)
  90. expect(response).to have_http_status(:ok)
  91. theatre.reload
  92. watch = TheatreWatchingUser.find_by!(theatre: theatre, user: member)
  93. expect(theatre.host_user_id).to eq(member.id)
  94. expect(watch.expires_at).to be_within(1.second).of(30.seconds.from_now)
  95. expect(json).to eq(
  96. 'host_flg' => true,
  97. 'post_id' => nil,
  98. 'post_started_at' => nil
  99. )
  100. end
  101. end
  102. context 'when current user is already watching' do
  103. let!(:watching_row) do
  104. TheatreWatchingUser.create!(
  105. theatre: theatre,
  106. user: member,
  107. expires_at: 5.seconds.from_now
  108. )
  109. end
  110. before do
  111. sign_in_as(member)
  112. end
  113. it 'refreshes expires_at without creating another row' do
  114. expect { do_request }
  115. .not_to change { TheatreWatchingUser.count }
  116. expect(response).to have_http_status(:ok)
  117. expect(watching_row.reload.expires_at)
  118. .to be_within(1.second).of(30.seconds.from_now)
  119. end
  120. end
  121. context 'when another active host exists' do
  122. before do
  123. TheatreWatchingUser.create!(
  124. theatre: theatre,
  125. user: other_user,
  126. expires_at: 10.minutes.from_now
  127. )
  128. theatre.update!(host_user: other_user)
  129. sign_in_as(member)
  130. end
  131. it 'does not steal host and returns host_flg false' do
  132. expect { do_request }
  133. .to change { TheatreWatchingUser.count }.by(1)
  134. expect(response).to have_http_status(:ok)
  135. expect(theatre.reload.host_user_id).to eq(other_user.id)
  136. expect(json).to eq(
  137. 'host_flg' => false,
  138. 'post_id' => nil,
  139. 'post_started_at' => nil
  140. )
  141. end
  142. end
  143. context 'when host is set but no longer actively watching' do
  144. let(:started_at) { 2.minutes.ago }
  145. before do
  146. TheatreWatchingUser.create!(
  147. theatre: theatre,
  148. user: other_user,
  149. expires_at: 1.second.ago
  150. )
  151. theatre.update!(
  152. host_user: other_user,
  153. current_post: youtube_post,
  154. current_post_started_at: started_at
  155. )
  156. sign_in_as(member)
  157. end
  158. it 'reassigns host to current user and returns current post info' do
  159. expect { do_request }
  160. .to change { TheatreWatchingUser.count }.by(1)
  161. expect(response).to have_http_status(:ok)
  162. theatre.reload
  163. expect(theatre.host_user_id).to eq(member.id)
  164. expect(json['host_flg']).to eq(true)
  165. expect(json['post_id']).to eq(youtube_post.id)
  166. expect(Time.zone.parse(json['post_started_at']))
  167. .to be_within(1.second).of(started_at)
  168. end
  169. end
  170. end
  171. describe 'PATCH /theatres/:id/next_post' do
  172. subject(:do_request) do
  173. patch "/theatres/#{theatre_id}/next_post"
  174. end
  175. let(:theatre_id) { theatre.id }
  176. context 'when not logged in' do
  177. it 'returns 401' do
  178. sign_out
  179. do_request
  180. expect(response).to have_http_status(:unauthorized)
  181. end
  182. end
  183. context 'when theatre does not exist' do
  184. let(:theatre_id) { 999_999_999 }
  185. it 'returns 404' do
  186. sign_in_as(member)
  187. do_request
  188. expect(response).to have_http_status(:not_found)
  189. end
  190. end
  191. context 'when logged in but not host' do
  192. before do
  193. theatre.update!(host_user: other_user)
  194. sign_in_as(member)
  195. end
  196. it 'returns 403' do
  197. do_request
  198. expect(response).to have_http_status(:forbidden)
  199. end
  200. end
  201. context 'when current user is host' do
  202. before do
  203. theatre.update!(host_user: member)
  204. sign_in_as(member)
  205. end
  206. it 'sets current_post to an eligible post and updates current_post_started_at' do
  207. expect { do_request }
  208. .to change { theatre.reload.current_post_id }
  209. .from(nil).to(youtube_post.id)
  210. expect(response).to have_http_status(:no_content)
  211. expect(theatre.reload.current_post_started_at)
  212. .to be_within(1.second).of(Time.current)
  213. end
  214. end
  215. context 'when current user is host and no eligible post exists' do
  216. before do
  217. youtube_post.destroy!
  218. theatre.update!(
  219. host_user: member,
  220. current_post: other_post,
  221. current_post_started_at: 1.hour.ago
  222. )
  223. sign_in_as(member)
  224. end
  225. it 'still returns 204 and clears current_post' do
  226. do_request
  227. expect(response).to have_http_status(:no_content)
  228. theatre.reload
  229. expect(theatre.current_post_id).to be_nil
  230. expect(theatre.current_post_started_at)
  231. .to be_within(1.second).of(Time.current)
  232. end
  233. end
  234. end
  235. end