From 35551a2f62c6cd57eed40c4e533928fa562f9f18 Mon Sep 17 00:00:00 2001 From: Dominik Lander Date: Thu, 13 Jun 2024 15:56:12 +0100 Subject: [PATCH] Euro 2024 atom header (#27220) Make the Euro 2024 stand out by adding the custom header on selected sports pages: /football/euro-2024/live /football/euro-2024/overview /football/euro-2024/table /football/euro-2024/fixtures Co-Authored-By: Dom Lander Co-authored-by: Max Duval --- .../conf/switches/JournalismSwitches.scala | 11 ++++ .../fragments/atoms/interactive.scala.html | 2 +- .../controllers/FixturesController.scala | 35 ++++++++---- .../controllers/LeagueTableController.scala | 55 ++++++++++++++----- .../controllers/MatchDayController.scala | 23 ++++++-- .../controllers/MatchListController.scala | 8 ++- .../controllers/ResultsController.scala | 5 +- .../controllers/WallchartController.scala | 40 ++++++++++---- .../views/matchList/matchesPage.scala.html | 8 ++- .../views/tablesList/tablesPage.scala.html | 5 ++ .../football/views/wallchart/embed.scala.html | 2 +- .../football/views/wallchart/page.scala.html | 5 +- .../views/wallchart/wallchart.scala.html | 12 +++- sport/conf/routes | 4 +- sport/test/LeagueTablesFeatureTest.scala | 9 ++- .../controllers/FixturesControllerTest.scala | 9 ++- .../LeagueTableControllerTest.scala | 9 ++- 17 files changed, 184 insertions(+), 58 deletions(-) diff --git a/common/app/conf/switches/JournalismSwitches.scala b/common/app/conf/switches/JournalismSwitches.scala index a794c350b52..5666fcab9a3 100644 --- a/common/app/conf/switches/JournalismSwitches.scala +++ b/common/app/conf/switches/JournalismSwitches.scala @@ -1,6 +1,7 @@ package conf.switches import conf.switches.Expiry.never +import java.time.LocalDate trait JournalismSwitches { @@ -73,4 +74,14 @@ trait JournalismSwitches { sellByDate = never, exposeClientSide = true, ) + + val Euro2024Header = Switch( + SwitchGroup.Journalism, + name = "euro-2024-header", + description = "Show the Euro 2024 interactive atom header on football pages", + owners = Seq(Owner.withEmail("dotcom.platform@theguardian.com")), + safeState = Off, + sellByDate = LocalDate.of(2024, 7, 15), + exposeClientSide = true, + ) } diff --git a/common/app/views/fragments/atoms/interactive.scala.html b/common/app/views/fragments/atoms/interactive.scala.html index 0405d0815ce..2cb29fab5c6 100644 --- a/common/app/views/fragments/atoms/interactive.scala.html +++ b/common/app/views/fragments/atoms/interactive.scala.html @@ -36,7 +36,7 @@ @if(shouldFence) { } else { -
+
diff --git a/sport/app/football/controllers/FixturesController.scala b/sport/app/football/controllers/FixturesController.scala index 2e53dbe2251..c960a9f756e 100644 --- a/sport/app/football/controllers/FixturesController.scala +++ b/sport/app/football/controllers/FixturesController.scala @@ -1,19 +1,26 @@ package football.controllers import common.Edition +import common.ImplicitControllerExecutionContext import feed.CompetitionsService import football.model._ import model._ +import model.content.InteractiveAtom +import contentapi.ContentApiClient import java.time.LocalDate import pa.FootballTeam import play.api.mvc.{Action, AnyContent, ControllerComponents} +import scala.concurrent.Future +import conf.switches.Switches class FixturesController( val competitionsService: CompetitionsService, val controllerComponents: ControllerComponents, + val contentApiClient: ContentApiClient, )(implicit context: ApplicationContext) extends MatchListController - with CompetitionFixtureFilters { + with CompetitionFixtureFilters + with ImplicitControllerExecutionContext { private def fixtures(date: LocalDate): FixturesList = FixturesList(date, competitionsService.competitions) private val page = new FootballPage("football/fixtures", "football", "All fixtures") @@ -80,14 +87,22 @@ class FixturesController( private def renderTagFixtures(date: LocalDate, tag: String): Action[AnyContent] = getTagFixtures(date, tag) - .map(result => - Action { implicit request => - renderMatchList( - result._1, - result._2, - filters, - ) - }, - ) + .map { + case (page, fixtures) => + Action.async { implicit request => + tag match { + case "euro-2024" if Switches.Euro2024Header.isSwitchedOn => + val id = "/atom/interactive/interactives/2023/01/euros-2024/tables-euros-2024-header" + val edition = Edition(request) + contentApiClient + .getResponse(contentApiClient.item(id, edition)) + .map(_.interactive.map(InteractiveAtom.make(_))) + .recover { case _ => None } + .map(renderMatchList(page, fixtures, filters, _)) + case _ => + Future.successful(renderMatchList(page, fixtures, filters, None)) + } + } + } .getOrElse(Action(NotFound)) } diff --git a/sport/app/football/controllers/LeagueTableController.scala b/sport/app/football/controllers/LeagueTableController.scala index ff899a1c4e2..0c2b9a1b471 100644 --- a/sport/app/football/controllers/LeagueTableController.scala +++ b/sport/app/football/controllers/LeagueTableController.scala @@ -5,6 +5,9 @@ import conf.switches.Switches import feed.CompetitionsService import model._ import play.api.mvc.{Action, AnyContent, BaseController, ControllerComponents} +import model.content.InteractiveAtom +import contentapi.ContentApiClient +import scala.concurrent.Future case class TablesPage( page: Page, @@ -12,6 +15,7 @@ case class TablesPage( urlBase: String, filters: Map[String, Seq[CompetitionFilter]] = Map.empty, comp: Option[Competition], + atom: Option[InteractiveAtom] = None, ) { lazy val singleCompetition = tables.size == 1 } @@ -19,6 +23,7 @@ case class TablesPage( class LeagueTableController( val competitionsService: CompetitionsService, val controllerComponents: ControllerComponents, + val contentApiClient: ContentApiClient, )(implicit context: ApplicationContext) extends BaseController with GuLogging @@ -80,10 +85,12 @@ class LeagueTableController( val htmlResponse = () => - football.views.html.tablesList.tablesPage(TablesPage(page, groups, "/football", filters(tableOrder), None)) + football.views.html.tablesList + .tablesPage(TablesPage(page, groups, "/football", filters(tableOrder), None)) val jsonResponse = () => - football.views.html.tablesList.tablesPage(TablesPage(page, groups, "/football", filters(tableOrder), None)) + football.views.html.tablesList + .tablesPage(TablesPage(page, groups, "/football", filters(tableOrder), None)) renderFormat(htmlResponse, jsonResponse, page, Switches.all) } @@ -115,7 +122,7 @@ class LeagueTableController( def renderCompetitionJson(competition: String): Action[AnyContent] = renderCompetition(competition) def renderCompetition(competition: String): Action[AnyContent] = - Action { implicit request => + Action.async { implicit request => val table = loadTables .find(_.competition.url.endsWith(s"/$competition")) .orElse(loadTables.find(_.competition.id == competition)) @@ -127,13 +134,30 @@ class LeagueTableController( s"${table.competition.fullName} table", ) + val futureAtom = if (Switches.Euro2024Header.isSwitchedOn && competition == "euro-2024") { + val id = "/atom/interactive/interactives/2023/01/euros-2024/tables-euros-2024-header" + val edition = Edition(request) + contentApiClient + .getResponse(contentApiClient.item(id, edition)) + .map(_.interactive.map(InteractiveAtom.make(_))) + .recover { case _ => None } + } else Future.successful(None) + val smallTableGroup = table.copy(groups = table.groups.map { group => group.copy(entries = group.entries.take(10)) }).groups(0) - val htmlResponse = () => - football.views.html.tablesList - .tablesPage( - TablesPage(page, Seq(table), table.competition.url, filters(tableOrder), Some(table.competition)), - ) + val htmlResponse = (atom: Option[InteractiveAtom]) => + () => + football.views.html.tablesList + .tablesPage( + TablesPage( + page, + Seq(table), + table.competition.url, + filters(tableOrder), + Some(table.competition), + atom, + ), + ) val jsonResponse = () => football.views.html.tablesList.tablesComponent( table.competition, @@ -142,14 +166,13 @@ class LeagueTableController( multiGroup = table.multiGroup, ) - renderFormat(htmlResponse, jsonResponse, page) - + futureAtom.map(maybeAtom => renderFormat(htmlResponse(maybeAtom), jsonResponse, page)) } .getOrElse( if (request.isJson) { - Cached(60)(JsonNotFound()) + Future.successful(Cached(60)(JsonNotFound())) } else { - Redirect("/football/tables") + Future.successful(Redirect("/football/tables")) }, ) } @@ -181,7 +204,13 @@ class LeagueTableController( val htmlResponse = () => football.views.html.tablesList .tablesPage( - TablesPage(page, Seq(groupTable), table.competition.url, filters(tableOrder), Some(table.competition)), + TablesPage( + page, + Seq(groupTable), + table.competition.url, + filters(tableOrder), + Some(table.competition), + ), ) val jsonResponse = () => football.views.html.tablesList.tablesComponent( diff --git a/sport/app/football/controllers/MatchDayController.scala b/sport/app/football/controllers/MatchDayController.scala index 003f2b6adae..ae27b21de47 100644 --- a/sport/app/football/controllers/MatchDayController.scala +++ b/sport/app/football/controllers/MatchDayController.scala @@ -6,13 +6,20 @@ import java.time.LocalDate import model._ import football.model._ import common.{Edition, JsonComponent} +import contentapi.ContentApiClient +import model.content.InteractiveAtom +import common.ImplicitControllerExecutionContext +import scala.concurrent.Future +import conf.switches.Switches class MatchDayController( val competitionsService: CompetitionsService, val controllerComponents: ControllerComponents, + val contentApiClient: ContentApiClient, )(implicit context: ApplicationContext) extends MatchListController - with CompetitionLiveFilters { + with CompetitionLiveFilters + with ImplicitControllerExecutionContext { def liveMatchesJson(): Action[AnyContent] = liveMatches() def liveMatches(): Action[AnyContent] = @@ -41,7 +48,7 @@ class MatchDayController( competitionMatchesFor(competitionTag, year, month, day) private def renderCompetitionMatches(competitionTag: String, date: LocalDate): Action[AnyContent] = - Action { implicit request => + Action.async { implicit request => lookupCompetition(competitionTag) .map { competition => val webTitle = @@ -49,10 +56,18 @@ class MatchDayController( else s" ${competition.fullName} matches" val page = new FootballPage(s"football/$competitionTag/live", "football", webTitle) val matches = CompetitionMatchDayList(competitionsService.competitions, competition.id, date) - renderMatchList(page, matches, filters) + if (Switches.Euro2024Header.isSwitchedOn) { + val id = "/atom/interactive/interactives/2023/01/euros-2024/match-centre-euros-2024-header" + val edition = Edition(request) + contentApiClient + .getResponse(contentApiClient.item(id, edition)) + .map(_.interactive.map(InteractiveAtom.make(_))) + .recover { case _ => None } + .map(renderMatchList(page, matches, filters, _)) + } else Future.successful(renderMatchList(page, matches, filters)) } .getOrElse { - NotFound + Future.successful(NotFound) } } diff --git a/sport/app/football/controllers/MatchListController.scala b/sport/app/football/controllers/MatchListController.scala index 1d21dc35af5..38f5f714a50 100644 --- a/sport/app/football/controllers/MatchListController.scala +++ b/sport/app/football/controllers/MatchListController.scala @@ -13,6 +13,7 @@ import play.api.mvc.{BaseController, RequestHeader} import play.twirl.api.Html import java.time.format.DateTimeFormatter +import model.content.InteractiveAtom trait MatchListController extends BaseController with Requests { def competitionsService: Competitions @@ -25,6 +26,7 @@ trait MatchListController extends BaseController with Requests { page: FootballPage, matchesList: MatchesList, filters: Map[String, Seq[CompetitionFilter]], + atom: Option[InteractiveAtom] = None, )(implicit request: RequestHeader, context: ApplicationContext) = { Cached(10) { if (request.isJson) @@ -32,9 +34,10 @@ trait MatchListController extends BaseController with Requests { "html" -> football.views.html.matchList.matchesComponent(matchesList), "next" -> Html(matchesList.nextPage.getOrElse("")), "previous" -> Html(matchesList.previousPage.getOrElse("")), + "atom" -> atom.isDefined, ) else - RevalidatableResult.Ok(football.views.html.matchList.matchesPage(page, matchesList, filters)) + RevalidatableResult.Ok(football.views.html.matchList.matchesPage(page, matchesList, filters, atom)) } } @@ -42,6 +45,7 @@ trait MatchListController extends BaseController with Requests { page: FootballPage, matchesList: MatchesList, filters: Map[String, Seq[CompetitionFilter]], + atom: Option[InteractiveAtom] = None, )(implicit request: RequestHeader, context: ApplicationContext) = { Cached(10) { if (request.isJson) @@ -51,7 +55,7 @@ trait MatchListController extends BaseController with Requests { "previous" -> Html(matchesList.previousPage.getOrElse("")), ) else - RevalidatableResult.Ok(football.views.html.matchList.matchesPage(page, matchesList, filters)) + RevalidatableResult.Ok(football.views.html.matchList.matchesPage(page, matchesList, filters, atom)) } } diff --git a/sport/app/football/controllers/ResultsController.scala b/sport/app/football/controllers/ResultsController.scala index f4f1fa20674..d43db88681b 100644 --- a/sport/app/football/controllers/ResultsController.scala +++ b/sport/app/football/controllers/ResultsController.scala @@ -8,6 +8,7 @@ import model._ import football.model._ import pa.FootballTeam import model.Competition +import model.content.InteractiveAtom class ResultsController( val competitionsService: CompetitionsService, @@ -54,13 +55,13 @@ class ResultsController( } private def renderWith( - renderFunction: (FootballPage, Results, Map[String, Seq[CompetitionFilter]]) => Result, + renderFunction: (FootballPage, Results, Map[String, Seq[CompetitionFilter]], Option[InteractiveAtom]) => Result, )(date: LocalDate, tag: Option[String] = None): Result = { val result = for { p <- page(tag) r <- results(date, tag) } yield { - renderFunction(p, r, filters) + renderFunction(p, r, filters, None) } result.getOrElse(NotFound("No results")) } diff --git a/sport/app/football/controllers/WallchartController.scala b/sport/app/football/controllers/WallchartController.scala index 964187c1013..187f8344234 100644 --- a/sport/app/football/controllers/WallchartController.scala +++ b/sport/app/football/controllers/WallchartController.scala @@ -9,10 +9,16 @@ import football.model.{CompetitionStage, Groups, KnockoutSpider} import pa.{FootballMatch} import java.time.ZonedDateTime +import scala.concurrent.Future +import contentapi.ContentApiClient +import conf.switches.Switches +import common.Edition +import model.content.InteractiveAtom class WallchartController( competitionsService: CompetitionsService, val controllerComponents: ControllerComponents, + val contentApiClient: ContentApiClient, )(implicit context: ApplicationContext) extends BaseController with GuLogging @@ -28,7 +34,7 @@ class WallchartController( def renderWallchartEmbed(competitionTag: String): Action[AnyContent] = renderWallchart(competitionTag, true) def renderWallchart(competitionTag: String, embed: Boolean = false): Action[AnyContent] = - Action { implicit request => + Action.async { implicit request => competitionsService .competitionsWithTag(competitionTag) .map { competition => @@ -40,18 +46,30 @@ class WallchartController( val competitionStages = new CompetitionStage(competitionsService.competitions) .stagesFromCompetition(competition, KnockoutSpider.orderings) val nextMatch = WallchartController.nextMatch(competition.matches, ZonedDateTime.now()) - Cached(60) { - if (embed) - RevalidatableResult.Ok( - football.views.html.wallchart.embed(page, competition, competitionStages, nextMatch), - ) - else - RevalidatableResult.Ok( - football.views.html.wallchart.page(page, competition, competitionStages, nextMatch), - ) + val futureAtom = if (Switches.Euro2024Header.isSwitchedOn && competitionTag == "euro-2024") { + val id = "/atom/interactive/interactives/2023/01/euros-2024/tables-euros-2024-header" + val edition = Edition(request) + contentApiClient + .getResponse(contentApiClient.item(id, edition)) + .map(_.interactive.map(InteractiveAtom.make(_))) + .recover { case _ => None } + } else Future.successful(None) + + futureAtom.map { maybeAtom => + Cached(60) { + if (embed) + RevalidatableResult.Ok( + football.views.html.wallchart.embed(page, competition, competitionStages, nextMatch), + ) + else + RevalidatableResult.Ok( + football.views.html.wallchart.page(page, competition, competitionStages, nextMatch, maybeAtom), + ) + } } + } - .getOrElse(NotFound) + .getOrElse(Future.successful(NotFound)) } def renderGroupTablesEmbed(competitionTag: String): Action[AnyContent] = diff --git a/sport/app/football/views/matchList/matchesPage.scala.html b/sport/app/football/views/matchList/matchesPage.scala.html index fa28d30ae03..e47f2cb104e 100644 --- a/sport/app/football/views/matchList/matchesPage.scala.html +++ b/sport/app/football/views/matchList/matchesPage.scala.html @@ -4,7 +4,8 @@ @import model.ApplicationContext @import views.html.fragments.commercial.pageLogo @import java.time.format.DateTimeFormatter -@(page: FootballPage, matchesList: MatchesList, filters: Map[String, Seq[CompetitionFilter]])( +@import model.content.InteractiveAtom +@(page: FootballPage, matchesList: MatchesList, filters: Map[String, Seq[CompetitionFilter]], maybeAtom: Option[InteractiveAtom])( implicit request: RequestHeader, context: ApplicationContext ) @@ -13,6 +14,11 @@
+ @maybeAtom.map{ atom => +
+ @views.html.fragments.atoms.interactive(atom, shouldFence = false) +
+ }

diff --git a/sport/app/football/views/tablesList/tablesPage.scala.html b/sport/app/football/views/tablesList/tablesPage.scala.html index 250f3e44b5a..bd02473e239 100644 --- a/sport/app/football/views/tablesList/tablesPage.scala.html +++ b/sport/app/football/views/tablesList/tablesPage.scala.html @@ -8,6 +8,11 @@
+ @page.atom.map{ atom => +
+ @views.html.fragments.atoms.interactive(atom, shouldFence = false) +
+ }
<@if(!page.singleCompetition){h1}else{h2} class="hide-on-mobile-if-localnav content__inline-section page-heading--football"> diff --git a/sport/app/football/views/wallchart/embed.scala.html b/sport/app/football/views/wallchart/embed.scala.html index d673a627db4..2e098f49539 100644 --- a/sport/app/football/views/wallchart/embed.scala.html +++ b/sport/app/football/views/wallchart/embed.scala.html @@ -8,7 +8,7 @@
- @wallchart(competition, competitionStages, next) + @wallchart(competition, competitionStages, next, None) @fragments.analytics.base()(page, request, context)
diff --git a/sport/app/football/views/wallchart/page.scala.html b/sport/app/football/views/wallchart/page.scala.html index 7f495b6ac94..9ab5816ef5b 100644 --- a/sport/app/football/views/wallchart/page.scala.html +++ b/sport/app/football/views/wallchart/page.scala.html @@ -1,9 +1,10 @@ @import _root_.football.model.CompetitionStageLike @import model.{Competition, Page} +@import model.content.InteractiveAtom -@(page: Page, competition: Competition, competitionStages: List[CompetitionStageLike], next: Option[pa.FootballMatch])(implicit request: RequestHeader, context: model.ApplicationContext) +@(page: Page, competition: Competition, competitionStages: List[CompetitionStageLike], next: Option[pa.FootballMatch], maybeAtom: Option[InteractiveAtom])(implicit request: RequestHeader, context: model.ApplicationContext) @mainLegacy(page, Some("football")){ }{ - @wallchart(competition, competitionStages, next) + @wallchart(competition, competitionStages, next, maybeAtom) } diff --git a/sport/app/football/views/wallchart/wallchart.scala.html b/sport/app/football/views/wallchart/wallchart.scala.html index f942dd3bc23..2331287959a 100644 --- a/sport/app/football/views/wallchart/wallchart.scala.html +++ b/sport/app/football/views/wallchart/wallchart.scala.html @@ -2,10 +2,16 @@ @import model.Competition @import conf.switches.Switches @import conf.Configuration +@import model.ApplicationContext +@import model.content.InteractiveAtom -@(competition: Competition, competitionStages: List[CompetitionStageLike], next: Option[pa.FootballMatch])(implicit request: RequestHeader) -
- +@(competition: Competition, competitionStages: List[CompetitionStageLike], next: Option[pa.FootballMatch], maybeAtom: Option[InteractiveAtom])(implicit request: RequestHeader, context: ApplicationContext) +
+ @maybeAtom.map{ atom => +
+ @views.html.fragments.atoms.interactive(atom, shouldFence = false) +
+ } @competitionStages.map { case knockoutStage: _root_.football.model.KnockoutSpider => {
diff --git a/sport/conf/routes b/sport/conf/routes index 8b5b072870e..17241b70979 100644 --- a/sport/conf/routes +++ b/sport/conf/routes @@ -23,8 +23,8 @@ GET /football/:tag/fixtures/more/:year/:month/:day.json GET /football/:tag/fixtures/more/:year/:month/:day football.controllers.FixturesController.moreTagFixturesFor(year, month, day, tag) GET /football/:tag/fixtures/:year/:month/:day.json football.controllers.FixturesController.tagFixturesForJson(year, month, day, tag) GET /football/:tag/fixtures/:year/:month/:day football.controllers.FixturesController.tagFixturesFor(year, month, day, tag) -GET /football/:tag/fixtures football.controllers.FixturesController.tagFixturesJson(tag) -GET /football/:tag/fixtures.json football.controllers.FixturesController.tagFixtures(tag) +GET /football/:tag/fixtures football.controllers.FixturesController.tagFixtures(tag) +GET /football/:tag/fixtures.json football.controllers.FixturesController.tagFixturesJson(tag) GET /football/results/:year/:month/:day.json football.controllers.ResultsController.allResultsForJson(year, month, day) GET /football/results/:year/:month/:day football.controllers.ResultsController.allResultsFor(year, month, day) diff --git a/sport/test/LeagueTablesFeatureTest.scala b/sport/test/LeagueTablesFeatureTest.scala index cb9f1d79ea1..6cd441e717c 100644 --- a/sport/test/LeagueTablesFeatureTest.scala +++ b/sport/test/LeagueTablesFeatureTest.scala @@ -18,7 +18,8 @@ import org.scalatest.matchers.should.Matchers with BeforeAndAfterAll with WithMaterializer with WithTestApplicationContext - with WithTestWsClient { + with WithTestWsClient + with WithTestContentApiClient { Feature("League Tables") { @@ -67,7 +68,11 @@ import org.scalatest.matchers.should.Matchers Scenario("Should redirect when no competition table data found") { val leagueTableController = - new LeagueTableController(testCompetitionsService, play.api.test.Helpers.stubControllerComponents()) + new LeagueTableController( + testCompetitionsService, + play.api.test.Helpers.stubControllerComponents(), + testContentApiClient, + ) val result = leagueTableController.renderCompetition("sfgsfgsfg")(FakeRequest()) status(result) should be(303) } diff --git a/sport/test/controllers/FixturesControllerTest.scala b/sport/test/controllers/FixturesControllerTest.scala index efd511379d2..e20cbf27fc8 100644 --- a/sport/test/controllers/FixturesControllerTest.scala +++ b/sport/test/controllers/FixturesControllerTest.scala @@ -17,14 +17,19 @@ import org.scalatest.matchers.should.Matchers with WithMaterializer with BeforeAndAfterAll with WithTestApplicationContext - with WithTestWsClient { + with WithTestWsClient + with WithTestContentApiClient { val fixturesUrl = "/football/fixtures" val fixtureForUrl = "/football/fixtures/2012/oct/20" val tag = "premierleague" lazy val fixturesController = - new FixturesController(testCompetitionsService, play.api.test.Helpers.stubControllerComponents()) + new FixturesController( + testCompetitionsService, + play.api.test.Helpers.stubControllerComponents(), + testContentApiClient, + ) "can load the all fixtures page" in { val result = fixturesController.allFixtures()(TestRequest()) diff --git a/sport/test/controllers/LeagueTableControllerTest.scala b/sport/test/controllers/LeagueTableControllerTest.scala index c541e479152..2b9c30c7af1 100644 --- a/sport/test/controllers/LeagueTableControllerTest.scala +++ b/sport/test/controllers/LeagueTableControllerTest.scala @@ -17,10 +17,15 @@ import org.scalatest.{BeforeAndAfterAll, DoNotDiscover} with BeforeAndAfterAll with WithTestApplicationContext with WithTestExecutionContext - with WithTestWsClient { + with WithTestWsClient + with WithTestContentApiClient { lazy val leagueTableController = - new LeagueTableController(testCompetitionsService, play.api.test.Helpers.stubControllerComponents()) + new LeagueTableController( + testCompetitionsService, + play.api.test.Helpers.stubControllerComponents(), + testContentApiClient, + ) "League Table Controller" should "200 when content type is table" in { val result = leagueTableController.renderLeagueTables()(TestRequest())