Files
eminuxandCursor c3ef8e91a6 Rende usabili calendario, overlay ospite e stato diretta del cartellone.
Il calendario non deve più scorrere in orizzontale, il logo a destra non copre il nome e una diretta YouTube o in collegamento compare come In diretta.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-06 09:55:08 +02:00

865 lines
32 KiB
Ruby
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
require "rails_helper"
require "base64"
RSpec.describe "Tournaments", type: :request do
let!(:coach) do
User.create!(email: "torneo-owner@test.it", name: "Owner", password: "Password123", role: "coach")
end
let!(:club) do
c = Club.create!(name: "Torneo Club", sport: "volleyball", primary_color: "#e53935", secondary_color: "#ffffff")
ClubMembership.create!(user: coach, club: c, role: "owner")
c
end
let!(:team) { club.teams.create!(name: "U15", sport: "volleyball") }
def login!
post public_login_path, params: { email: coach.email, password: "Password123" }
end
def assign_plan!(slug)
Billing::AssignPlan.call(club: club, plan_slug: slug)
club.reload
end
it "non crea tornei senza Premium Full" do
assign_plan!("premium_light")
login!
expect {
post public_club_tournaments_path(club), params: {
tournament: {
name: "Memorial",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current + 1,
format_kind: "mixed"
}
}
}.not_to change(Tournament, :count)
expect(response).to redirect_to(public_club_billing_path(club))
end
it "sulla società Free il pulsante Tornei ha il nastrino FULL" do
assign_plan!("free")
login!
get public_club_path(club)
expect(response).to have_http_status(:ok)
expect(response.body).to include("btn-gated__ribbon")
expect(response.body).to include(">FULL<")
expect(response.body).to include(public_club_billing_path(club))
expect(response.body).not_to include(%(href="#{public_club_tournaments_path(club)}"))
end
it "dalla società apre l'elenco tornei, non in dashboard" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Open Elenco",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current + 1,
format_kind: "free"
}
)
get public_club_path(club)
expect(response.body).to include(public_club_tournaments_path(club))
expect(response.body).not_to include("btn-gated__ribbon")
expect(response.body).not_to include("Open Elenco")
expect(response.body).not_to include(public_new_club_tournament_path(club))
get public_club_tournaments_path(club)
expect(response).to have_http_status(:ok)
expect(response.body).to include("Open Elenco")
expect(response.body).to include(public_new_club_tournament_path(club))
expect(response.body).to include(public_tournament_path(tournament))
end
it "crea il torneo, iscrive squadre, genera gironi e pubblica la pagina" do
assign_plan!("premium_full")
login!
expect {
post public_club_tournaments_path(club), params: {
tournament: {
name: "Memorial Estate",
sport_key: "pallavolo",
venue: "Palestra A",
starts_on: Date.current,
ends_on: Date.current + 1,
format_kind: "mixed",
courts: "Campo 1\nCampo 2",
knockout_size: 4
}
}
}.to change(Tournament, :count).by(1)
tournament = Tournament.order(:created_at).last
expect(tournament.broadcast_team).to be_present
expect(tournament.broadcast_team.tournament_broadcast?).to be(true)
expect(tournament.groups.count).to eq(2)
expect(response).to redirect_to(public_tournament_path(tournament))
a = tournament.groups.order(:position).first
b = tournament.groups.order(:position).last
post public_tournament_participants_path(tournament), params: { tournament_participant: { name: "Alfa", group_id: a.id } }
post public_tournament_participants_path(tournament), params: { tournament_participant: { name: "Beta", group_id: a.id } }
post public_tournament_participants_path(tournament), params: { tournament_participant: { name: "Gamma", group_id: b.id } }
post public_tournament_participants_path(tournament), params: { tournament_participant: { name: "Delta", group_id: b.id } }
expect(tournament.participants.count).to eq(4)
post public_generate_group_matches_tournament_path(tournament)
expect(tournament.matches.count).to be > 0
expect(club.teams.visible.map(&:id)).to include(team.id)
expect(club.teams.visible.map(&:id)).not_to include(tournament.broadcast_team_id)
match = tournament.matches.first
home = match.home_participant
away = match.away_participant
post public_tournament_match_result_path(tournament, match), params: { home_score: 2, away_score: 0, tab: "calendario" }
expect(match.reload.played?).to be(true)
expect(match.winner_participant_id).to eq(home.id)
standings = Tournaments::Standings.call(match.tournament_group)
expect(standings.first.participant).to eq(home)
expect(standings.first.points).to eq(3)
tournament.matches.where.associated(:tournament_group).where.not(id: match.id).find_each do |other|
post public_tournament_match_result_path(tournament, other),
params: { home_score: 2, away_score: 0, tab: "calendario" }
end
post public_propose_knockout_tournament_path(tournament)
final = tournament.rounds.find_by(kind: "final").matches.first
expect(final).to be_present
expect(final.home_source_kind).to eq("winner_match")
expect(final.away_source_kind).to eq("winner_match")
get public_tournament_path(tournament, tab: "tabellone")
expect(response.body).to include("Semifinali e finali")
expect(response.body).to include("Compila tabellone")
expect(response.body).to include("match[home_participant_id]")
semi = tournament.rounds.find_by(kind: "semifinal").matches.first
patch public_tournament_match_path(tournament, semi), params: {
tab: "tabellone",
match: {
home_participant_id: tournament.participants.find_by!(name: "Alfa").id,
away_participant_id: tournament.participants.find_by!(name: "Gamma").id
}
}
expect(response).to redirect_to(public_tournament_path(tournament, tab: "tabellone"))
expect(semi.reload.home_participant.name).to eq("Alfa")
expect(semi.away_participant.name).to eq("Gamma")
tournament.rounds.find_by(kind: "semifinal").matches.each do |semi|
post public_tournament_match_result_path(tournament, semi),
params: { home_score: 2, away_score: 0, tab: "tabellone" }
end
expect(final.reload.home_participant).to be_present
expect(final.away_participant).to be_present
expect(final.home_participant_id).not_to eq(final.away_participant_id)
delete public_logout_path
get public_tournament_page_path(tournament.slug)
expect(response).to have_http_status(:not_found)
login!
post public_publish_tournament_path(tournament)
get public_tournament_page_path(tournament.slug)
expect(response).to have_http_status(:ok)
expect(response.body).to include("Memorial Estate")
expect(response.body).to include(home.name)
expect(response.body).to include("Risultati")
expect(response.body).to include("Tabellone")
get public_tournament_page_path(tournament.slug, tab: "tabellone")
expect(response.body).to include("Classifica")
expect(response.body).to include(home.name)
get public_tournament_pages_path
expect(response).to have_http_status(:ok)
expect(response.body).to include("Memorial Estate")
expect(response.body).to include(public_tournament_page_path(tournament.slug))
get public_live_index_path
expect(response.body).to include("Memorial Estate")
expect(response.body).to include("Segui il cartellone")
end
it "delega per campo/giornata e accetta l'invito" do
assign_plan!("premium_full")
login!
post public_club_tournaments_path(club), params: {
tournament: {
name: "Open Day",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free",
courts: "Campo 2"
}
}
tournament = Tournament.order(:created_at).last
home = tournament.participants.create!(name: "Casa")
away = tournament.participants.create!(name: "Ospite")
match = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: home.id,
away_participant_id: away.id,
court: "Campo 2",
scheduled_at: Time.zone.now.change(hour: 10)
}
)
expect {
post public_tournament_invitations_path(tournament), params: {
email: "volontario@test.it",
note: "Porta il treppiede",
email_html: "<p>Testo personalizzato campo 2</p><p>{{link_invito}}</p>",
scope_kind: "court_day",
court: "Campo 2",
on_date: Date.current
}
}.to change { tournament.broadcast_invitations.count }.by(1)
.and change { ActionMailer::Base.deliveries.size }.by(1)
invitation = tournament.broadcast_invitations.last
expect(invitation.note).to eq("Porta il treppiede")
expect(invitation.email_html).to include("Testo personalizzato campo 2")
mail = ActionMailer::Base.deliveries.last
html = (mail.html_part || mail).body.decoded
expect(html).to include("Testo personalizzato campo 2")
expect(html).to include("/join/")
token = nil
follow_redirect!
expect(response.body).to include("/join/")
token = flash[:invite_url].to_s.split("/join/").last
token = CGI.unescapeHTML(response.body[/\/join\/([^"<\s]+)/, 1]) if token.blank?
expect(token).to be_present
volunteer = User.create!(email: "volontario@test.it", name: "Volo", password: "Password123", role: "volunteer")
invitation = tournament.broadcast_invitations.last
invitation.accept!(volunteer)
expect(volunteer.can_broadcast_match?(match)).to be(true)
expect(volunteer.can_broadcast_match?(Match.new(team: team))).to be(false)
end
it "aggiorna orario, campo e logo squadra" do
assign_plan!("premium_full")
login!
post public_club_tournaments_path(club), params: {
tournament: {
name: "Memorial Logo",
sport_key: "pallavolo",
venue: "Palestra A",
starts_on: Date.current,
ends_on: Date.current + 1,
format_kind: "groups",
courts: "Campo 1\nCampo 2"
}
}
tournament = Tournament.order(:created_at).last
group = tournament.groups.order(:position).first
alfa = tournament.participants.create!(name: "Alfa", group: group)
beta = tournament.participants.create!(name: "Beta", group: group)
post public_generate_group_matches_tournament_path(tournament)
match = tournament.matches.first
new_at = Time.zone.local(Date.current.year, Date.current.month, Date.current.day, 16, 30)
patch public_tournament_match_path(tournament, match), params: {
match: { court: "Campo 2", scheduled_at: new_at.strftime("%Y-%m-%dT%H:%M") }
}
match.reload
expect(match.court).to eq("Campo 2")
expect(match.scheduled_at).to eq(new_at)
expect(match.location).to include("Campo 2")
png = nil
png = Tempfile.new(["logo", ".png"])
png.binmode
png.write(Base64.decode64("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="))
png.rewind
patch public_tournament_participant_path(tournament, alfa), params: {
tournament_participant: {
name: "Alfa Blu",
group_id: group.id,
logo_file: Rack::Test::UploadedFile.new(png.path, "image/png", original_filename: "logo.png")
}
}
alfa.reload
expect(alfa.name).to eq("Alfa Blu")
expect(alfa.logo_file).to be_attached
expect(alfa.effective_logo_url).to be_present
if match.away_participant_id == alfa.id
expect(match.reload.opponent_name).to eq("Alfa Blu")
end
ensure
png&.close!
end
it "carica il logo del torneo e lo mostra in pubblico" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Open Logo",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free"
}
)
png = Tempfile.new(["torneo-logo", ".png"])
png.binmode
png.write(Base64.decode64("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="))
png.rewind
patch public_tournament_path(tournament), params: {
tournament: { logo_file: Rack::Test::UploadedFile.new(png.path, "image/png", original_filename: "torneo.png") }
}
expect(tournament.reload.logo_file).to be_attached
expect(tournament.effective_logo_url).to be_present
post public_publish_tournament_path(tournament)
get public_tournament_page_path(tournament.slug)
expect(response.body).to include("tournament-public-hero__logo")
expect(response.body).to include(tournament.effective_logo_url)
get public_tournament_pages_path
expect(response.body).to include("tournament-directory-card")
expect(response.body).to include(tournament.effective_logo_url)
ensure
png&.close!
end
it "inverte casa e ospite con un click" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Memorial Swap",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free",
courts: "Campo 1"
}
)
home = tournament.participants.create!(name: "Casa")
away = tournament.participants.create!(name: "Ospite")
match = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: home.id,
away_participant_id: away.id,
court: "Campo 1",
scheduled_at: Time.zone.now.change(hour: 11)
}
)
Tournaments::RecordResult.call(match: match, home_score: 2, away_score: 0, source: "manual")
get public_tournament_path(tournament, tab: "calendario")
expect(response.body).to include("tournament-match-swap__btn")
expect(response.body).to include("tournament-match-row")
expect(response.body).to include(public_swap_tournament_match_path(tournament, match))
expect(response.body).to include("tournament-calendar.js")
post public_swap_tournament_match_path(tournament, match), as: :json
expect(response).to have_http_status(:ok)
expect(response).not_to be_redirect
json = JSON.parse(response.body)
expect(json["ok"]).to be(true)
expect(json["matchup_label"]).to include("Ospite")
expect(json["matchup_label"]).to include("Casa")
match.reload
expect(match.home_participant_id).to eq(away.id)
expect(match.away_participant_id).to eq(home.id)
expect(match.home_score).to eq(0)
expect(match.away_score).to eq(2)
expect(match.winner_participant_id).to eq(home.id)
expect(match.opponent_name).to eq("Casa")
end
it "invita e gestisce lo streaming dal piano dirette" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Memorial Streaming",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free",
courts: "Campo 1"
}
)
tournament.update!(
invite_draft_email: "bozza@test.it",
invite_draft_html: "<p>Bozza salvata</p><p>{{link_invito}}</p>",
invite_draft_saved_at: Time.current
)
home = tournament.participants.create!(name: "Casa")
away = tournament.participants.create!(name: "Ospite")
match = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: home.id,
away_participant_id: away.id,
court: "Campo 1",
scheduled_at: Time.zone.now.change(hour: 11)
}
)
other = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: away.id,
away_participant_id: home.id,
court: "Campo 1",
scheduled_at: Time.zone.now.change(hour: 13)
}
)
get public_tournament_path(tournament, tab: "delega")
expect(response).to redirect_to(public_tournament_path(tournament, tab: "dirette"))
get public_tournament_path(tournament, tab: "dirette")
expect(response.body).to include("Piano dirette")
expect(response.body).to include("Invita selezionate")
expect(response.body).to include("plan_match_#{match.id}")
expect(response.body).to include("2 da coprire")
get public_tournament_path(tournament, tab: "calendario")
expect(response.body).not_to include("Da coprire")
expect(response.body).not_to include(">Streaming<")
expect {
post public_tournament_invitations_path(tournament), params: {
email: "op.cal@test.it",
tab: "dirette",
match_ids: [match.id]
}
}.to change { tournament.broadcast_invitations.count }.by(1)
.and change { ActionMailer::Base.deliveries.size }.by(1)
invitation = tournament.broadcast_invitations.last
expect(invitation.scope_kind).to eq("matches")
expect(invitation.email_html).to include("Bozza salvata")
expect(invitation.covers_match?(match)).to be(true)
expect(invitation.covers_match?(other)).to be(false)
follow_redirect!
expect(response.body).to include("Piano dirette")
expect(response.body).to include("tournament-streaming-chip--pending")
expect(response.body).to include("tournament-live-status--waiting_operator")
expect(response.body).not_to include("plan_match_#{match.id}")
expect(response.body).to include("plan_match_#{other.id}")
volunteer = User.create!(email: "op.cal@test.it", name: "Operatore Cal", password: "Password123", role: "volunteer")
invitation.accept!(volunteer)
expect(volunteer.can_broadcast_match?(match)).to be(true)
expect(volunteer.can_broadcast_match?(other)).to be(false)
get public_tournament_path(tournament, tab: "dirette")
expect(response.body).to include("Operatore Cal")
expect(response.body).not_to include("tournament-streaming-chip--pending")
session = StreamSession.create!(match: match, user: volunteer, platform: "matchlivetv", status: "live")
get public_tournament_path(tournament, tab: "dirette")
expect(response.body).to include("tournament-live-status--live")
expect(response.body).to include("In diretta")
session.update_columns(status: "ended", ended_at: Time.current)
get public_tournament_path(tournament, tab: "dirette")
expect(response.body).to include("tournament-live-status--ended")
get public_tournament_path(tournament, tab: "calendario")
expect(response.body).not_to include("Operatore Cal")
expect(response.body).not_to include("Invita selezionate")
assignment = match.broadcast_assignments.find_by!(user: volunteer)
delete public_tournament_assignment_path(tournament, assignment)
follow_redirect!
expect(volunteer.reload.can_broadcast_match?(match)).to be(false)
expect(response.body).to include("Piano dirette")
expect(response.body).to include("tournament-live-status--ended")
expect(response.body).not_to include("Operatore Cal")
end
it "revoca un assegnamento senza togliere le altre gare della stessa delega" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Memorial Court Day",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free",
courts: "Campo 2"
}
)
home = tournament.participants.create!(name: "Casa")
away = tournament.participants.create!(name: "Ospite")
match = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: home.id,
away_participant_id: away.id,
court: "Campo 2",
scheduled_at: Time.zone.now.change(hour: 10)
}
)
other = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: away.id,
away_participant_id: home.id,
court: "Campo 2",
scheduled_at: Time.zone.now.change(hour: 12)
}
)
post public_tournament_invitations_path(tournament), params: {
email: "campo@test.it",
scope_kind: "court_day",
court: "Campo 2",
on_date: Date.current
}
volunteer = User.create!(email: "campo@test.it", name: "Campo Op", password: "Password123", role: "volunteer")
invitation = tournament.broadcast_invitations.last
invitation.accept!(volunteer)
expect(volunteer.can_broadcast_match?(match)).to be(true)
expect(volunteer.can_broadcast_match?(other)).to be(true)
assignment = match.broadcast_assignments.find_by!(user: volunteer)
delete public_tournament_assignment_path(tournament, assignment)
expect(volunteer.reload.can_broadcast_match?(match)).to be(false)
expect(volunteer.can_broadcast_match?(other)).to be(true)
expect(invitation.reload.scope_kind).to eq("matches")
expect(invitation.match_ids.map(&:to_s)).to contain_exactly(other.id.to_s)
end
it "carica un'immagine per la mail di delega" do
assign_plan!("premium_full")
login!
post public_club_tournaments_path(club), params: {
tournament: {
name: "Memorial Mail",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free",
courts: "Campo 1"
}
}
tournament = Tournament.order(:created_at).last
png = Tempfile.new(["invite", ".png"])
png.binmode
png.write(Base64.decode64("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="))
png.rewind
post public_tournament_invite_images_path(tournament), params: {
file: Rack::Test::UploadedFile.new(png.path, "image/png", original_filename: "logo.png")
}
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json["url"]).to include("/rails/active_storage")
expect(tournament.reload.invite_email_images).to be_attached
ensure
png&.close!
end
it "salva la bozza della mail senza inviarla" do
assign_plan!("premium_full")
login!
post public_club_tournaments_path(club), params: {
tournament: {
name: "Memorial Bozza",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free",
courts: "Campo 1"
}
}
tournament = Tournament.order(:created_at).last
expect {
post public_tournament_invite_draft_path(tournament), params: {
email: "dopo@test.it",
note: "Porta il treppiede",
email_html: %(<p>Testo bozza con {{link_invito}}</p><p><img src="https://www.example.com/logo.png" alt=""></p>)
}
}.not_to change { ActionMailer::Base.deliveries.size }
tournament.reload
expect(tournament.invite_draft_note).to eq("Porta il treppiede")
expect(tournament.invite_draft_email).to eq("dopo@test.it")
expect(tournament.invite_draft_html).to include("Testo bozza")
expect(tournament.invite_draft_html).to include("{{link_invito}}")
expect(tournament.invite_draft_html).to include("logo.png")
expect(tournament.invite_draft_saved_at).to be_present
get public_tournament_path(tournament, tab: "dirette")
expect(response.body).to include("Testo bozza")
expect(response.body).to include("Porta il treppiede")
expect(response.body).to include("dopo@test.it")
expect(response.body).to include("Salva bozza")
expect(response.body).to include("Piano dirette")
expect(response.body).to include("Testo della mail")
expect(response.body).to include("Invita un operatore")
end
it "elimina il torneo, le partite e il team interno" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Memorial da cancellare",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free",
courts: "Campo 1"
}
)
home = tournament.participants.create!(name: "Casa")
away = tournament.participants.create!(name: "Ospite")
match = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: home.id,
away_participant_id: away.id,
court: "Campo 1",
scheduled_at: Time.zone.now.change(hour: 10)
}
)
session = StreamSession.create!(
match: match, user: coach, platform: "matchlivetv", status: "ended", ended_at: 1.hour.ago
)
Recording.create!(
stream_session: session, team: tournament.broadcast_team, status: "ready", privacy_status: "public",
title: "Replay torneo",
storage_key: "teams/#{tournament.broadcast_team_id}/sessions/#{session.id}/replay.mp4"
)
team_id = tournament.broadcast_team_id
match_id = match.id
get public_tournament_path(tournament)
expect(response.body).to include("Elimina")
expect {
delete public_tournament_path(tournament)
}.to change(Tournament, :count).by(-1)
.and change(Match, :count).by(-1)
.and change(Team, :count).by(-1)
expect(response).to redirect_to(public_club_tournaments_path(club))
expect(Tournament.find_by(id: tournament.id)).to be_nil
expect(Match.find_by(id: match_id)).to be_nil
expect(Team.find_by(id: team_id)).to be_nil
expect(Recording.find_by(stream_session_id: session.id)).to be_nil
get public_tournament_path(tournament.id)
expect(response).to have_http_status(:not_found)
end
it "non elimina il torneo se una diretta è in corso" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Memorial live",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free",
courts: "Campo 1"
}
)
home = tournament.participants.create!(name: "Casa")
away = tournament.participants.create!(name: "Ospite")
match = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: home.id,
away_participant_id: away.id,
court: "Campo 1",
scheduled_at: Time.zone.now.change(hour: 18)
}
)
StreamSession.create!(match: match, user: coach, platform: "matchlivetv", status: "live")
expect {
delete public_tournament_path(tournament)
}.not_to change(Tournament, :count)
expect(response).to redirect_to(public_tournament_path(tournament))
follow_redirect!
expect(response.body).to include("Chiudi le dirette")
end
it "l'owner elimina il torneo anche senza Premium Full" do
assign_plan!("premium_full")
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Memorial declassato",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free"
}
)
assign_plan!("premium_light")
login!
expect {
delete public_tournament_path(tournament)
}.to change(Tournament, :count).by(-1)
expect(response).to redirect_to(public_club_tournaments_path(club))
end
it "mostra sul cartellone i link a diretta e replay" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Open Cartellone",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current + 1,
format_kind: "free",
courts: "Campo 1"
}
)
home = tournament.participants.create!(name: "Alfa")
away = tournament.participants.create!(name: "Beta")
match = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: home.id,
away_participant_id: away.id,
court: "Campo 1",
scheduled_at: 2.hours.from_now
}
)
post public_publish_tournament_path(tournament)
session = StreamSession.create!(
match: match, user: coach, platform: "matchlivetv", status: "live", privacy_status: "public"
)
get public_tournament_page_path(tournament.slug)
expect(response).to have_http_status(:ok)
expect(response.body).to include("Risultati")
expect(response.body).to include("Guarda diretta")
expect(response.body).to include(public_live_path(session))
expect(response.body).to include("tournament-live-status--live")
session.update_columns(status: "ended", ended_at: Time.current)
Recording.create!(
stream_session: session, team: tournament.broadcast_team, status: "ready", privacy_status: "public",
title: "#{tournament.broadcast_team.name} vs #{away.name}",
storage_key: "teams/#{tournament.broadcast_team_id}/sessions/#{session.id}/replay.mp4"
)
get public_tournament_page_path(tournament.slug)
expect(response.body).to include("Guarda replay")
expect(response.body).to include(public_replay_path(session.id))
expect(response.body).to include("tournament-live-status--replay")
expect(response.body).to include("#{home.name} vs #{away.name}")
expect(response.body).not_to include("#{tournament.broadcast_team.name} vs #{away.name}")
get public_club_tournaments_path(club)
expect(response.body).to include(public_tournament_page_path(tournament.slug))
end
it "marca In diretta una gara YouTube o in collegamento, non In attesa" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Open Diretta YouTube",
sport_key: "basket",
starts_on: Date.current,
ends_on: Date.current,
format_kind: "free",
courts: "Campo A"
}
)
home = tournament.participants.create!(name: "Squadra 1")
away = tournament.participants.create!(name: "Squadra 3")
match = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: home.id,
away_participant_id: away.id,
court: "Campo A",
scheduled_at: 30.minutes.ago
}
)
post public_publish_tournament_path(tournament)
session = StreamSession.create!(
match: match, user: coach, platform: "youtube", status: "connecting",
privacy_status: "unlisted", youtube_broadcast_id: "ytLiveBoard1"
)
get public_tournament_page_path(tournament.slug)
expect(response.body).to include("tournament-live-status--live")
expect(response.body).to include("In diretta")
expect(response.body).not_to include("tournament-live-status--waiting")
expect(response.body).to include("Guarda su YouTube")
expect(response.body).to include(session.youtube_watch_url)
get public_tournament_path(tournament, tab: "dirette")
expect(response.body).to include("tournament-live-status--live")
expect(response.body).to include("In diretta")
expect(response.body).not_to include("tournament-live-status--waiting_operator")
end
it "marca Terminata una gara con risultato anche se l'orario è ancora futuro" do
assign_plan!("premium_full")
login!
tournament = Tournaments::Create.call(
club: club,
attrs: {
name: "Open Risultato Anticipato",
sport_key: "pallavolo",
starts_on: Date.current,
ends_on: Date.current + 1,
format_kind: "free",
courts: "Campo 1"
}
)
home = tournament.participants.create!(name: "Alfa")
away = tournament.participants.create!(name: "Delta")
match = Tournaments::ScheduleMatch.call(
tournament: tournament,
attrs: {
home_participant_id: home.id,
away_participant_id: away.id,
court: "Campo 1",
scheduled_at: 6.hours.from_now
}
)
Tournaments::RecordResult.call(match: match, home_score: 2, away_score: 0, source: "manual")
post public_publish_tournament_path(tournament)
get public_tournament_page_path(tournament.slug, tab: "risultati")
expect(response.body).to include("20")
expect(response.body).to include("tournament-live-status--ended")
expect(response.body).to include("Terminata")
expect(response.body).not_to include("tournament-live-status--scheduled")
end
end