1+ /**
2+ * tests/integration/broadcast.test.js
3+ *
4+ * Tests broadcast HTTP endpoints:
5+ * GET /broadcast/status
6+ * POST /broadcast/start
7+ * POST /broadcast/end
8+ */
9+
10+ import { describe , it , expect , beforeEach } from 'vitest'
11+ import request from 'supertest'
12+ import { setup , resetDb , getApp } from '../helpers/setup.js'
13+ import { createRequire } from 'module'
14+
15+ const require = createRequire ( import . meta. url )
16+
17+ setup ( )
18+
19+ beforeEach ( async ( ) => {
20+ await resetDb ( )
21+ // reset broadcast state between tests
22+ const mod = require ( '../../server/server.js' )
23+ // access and clear currentBroadcast via the end endpoint
24+ // if a broadcast is live from a previous test, end it cleanly
25+ await request ( getApp ( ) ) . post ( '/broadcast/end' )
26+ } )
27+
28+ // ─────────────────────────────────────────────────────────────────────────────
29+ // GET /broadcast/status
30+ // ─────────────────────────────────────────────────────────────────────────────
31+
32+ describe ( 'GET /broadcast/status' , ( ) => {
33+ it ( 'returns live:false when no broadcast is active' , async ( ) => {
34+ const res = await request ( getApp ( ) ) . get ( '/broadcast/status' )
35+ expect ( res . status ) . toBe ( 200 )
36+ expect ( res . body . live ) . toBe ( false )
37+ } )
38+
39+ it ( 'returns live:true with broadcast info when active' , async ( ) => {
40+ await request ( getApp ( ) )
41+ . post ( '/broadcast/start' )
42+ . send ( { uploader : 'Alice' , channel : 'general' } )
43+
44+ const res = await request ( getApp ( ) ) . get ( '/broadcast/status' )
45+ expect ( res . status ) . toBe ( 200 )
46+ expect ( res . body . live ) . toBe ( true )
47+ expect ( res . body . uploader ) . toBe ( 'Alice' )
48+ expect ( res . body . channel ) . toBe ( 'general' )
49+ expect ( res . body . startedAt ) . toBeDefined ( )
50+ } )
51+ } )
52+
53+ // ─────────────────────────────────────────────────────────────────────────────
54+ // POST /broadcast/start
55+ // ─────────────────────────────────────────────────────────────────────────────
56+
57+ describe ( 'POST /broadcast/start' , ( ) => {
58+ it ( 'starts a broadcast and returns 200' , async ( ) => {
59+ const res = await request ( getApp ( ) )
60+ . post ( '/broadcast/start' )
61+ . send ( { uploader : 'Alice' , channel : 'general' } )
62+
63+ expect ( res . status ) . toBe ( 200 )
64+ expect ( res . body . ok ) . toBe ( true )
65+ expect ( res . body . uploader ) . toBe ( 'Alice' )
66+ expect ( res . body . channel ) . toBe ( 'general' )
67+ } )
68+
69+ it ( 'returns 409 if a broadcast is already in progress' , async ( ) => {
70+ await request ( getApp ( ) )
71+ . post ( '/broadcast/start' )
72+ . send ( { uploader : 'Alice' , channel : 'general' } )
73+
74+ const res = await request ( getApp ( ) )
75+ . post ( '/broadcast/start' )
76+ . send ( { uploader : 'Bob' , channel : 'general' } )
77+
78+ expect ( res . status ) . toBe ( 409 )
79+ expect ( res . body . error ) . toBeDefined ( )
80+ expect ( res . body . uploader ) . toBe ( 'Alice' )
81+ } )
82+
83+ it ( 'returns 400 when uploader is missing' , async ( ) => {
84+ const res = await request ( getApp ( ) )
85+ . post ( '/broadcast/start' )
86+ . send ( { channel : 'general' } )
87+
88+ expect ( res . status ) . toBe ( 400 )
89+ } )
90+
91+ it ( 'returns 400 when channel is missing' , async ( ) => {
92+ const res = await request ( getApp ( ) )
93+ . post ( '/broadcast/start' )
94+ . send ( { uploader : 'Alice' } )
95+
96+ expect ( res . status ) . toBe ( 400 )
97+ } )
98+
99+ it ( 'status reflects live broadcast after start' , async ( ) => {
100+ await request ( getApp ( ) )
101+ . post ( '/broadcast/start' )
102+ . send ( { uploader : 'Alice' , channel : 'projects' } )
103+
104+ const status = await request ( getApp ( ) ) . get ( '/broadcast/status' )
105+ expect ( status . body . live ) . toBe ( true )
106+ expect ( status . body . channel ) . toBe ( 'projects' )
107+ } )
108+ } )
109+
110+ // ─────────────────────────────────────────────────────────────────────────────
111+ // POST /broadcast/end
112+ // ─────────────────────────────────────────────────────────────────────────────
113+
114+ describe ( 'POST /broadcast/end' , ( ) => {
115+ it ( 'ends an active broadcast and returns 200' , async ( ) => {
116+ await request ( getApp ( ) )
117+ . post ( '/broadcast/start' )
118+ . send ( { uploader : 'Alice' , channel : 'general' } )
119+
120+ const res = await request ( getApp ( ) ) . post ( '/broadcast/end' )
121+ expect ( res . status ) . toBe ( 200 )
122+ expect ( res . body . ok ) . toBe ( true )
123+ } )
124+
125+ it ( 'status is live:false after broadcast ends' , async ( ) => {
126+ await request ( getApp ( ) )
127+ . post ( '/broadcast/start' )
128+ . send ( { uploader : 'Alice' , channel : 'general' } )
129+
130+ await request ( getApp ( ) ) . post ( '/broadcast/end' )
131+
132+ const status = await request ( getApp ( ) ) . get ( '/broadcast/status' )
133+ expect ( status . body . live ) . toBe ( false )
134+ } )
135+
136+ it ( 'returns 400 when no broadcast is in progress' , async ( ) => {
137+ const res = await request ( getApp ( ) ) . post ( '/broadcast/end' )
138+ expect ( res . status ) . toBe ( 400 )
139+ } )
140+
141+ it ( 'a new broadcast can start after the previous one ends' , async ( ) => {
142+ await request ( getApp ( ) )
143+ . post ( '/broadcast/start' )
144+ . send ( { uploader : 'Alice' , channel : 'general' } )
145+
146+ await request ( getApp ( ) ) . post ( '/broadcast/end' )
147+
148+ const res = await request ( getApp ( ) )
149+ . post ( '/broadcast/start' )
150+ . send ( { uploader : 'Bob' , channel : 'general' } )
151+
152+ expect ( res . status ) . toBe ( 200 )
153+ expect ( res . body . uploader ) . toBe ( 'Bob' )
154+ } )
155+ } )
0 commit comments