ぼざクリタグ広場 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.
 
 
 
 
 
 

308 lines
7.7 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 include(
  96. 'host_flg' => true,
  97. 'post_id' => nil,
  98. 'post_started_at' => nil
  99. )
  100. expect(json.fetch('watching_users')).to contain_exactly(
  101. {
  102. 'id' => member.id,
  103. 'name' => 'member user'
  104. }
  105. )
  106. end
  107. end
  108. context 'when current user is already watching' do
  109. let!(:watching_row) do
  110. TheatreWatchingUser.create!(
  111. theatre: theatre,
  112. user: member,
  113. expires_at: 5.seconds.from_now
  114. )
  115. end
  116. before do
  117. sign_in_as(member)
  118. end
  119. it 'refreshes expires_at without creating another row' do
  120. expect { do_request }
  121. .not_to change { TheatreWatchingUser.count }
  122. expect(response).to have_http_status(:ok)
  123. expect(watching_row.reload.expires_at)
  124. .to be_within(1.second).of(30.seconds.from_now)
  125. end
  126. end
  127. context 'when another active host exists' do
  128. before do
  129. TheatreWatchingUser.create!(
  130. theatre: theatre,
  131. user: other_user,
  132. expires_at: 10.minutes.from_now
  133. )
  134. theatre.update!(host_user: other_user)
  135. sign_in_as(member)
  136. end
  137. it 'does not steal host and returns host_flg false' do
  138. expect { do_request }
  139. .to change { TheatreWatchingUser.count }.by(1)
  140. expect(response).to have_http_status(:ok)
  141. expect(theatre.reload.host_user_id).to eq(other_user.id)
  142. expect(json).to include(
  143. 'host_flg' => false,
  144. 'post_id' => nil,
  145. 'post_started_at' => nil
  146. )
  147. expect(json.fetch('watching_users')).to contain_exactly(
  148. {
  149. 'id' => member.id,
  150. 'name' => 'member user'
  151. },
  152. {
  153. 'id' => other_user.id,
  154. 'name' => 'other user'
  155. }
  156. )
  157. end
  158. end
  159. context 'when host is set but no longer actively watching' do
  160. let(:started_at) { 2.minutes.ago }
  161. before do
  162. TheatreWatchingUser.create!(
  163. theatre: theatre,
  164. user: other_user,
  165. expires_at: 1.second.ago
  166. )
  167. theatre.update!(
  168. host_user: other_user,
  169. current_post: youtube_post,
  170. current_post_started_at: started_at
  171. )
  172. sign_in_as(member)
  173. end
  174. it 'reassigns host to current user and returns current post info' do
  175. expect { do_request }
  176. .to change { TheatreWatchingUser.count }.by(1)
  177. expect(response).to have_http_status(:ok)
  178. theatre.reload
  179. expect(theatre.host_user_id).to eq(member.id)
  180. expect(json['host_flg']).to eq(true)
  181. expect(json['post_id']).to eq(youtube_post.id)
  182. expect(Time.zone.parse(json['post_started_at']))
  183. .to be_within(1.second).of(started_at)
  184. end
  185. end
  186. end
  187. describe 'PATCH /theatres/:id/next_post' do
  188. subject(:do_request) do
  189. patch "/theatres/#{theatre_id}/next_post"
  190. end
  191. let(:theatre_id) { theatre.id }
  192. context 'when not logged in' do
  193. it 'returns 401' do
  194. sign_out
  195. do_request
  196. expect(response).to have_http_status(:unauthorized)
  197. end
  198. end
  199. context 'when theatre does not exist' do
  200. let(:theatre_id) { 999_999_999 }
  201. it 'returns 404' do
  202. sign_in_as(member)
  203. do_request
  204. expect(response).to have_http_status(:not_found)
  205. end
  206. end
  207. context 'when logged in but not host' do
  208. before do
  209. theatre.update!(host_user: other_user)
  210. sign_in_as(member)
  211. end
  212. it 'returns 403' do
  213. do_request
  214. expect(response).to have_http_status(:forbidden)
  215. end
  216. end
  217. context 'when current user is host' do
  218. before do
  219. theatre.update!(host_user: member)
  220. sign_in_as(member)
  221. end
  222. it 'sets current_post to an eligible post and updates current_post_started_at' do
  223. expect { do_request }
  224. .to change { theatre.reload.current_post_id }
  225. .from(nil).to(youtube_post.id)
  226. expect(response).to have_http_status(:no_content)
  227. expect(theatre.reload.current_post_started_at)
  228. .to be_within(1.second).of(Time.current)
  229. end
  230. end
  231. context 'when current user is host and no eligible post exists' do
  232. before do
  233. youtube_post.destroy!
  234. theatre.update!(
  235. host_user: member,
  236. current_post: other_post,
  237. current_post_started_at: 1.hour.ago
  238. )
  239. sign_in_as(member)
  240. end
  241. it 'still returns 204 and clears current_post' do
  242. do_request
  243. expect(response).to have_http_status(:no_content)
  244. theatre.reload
  245. expect(theatre.current_post_id).to be_nil
  246. expect(theatre.current_post_started_at)
  247. .to be_within(1.second).of(Time.current)
  248. end
  249. end
  250. end
  251. end