require 'rails_helper' RSpec.describe BroadcastsController, type: :controller do render_views let(:user) { create(:user) } let(:account) { user.primary_account } let(:project) { create(:project, account: user.primary_account) } before do sign_in user end describe "#index" do before do stub_mux_live_stream end it "responds successfully" do get :index, params: { project_id: project } expect(response).to be_successful end it "renders content if theere are existing broadcasts" do create(:broadcast, project: project, name: "Another Broadcast") get :index, params: { project_id: project } expect(response.body).to have_content "Another Broadcast" expect(response.body).to have_content "Created" expect(response.body).to have_content "less than a minute ago" expect(response.body).to have_link "Create New Live Stream" end context "when there are no active broadcasts" do it "renders splash screen" do Broadcast.destroy_all get :index, params: { project_id: project } expect(response.body).to have_link create_stream expect(response.body).to have_link schedule_demo end end context "when there are many records" do it "paginates the table" do create_list(:broadcast, 20, project: project) get :index, params: { project_id: project } expect(response.body).to have_link("2", href: project_broadcasts_path(project, page: 2)) end end context "for xhr request" do it "filters the broadcasts by a query param" do create(:broadcast, project: project, skip_create_callback: true, name: "Stream by Adam") create(:broadcast, project: project, skip_create_callback: true, name: "Stream by Zoe") get :index, params: { project_id: project, query: "Zoe" }, xhr: true expect(response.body).not_to have_content("Adam") expect(response.body).to have_content("Zoe") end end end describe "#new" do it "responds successfully" do get :new, params: { project_id: project } expect(response).to be_successful expect(assigns(:broadcast)).to be_a_new(Broadcast) expect(response).to render_template(:new) end end describe "#create" do before do stub_mux_live_stream end it "responds with a redirect" do post :create, params: { project_id: project.id, broadcast: broadcast_params } expect(response).to be_redirect expect(flash.notice).not_to be_nil end it "does create a new record" do expect { post :create, params: { project_id: project.id, broadcast: broadcast_params } }.to change(Broadcast, :count) end it "logs an event" do expect { post :create, params: { project_id: project.id, broadcast: broadcast_params } }.to have_enqueued_job(TrackAnalyticsJob).with(user, account, :track_create_live_stream, user_agent: "Rails Testing", user_ip: "0.0.0.0") end context "with invalid data" do it "does not create a new record" do expect { post :create, params: { project_id: project.id, broadcast: { name: "" } } }.not_to change(Broadcast, :count) end end context "when Mux API error occurs" do it "displays an alert message" do allow_any_instance_of(Broadcast).to receive(:create_mux_live_stream).and_raise(MuxRuby::ApiError) expect { post :create, params: { project_id: project.id, broadcast: broadcast_params } }.not_to change(Broadcast, :count) expect(response).to be_redirect expect(flash.alert).not_to be_nil end end context "when ActiveResource API error occurs" do it "displays an alert message" do allow_any_instance_of(Broadcast).to receive(:create_mux_live_stream).and_raise(ActiveResource::ConnectionError.new("")) expect { post :create, params: { project_id: project.id, broadcast: broadcast_params } }.not_to change(Broadcast, :count) expect(response).to be_redirect expect(flash.alert).not_to be_nil end end end describe "#show" do let(:broadcast) { create(:broadcast, project: project, name: "Another Broadcast") } before do stub_mux_live_stream end it "responds successfully" do get :show, params: { project_id: project.id, id: broadcast.id } expect(response).to be_successful expect(assigns(:broadcast)).to eq(broadcast) end it "displays zoom meeting button" do get :show, params: { project_id: project.id, id: broadcast.id } expect(response.body).to have_link("Video Conference", href: project_broadcast_zoom_meeting_url(project, broadcast)) end it "assigns required variables" do get :show, params: { project_id: project.id, id: broadcast.id } expect(assigns(:conference_url)).to eq project_broadcast_zoom_meeting_url(project, broadcast) expect(assigns(:broadcast)).to eq broadcast end context "when there are no multi-view broadcasts" do it "renders the view dropdown with just the current broadcast" do get :show, params: { project_id: project, id: broadcast } expect(response.body).to have_content broadcast.name expect(response.body).to have_selector(".dropdown-menu .dropdown-item.active", text: "Another Broadcast") end end context "when there are multi-view broadcasts" do it "renders the view dropdown with all the broadcasts" do other_broadcast = create(:broadcast, project: project, name: "Some Other Broadcast") get :show, params: { project_id: project, id: broadcast, multi_view_ids: [broadcast.id, other_broadcast.id] } expect(response.body).to have_content broadcast.name expect(response.body).to have_selector(".dropdown-menu .dropdown-item.active", text: "Another Broadcast") expect(response.body).to have_selector(".dropdown-menu a.dropdown-item", text: "Some Other Broadcast") end end context "when virtual director video embed is available" do let(:broadcast) { create(:broadcast, project: project, name: "Another Broadcast", director_mode_video_embed: "") } it "renders the view dropdown with a director mode enable option" do get :show, params: { project_id: project, id: broadcast } expect(response.body).to have_content broadcast.name expect(response.body).to have_selector(".custom-control-label", text: "Director Mode") end context "when director mode is enabled" do it "shows the video embed" do get :show, params: { project_id: project, id: broadcast } expect(response.body).to have_selector("iframe", text: "video player") end it "renders the view dropdown with a director mode disable option" do get :show, params: { project_id: project, id: broadcast } expect(response.body).to have_content broadcast.name expect(response.body).to have_selector(".custom-control-label", text: "Director Mode") end end end context 'when video conference url has been overriden' do let(:broadcast) { create(:broadcast, project: project, video_conference_url_override: 'https://test.com') } it 'uses the override url for the video conference button' do get :show, params: { project_id: project, id: broadcast } expect(response.body).to have_link("Video Conference", href: 'https://test.com') end end end describe "#update" do let!(:broadcast) { create(:broadcast, :with_stream, skip_create_callback: true, project: project ) } it "uploads files to broadcast" do patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true expect(broadcast.files.count).to eq(1) expect(broadcast.files.first.filename).to eq("contract.pdf") end it "sends an update to the broadcasts channel" do allow(BroadcastsChannel).to receive(:broadcast_file_upload_updates) patch :update, params: { project_id: project.id, id: broadcast.id, broadcast: file_params }, xhr: true expect(BroadcastsChannel).to have_received(:broadcast_file_upload_updates) end it "regenerates token if #update is called without broadcast param" do old_token = broadcast.token patch :update, params: { project_id: project.id, id: broadcast.id } expect(response).to redirect_to [project, broadcast] expect(flash.notice).to eq token_reset_notice expect(Broadcast.last.token).not_to eq old_token end end describe "#destroy" do let!(:broadcast_2) { create(:broadcast, :with_stream, skip_create_callback: true, project: project, name: "Another Broadcast") } before do allow_any_instance_of(MuxLiveStream).to receive(:destroy_stream).with(broadcast_2.stream_uid) end it "responds with redirect" do delete :destroy, params: { project_id: project.id, id: broadcast_2.id } expect(response).to be_redirect expect(response).to redirect_to(project_broadcasts_path(project)) expect(flash.alert).not_to be_nil end it "destroys the record" do expect { delete :destroy, params: { project_id: project.id, id: broadcast_2.id } }.to change(Broadcast, :count).by(-1) end end after do # Set the callback again or it will affect other test cases where the callback is required Broadcast.set_callback(:create, :after, :create_mux_live_stream) end private def broadcast_params attributes_for(:broadcast) end def file_params path = Rails.root.join("spec", "fixtures", "files", "contract.pdf") contract_file = Rack::Test::UploadedFile.new(path, "application/pdf") { files: [contract_file] } end def schedule_demo t 'broadcasts.splash.actions.book_demo' end def create_stream t 'broadcasts.splash.actions.create_stream' end def token_reset_notice t 'broadcasts.update.reset_notice' end end