github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/web/elm/tests/PipelineCardTests.elm (about)

     1  module PipelineCardTests exposing (all)
     2  
     3  import Application.Application as Application
     4  import Assets
     5  import ColorValues
     6  import Colors
     7  import Common exposing (defineHoverBehaviour, isColorWithStripes)
     8  import Concourse
     9  import Concourse.BuildStatus exposing (BuildStatus(..))
    10  import Concourse.PipelineStatus exposing (PipelineStatus(..), StatusDetails(..))
    11  import DashboardTests
    12      exposing
    13          ( afterSeconds
    14          , amber
    15          , apiData
    16          , blue
    17          , brown
    18          , circularJobs
    19          , darkGrey
    20          , fadedGreen
    21          , givenDataAndUser
    22          , givenDataUnauthenticated
    23          , green
    24          , iconSelector
    25          , job
    26          , jobWithNameTransitionedAt
    27          , lightGrey
    28          , middleGrey
    29          , orange
    30          , otherJob
    31          , red
    32          , running
    33          , userWithRoles
    34          , whenOnDashboard
    35          , whenOnDashboardViewingAllPipelines
    36          , white
    37          )
    38  import Data
    39  import Expect exposing (Expectation)
    40  import Html.Attributes as Attr
    41  import Message.Callback as Callback
    42  import Message.Effects as Effects
    43  import Message.Message as Msgs exposing (DomID(..), PipelinesSection(..))
    44  import Message.Subscription exposing (Delivery(..), Interval(..))
    45  import Message.TopLevelMessage as ApplicationMsgs
    46  import Set
    47  import Test exposing (Test, describe, test)
    48  import Test.Html.Event as Event
    49  import Test.Html.Query as Query
    50  import Test.Html.Selector exposing (attribute, class, containing, style, tag, text)
    51  import Time
    52  
    53  
    54  all : Test
    55  all =
    56      describe "pipeline cards" <|
    57          let
    58              findHeader :
    59                  Query.Single ApplicationMsgs.TopLevelMessage
    60                  -> Query.Single ApplicationMsgs.TopLevelMessage
    61              findHeader =
    62                  Query.find [ class "card-header" ]
    63  
    64              findBody :
    65                  Query.Single ApplicationMsgs.TopLevelMessage
    66                  -> Query.Single ApplicationMsgs.TopLevelMessage
    67              findBody =
    68                  Query.find [ class "card-body" ]
    69  
    70              pipelineWithStatus :
    71                  BuildStatus
    72                  -> Bool
    73                  -> Application.Model
    74                  -> Query.Single ApplicationMsgs.TopLevelMessage
    75              pipelineWithStatus status isRunning =
    76                  let
    77                      jobFunc =
    78                          if isRunning then
    79                              job >> running
    80  
    81                          else
    82                              job
    83                  in
    84                  Application.handleCallback
    85                      (Callback.AllJobsFetched <| Ok [ jobFunc status ])
    86                      >> Tuple.first
    87                      >> givenDataUnauthenticated [ { id = 0, name = "team" } ]
    88                      >> Tuple.first
    89                      >> Application.handleCallback
    90                          (Callback.AllPipelinesFetched <|
    91                              Ok
    92                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
    93                          )
    94                      >> Tuple.first
    95                      >> Application.handleDelivery
    96                          (ClockTicked OneSecond <| Time.millisToPosix 0)
    97                      >> Tuple.first
    98                      >> Common.queryView
    99          in
   100          [ describe "when team has no visible pipelines" <|
   101              let
   102                  noPipelinesCard : () -> Query.Single ApplicationMsgs.TopLevelMessage
   103                  noPipelinesCard _ =
   104                      whenOnDashboard { highDensity = False }
   105                          |> givenDataUnauthenticated
   106                              (apiData
   107                                  [ ( "some-team", [] )
   108                                  , ( "other-team", [] )
   109                                  ]
   110                              )
   111                          |> Tuple.first
   112                          |> Application.handleCallback
   113                              (Callback.AllPipelinesFetched <|
   114                                  Ok
   115                                      [ Data.pipeline "other-team" 0 |> Data.withName "pipeline" ]
   116                              )
   117                          |> Tuple.first
   118                          |> Common.queryView
   119                          |> Query.find
   120                              [ class "dashboard-team-group"
   121                              , attribute <|
   122                                  Attr.attribute "data-team-name"
   123                                      "some-team"
   124                              ]
   125                          |> Query.find [ class "card" ]
   126              in
   127              [ describe "card" <|
   128                  [ test "card has display flex with direction column" <|
   129                      noPipelinesCard
   130                          >> Query.has
   131                              [ style "display" "flex"
   132                              , style "flex-direction" "column"
   133                              ]
   134                  , test "card has width 272px and height 268px" <|
   135                      noPipelinesCard
   136                          >> Query.has
   137                              [ style "width" "272px"
   138                              , style "height" "268px"
   139                              ]
   140                  , test "card has a left margin of 25px" <|
   141                      noPipelinesCard
   142                          >> Query.has
   143                              [ style "margin-left" "25px" ]
   144                  ]
   145              , describe "header" <|
   146                  let
   147                      header : () -> Query.Single ApplicationMsgs.TopLevelMessage
   148                      header =
   149                          noPipelinesCard
   150                              >> findHeader
   151                  in
   152                  [ test "says 'no pipeline set' in white font" <|
   153                      header
   154                          >> Expect.all
   155                              [ Query.has [ text "no pipeline set" ]
   156                              , Query.has [ style "color" ColorValues.grey20 ]
   157                              ]
   158                  , test "has dark grey background and 12.5px padding" <|
   159                      header
   160                          >> Query.has
   161                              [ style "background-color" ColorValues.grey90
   162                              , style "padding" "12.5px"
   163                              ]
   164                  , test "text is larger and wider spaced" <|
   165                      header
   166                          >> Query.has
   167                              [ style "font-size" "1.5em"
   168                              , style "letter-spacing" "0.1em"
   169                              ]
   170                  , test "text is centered" <|
   171                      header
   172                          >> Query.has [ style "text-align" "center" ]
   173                  ]
   174              , describe "body" <|
   175                  let
   176                      body : () -> Query.Single ApplicationMsgs.TopLevelMessage
   177                      body =
   178                          noPipelinesCard
   179                              >> Query.find [ class "card-body" ]
   180                  in
   181                  [ test "has 20px 36px padding" <|
   182                      body
   183                          >> Query.has
   184                              [ style "padding" "20px 36px" ]
   185                  , test "fills available height" <|
   186                      body
   187                          >> Query.has [ style "flex-grow" "1" ]
   188                  , test "has dark grey background" <|
   189                      body
   190                          >> Query.has [ style "background-color" ColorValues.grey90 ]
   191                  , test "has 2px margins above and below" <|
   192                      body
   193                          >> Query.has [ style "margin" "2px 0" ]
   194                  , test "has lighter grey placeholder box that fills" <|
   195                      body
   196                          >> Expect.all
   197                              [ Query.has [ style "display" "flex" ]
   198                              , Query.children []
   199                                  >> Query.first
   200                                  >> Query.has
   201                                      [ style "background-color" ColorValues.grey80
   202                                      , style "flex-grow" "1"
   203                                      ]
   204                              ]
   205                  ]
   206              , test "footer is dark grey and 47 pixels tall" <|
   207                  noPipelinesCard
   208                      >> Query.find [ class "card-footer" ]
   209                      >> Query.has
   210                          [ style "background-color" ColorValues.grey90
   211                          , style "height" "47px"
   212                          ]
   213              ]
   214          , test "is draggable when in all pipelines section and result is not stale" <|
   215              \_ ->
   216                  whenOnDashboard { highDensity = False }
   217                      |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
   218                      |> Tuple.first
   219                      |> Application.handleCallback
   220                          (Callback.AllPipelinesFetched <|
   221                              Ok
   222                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   223                          )
   224                      |> Tuple.first
   225                      |> Common.queryView
   226                      |> Query.find
   227                          [ class "card"
   228                          , containing [ text "pipeline" ]
   229                          ]
   230                      |> Expect.all
   231                          [ Query.has [ attribute <| Attr.attribute "draggable" "true" ]
   232                          , Query.has [ style "cursor" "move" ]
   233                          ]
   234          , test "is not draggable when in favorites section" <|
   235              \_ ->
   236                  whenOnDashboard { highDensity = False }
   237                      |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
   238                      |> Tuple.first
   239                      |> Application.handleCallback
   240                          (Callback.AllPipelinesFetched <|
   241                              Ok
   242                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   243                          )
   244                      |> Tuple.first
   245                      |> Application.handleDelivery
   246                          (FavoritedPipelinesReceived <| Ok <| Set.singleton 0)
   247                      |> Tuple.first
   248                      |> Common.queryView
   249                      |> Query.findAll
   250                          [ class "card"
   251                          , containing [ text "pipeline" ]
   252                          ]
   253                      |> Query.first
   254                      |> Expect.all
   255                          [ Query.hasNot [ attribute <| Attr.attribute "draggable" "true" ]
   256                          , Query.hasNot [ style "cursor" "move" ]
   257                          ]
   258          , test "is not draggable when rendering based on the cache" <|
   259              \_ ->
   260                  whenOnDashboard { highDensity = False }
   261                      |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
   262                      |> Tuple.first
   263                      |> Application.handleDelivery
   264                          (CachedPipelinesReceived <|
   265                              Ok
   266                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   267                          )
   268                      |> Tuple.first
   269                      |> Common.queryView
   270                      |> Query.find
   271                          [ class "card"
   272                          , containing [ text "pipeline" ]
   273                          ]
   274                      |> Expect.all
   275                          [ Query.hasNot [ attribute <| Attr.attribute "draggable" "true" ]
   276                          , Query.hasNot [ style "cursor" "move" ]
   277                          ]
   278          , test "fills available space" <|
   279              \_ ->
   280                  whenOnDashboard { highDensity = False }
   281                      |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
   282                      |> Tuple.first
   283                      |> Application.handleCallback
   284                          (Callback.AllPipelinesFetched <|
   285                              Ok
   286                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   287                          )
   288                      |> Tuple.first
   289                      |> Common.queryView
   290                      |> Query.find
   291                          [ class "card"
   292                          , containing [ text "pipeline" ]
   293                          ]
   294                      |> Query.has
   295                          [ style "width" "100%"
   296                          , style "height" "100%"
   297                          , style "display" "flex"
   298                          , style "flex-direction" "column"
   299                          ]
   300          , describe "header" <|
   301              let
   302                  header : () -> Query.Single ApplicationMsgs.TopLevelMessage
   303                  header _ =
   304                      whenOnDashboard { highDensity = False }
   305                          |> givenDataUnauthenticated
   306                              (apiData [ ( "team", [] ) ])
   307                          |> Tuple.first
   308                          |> Application.handleCallback
   309                              (Callback.AllPipelinesFetched <|
   310                                  Ok
   311                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   312                              )
   313                          |> Tuple.first
   314                          |> Common.queryView
   315                          |> Query.find
   316                              [ class "card"
   317                              , containing [ text "pipeline" ]
   318                              ]
   319                          |> findHeader
   320              in
   321              [ test "has dark grey background" <|
   322                  header
   323                      >> Query.has [ style "background-color" ColorValues.grey90 ]
   324              , test "has larger, spaced-out white text" <|
   325                  header
   326                      >> Query.has
   327                          [ style "font-size" "1.5em"
   328                          , style "letter-spacing" "0.1em"
   329                          , style "color" ColorValues.grey20
   330                          ]
   331              , test "has 12.5px padding" <|
   332                  header
   333                      >> Query.has [ style "padding" "12.5px" ]
   334              , test "text does not overflow or wrap" <|
   335                  header
   336                      >> Query.children []
   337                      >> Query.first
   338                      >> Query.has
   339                          [ style "width" "245px"
   340                          , style "white-space" "nowrap"
   341                          , style "overflow" "hidden"
   342                          , style "text-overflow" "ellipsis"
   343                          ]
   344              ]
   345          , describe "colored banner" <|
   346              let
   347                  findBanner =
   348                      Query.find
   349                          [ class "card"
   350                          , containing [ text "pipeline" ]
   351                          ]
   352                          >> Query.find
   353                              [ class "banner" ]
   354  
   355                  isSolid : String -> Query.Single ApplicationMsgs.TopLevelMessage -> Expectation
   356                  isSolid color =
   357                      Query.has [ style "background-color" color ]
   358              in
   359              [ describe "non-HD view"
   360                  [ test "is 7px tall" <|
   361                      \_ ->
   362                          whenOnDashboard { highDensity = False }
   363                              |> givenDataUnauthenticated
   364                                  (apiData [ ( "team", [] ) ])
   365                              |> Tuple.first
   366                              |> Application.handleCallback
   367                                  (Callback.AllPipelinesFetched <|
   368                                      Ok
   369                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   370                                  )
   371                              |> Tuple.first
   372                              |> Common.queryView
   373                              |> findBanner
   374                              |> Query.has [ style "height" "7px" ]
   375                  , test "is grey when pipeline is cached" <|
   376                      \_ ->
   377                          whenOnDashboard { highDensity = False }
   378                              |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   379                              |> Tuple.first
   380                              |> Application.handleDelivery
   381                                  (CachedPipelinesReceived <|
   382                                      Ok
   383                                          [ Data.pipeline "team" 0
   384                                              |> Data.withName "pipeline"
   385                                              |> Data.withPaused True
   386                                          ]
   387                                  )
   388                              |> Tuple.first
   389                              |> Common.queryView
   390                              |> findBanner
   391                              |> isSolid lightGrey
   392                  , test "is dark grey when pipeline is archived" <|
   393                      \_ ->
   394                          whenOnDashboardViewingAllPipelines { highDensity = False }
   395                              |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   396                              |> Tuple.first
   397                              |> Application.handleCallback
   398                                  (Callback.AllPipelinesFetched <|
   399                                      Ok
   400                                          [ Data.pipeline "team" 0
   401                                              |> Data.withName "pipeline"
   402                                              |> Data.withArchived True
   403                                              |> Data.withPaused True
   404                                          ]
   405                                  )
   406                              |> Tuple.first
   407                              |> Common.queryView
   408                              |> findBanner
   409                              |> isSolid Colors.backgroundDark
   410                  , test "is blue when pipeline is paused" <|
   411                      \_ ->
   412                          whenOnDashboard { highDensity = False }
   413                              |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   414                              |> Tuple.first
   415                              |> Application.handleCallback
   416                                  (Callback.AllPipelinesFetched <|
   417                                      Ok
   418                                          [ Data.pipeline "team" 0
   419                                              |> Data.withName "pipeline"
   420                                              |> Data.withPaused True
   421                                          ]
   422                                  )
   423                              |> Tuple.first
   424                              |> Common.queryView
   425                              |> findBanner
   426                              |> isSolid blue
   427                  , test "is green when pipeline is succeeding" <|
   428                      \_ ->
   429                          whenOnDashboard { highDensity = False }
   430                              |> pipelineWithStatus
   431                                  BuildStatusSucceeded
   432                                  False
   433                              |> findBanner
   434                              |> isSolid green
   435                  , test "is green with black stripes when pipeline is succeeding and running" <|
   436                      \_ ->
   437                          whenOnDashboard { highDensity = False }
   438                              |> pipelineWithStatus
   439                                  BuildStatusSucceeded
   440                                  True
   441                              |> findBanner
   442                              |> isColorWithStripes { thin = green, thick = ColorValues.grey90 }
   443                  , test "is grey when pipeline is pending" <|
   444                      \_ ->
   445                          whenOnDashboard { highDensity = False }
   446                              |> givenDataUnauthenticated
   447                                  (apiData [ ( "team", [] ) ])
   448                              |> Tuple.first
   449                              |> Application.handleCallback
   450                                  (Callback.AllPipelinesFetched <|
   451                                      Ok
   452                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   453                                  )
   454                              |> Tuple.first
   455                              |> Common.queryView
   456                              |> findBanner
   457                              |> isSolid lightGrey
   458                  , test "is grey with black stripes when pipeline is pending and running" <|
   459                      \_ ->
   460                          whenOnDashboard { highDensity = False }
   461                              |> pipelineWithStatus
   462                                  BuildStatusStarted
   463                                  True
   464                              |> findBanner
   465                              |> isColorWithStripes { thin = lightGrey, thick = ColorValues.grey90 }
   466                  , test "is red when pipeline is failing" <|
   467                      \_ ->
   468                          whenOnDashboard { highDensity = False }
   469                              |> pipelineWithStatus
   470                                  BuildStatusFailed
   471                                  False
   472                              |> findBanner
   473                              |> isSolid red
   474                  , test "is red with black stripes when pipeline is failing and running" <|
   475                      \_ ->
   476                          whenOnDashboard { highDensity = False }
   477                              |> pipelineWithStatus
   478                                  BuildStatusFailed
   479                                  True
   480                              |> findBanner
   481                              |> isColorWithStripes { thin = red, thick = ColorValues.grey90 }
   482                  , test "is amber when pipeline is erroring" <|
   483                      \_ ->
   484                          whenOnDashboard { highDensity = False }
   485                              |> pipelineWithStatus
   486                                  BuildStatusErrored
   487                                  False
   488                              |> findBanner
   489                              |> isSolid amber
   490                  , test "is amber with black stripes when pipeline is erroring and running" <|
   491                      \_ ->
   492                          whenOnDashboard { highDensity = False }
   493                              |> pipelineWithStatus
   494                                  BuildStatusErrored
   495                                  True
   496                              |> findBanner
   497                              |> isColorWithStripes { thin = amber, thick = ColorValues.grey90 }
   498                  , test "is brown when pipeline is aborted" <|
   499                      \_ ->
   500                          whenOnDashboard { highDensity = False }
   501                              |> pipelineWithStatus
   502                                  BuildStatusAborted
   503                                  False
   504                              |> findBanner
   505                              |> isSolid brown
   506                  , test "is brown with black stripes when pipeline is aborted and running" <|
   507                      \_ ->
   508                          whenOnDashboard { highDensity = False }
   509                              |> pipelineWithStatus
   510                                  BuildStatusAborted
   511                                  True
   512                              |> findBanner
   513                              |> isColorWithStripes { thin = brown, thick = ColorValues.grey90 }
   514                  , describe "status priorities" <|
   515                      let
   516                          givenTwoJobsWithModifiers :
   517                              BuildStatus
   518                              -> (Concourse.Job -> Concourse.Job)
   519                              -> BuildStatus
   520                              -> (Concourse.Job -> Concourse.Job)
   521                              -> Query.Single ApplicationMsgs.TopLevelMessage
   522                          givenTwoJobsWithModifiers firstStatus firstModifier secondStatus secondModifier =
   523                              whenOnDashboard { highDensity = False }
   524                                  |> Application.handleCallback
   525                                      (Callback.AllJobsFetched <|
   526                                          Ok
   527                                              [ job firstStatus |> firstModifier
   528                                              , otherJob secondStatus |> secondModifier
   529                                              ]
   530                                      )
   531                                  |> Tuple.first
   532                                  |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   533                                  |> Tuple.first
   534                                  |> Application.handleCallback
   535                                      (Callback.AllPipelinesFetched <|
   536                                          Ok
   537                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   538                                      )
   539                                  |> Tuple.first
   540                                  |> Common.queryView
   541  
   542                          givenTwoJobs :
   543                              BuildStatus
   544                              -> BuildStatus
   545                              -> Query.Single ApplicationMsgs.TopLevelMessage
   546                          givenTwoJobs firstStatus secondStatus =
   547                              givenTwoJobsWithModifiers firstStatus identity secondStatus identity
   548                      in
   549                      [ test "failed is more important than errored" <|
   550                          \_ ->
   551                              givenTwoJobs
   552                                  BuildStatusFailed
   553                                  BuildStatusErrored
   554                                  |> findBanner
   555                                  |> isSolid red
   556                      , test "errored is more important than aborted" <|
   557                          \_ ->
   558                              givenTwoJobs
   559                                  BuildStatusErrored
   560                                  BuildStatusAborted
   561                                  |> findBanner
   562                                  |> isSolid amber
   563                      , test "aborted is more important than succeeding" <|
   564                          \_ ->
   565                              givenTwoJobs
   566                                  BuildStatusAborted
   567                                  BuildStatusSucceeded
   568                                  |> findBanner
   569                                  |> isSolid brown
   570                      , test "succeeding is more important than pending" <|
   571                          \_ ->
   572                              givenTwoJobs
   573                                  BuildStatusSucceeded
   574                                  BuildStatusPending
   575                                  |> findBanner
   576                                  |> isSolid green
   577                      , test "paused jobs are ignored" <|
   578                          \_ ->
   579                              givenTwoJobsWithModifiers
   580                                  BuildStatusSucceeded
   581                                  identity
   582                                  BuildStatusFailed
   583                                  (Data.withPaused True)
   584                                  |> findBanner
   585                                  |> isSolid green
   586                      ]
   587                  , test "does not crash with a circular pipeline" <|
   588                      \_ ->
   589                          whenOnDashboard { highDensity = False }
   590                              |> Application.handleCallback (Callback.AllJobsFetched <| Ok circularJobs)
   591                              |> Tuple.first
   592                              |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   593                              |> Tuple.first
   594                              |> Application.handleCallback
   595                                  (Callback.AllPipelinesFetched <|
   596                                      Ok
   597                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   598                                  )
   599                              |> Tuple.first
   600                              |> Common.queryView
   601                              |> findBanner
   602                              |> isSolid green
   603                  , describe "HD view"
   604                      [ test "is 8px wide" <|
   605                          \_ ->
   606                              whenOnDashboard { highDensity = True }
   607                                  |> givenDataUnauthenticated
   608                                      (apiData [ ( "team", [] ) ])
   609                                  |> Tuple.first
   610                                  |> Application.handleCallback
   611                                      (Callback.AllPipelinesFetched <|
   612                                          Ok
   613                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   614                                      )
   615                                  |> Tuple.first
   616                                  |> Common.queryView
   617                                  |> findBanner
   618                                  |> Query.has [ style "width" "8px" ]
   619                      , test "is grey when pipeline is cached" <|
   620                          \_ ->
   621                              whenOnDashboard { highDensity = True }
   622                                  |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   623                                  |> Tuple.first
   624                                  |> Application.handleDelivery
   625                                      (CachedPipelinesReceived <|
   626                                          Ok
   627                                              [ Data.pipeline "team" 0
   628                                                  |> Data.withName "pipeline"
   629                                                  |> Data.withPaused True
   630                                              ]
   631                                      )
   632                                  |> Tuple.first
   633                                  |> Common.queryView
   634                                  |> findBanner
   635                                  |> isSolid lightGrey
   636                      , test "is dark grey when pipeline is archived" <|
   637                          \_ ->
   638                              whenOnDashboardViewingAllPipelines { highDensity = False }
   639                                  |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   640                                  |> Tuple.first
   641                                  |> Application.handleCallback
   642                                      (Callback.AllPipelinesFetched <|
   643                                          Ok
   644                                              [ Data.pipeline "team" 0
   645                                                  |> Data.withName "pipeline"
   646                                                  |> Data.withArchived True
   647                                                  |> Data.withPaused True
   648                                              ]
   649                                      )
   650                                  |> Tuple.first
   651                                  |> Common.queryView
   652                                  |> findBanner
   653                                  |> isSolid Colors.backgroundDark
   654                      , test "is blue when pipeline is paused" <|
   655                          \_ ->
   656                              whenOnDashboard { highDensity = True }
   657                                  |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   658                                  |> Tuple.first
   659                                  |> Application.handleCallback
   660                                      (Callback.AllPipelinesFetched <|
   661                                          Ok
   662                                              [ Data.pipeline "team" 0
   663                                                  |> Data.withName "pipeline"
   664                                                  |> Data.withPaused True
   665                                              ]
   666                                      )
   667                                  |> Tuple.first
   668                                  |> Common.queryView
   669                                  |> findBanner
   670                                  |> isSolid blue
   671                      , test "is green when pipeline is succeeding" <|
   672                          \_ ->
   673                              whenOnDashboard { highDensity = True }
   674                                  |> pipelineWithStatus
   675                                      BuildStatusSucceeded
   676                                      False
   677                                  |> findBanner
   678                                  |> isSolid green
   679                      , test "is green with black stripes when pipeline is succeeding and running" <|
   680                          \_ ->
   681                              whenOnDashboard { highDensity = True }
   682                                  |> pipelineWithStatus
   683                                      BuildStatusSucceeded
   684                                      True
   685                                  |> findBanner
   686                                  |> isColorWithStripes { thin = green, thick = ColorValues.grey90 }
   687                      , test "is grey when pipeline is pending" <|
   688                          \_ ->
   689                              whenOnDashboard { highDensity = True }
   690                                  |> givenDataUnauthenticated
   691                                      (apiData [ ( "team", [] ) ])
   692                                  |> Tuple.first
   693                                  |> Application.handleCallback
   694                                      (Callback.AllPipelinesFetched <|
   695                                          Ok
   696                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   697                                      )
   698                                  |> Tuple.first
   699                                  |> Common.queryView
   700                                  |> findBanner
   701                                  |> isSolid lightGrey
   702                      , test "is grey with black stripes when pipeline is pending and running" <|
   703                          \_ ->
   704                              whenOnDashboard { highDensity = True }
   705                                  |> pipelineWithStatus
   706                                      BuildStatusStarted
   707                                      True
   708                                  |> findBanner
   709                                  |> isColorWithStripes { thin = lightGrey, thick = ColorValues.grey90 }
   710                      , test "is red when pipeline is failing" <|
   711                          \_ ->
   712                              whenOnDashboard { highDensity = True }
   713                                  |> pipelineWithStatus
   714                                      BuildStatusFailed
   715                                      False
   716                                  |> findBanner
   717                                  |> isSolid red
   718                      , test "is red with black stripes when pipeline is failing and running" <|
   719                          \_ ->
   720                              whenOnDashboard { highDensity = True }
   721                                  |> pipelineWithStatus
   722                                      BuildStatusFailed
   723                                      True
   724                                  |> findBanner
   725                                  |> isColorWithStripes { thin = red, thick = ColorValues.grey90 }
   726                      , test "is amber when pipeline is erroring" <|
   727                          \_ ->
   728                              whenOnDashboard { highDensity = True }
   729                                  |> pipelineWithStatus
   730                                      BuildStatusErrored
   731                                      False
   732                                  |> findBanner
   733                                  |> isSolid amber
   734                      , test "is amber with black stripes when pipeline is erroring and running" <|
   735                          \_ ->
   736                              whenOnDashboard { highDensity = True }
   737                                  |> pipelineWithStatus
   738                                      BuildStatusErrored
   739                                      True
   740                                  |> findBanner
   741                                  |> isColorWithStripes { thin = amber, thick = ColorValues.grey90 }
   742                      , test "is brown when pipeline is aborted" <|
   743                          \_ ->
   744                              whenOnDashboard { highDensity = True }
   745                                  |> pipelineWithStatus
   746                                      BuildStatusAborted
   747                                      False
   748                                  |> findBanner
   749                                  |> isSolid brown
   750                      , test "is brown with black stripes when pipeline is aborted and running" <|
   751                          \_ ->
   752                              whenOnDashboard { highDensity = True }
   753                                  |> pipelineWithStatus
   754                                      BuildStatusAborted
   755                                      True
   756                                  |> findBanner
   757                                  |> isColorWithStripes { thin = brown, thick = ColorValues.grey90 }
   758                      , describe "status priorities" <|
   759                          let
   760                              givenTwoJobsWithModifiers :
   761                                  BuildStatus
   762                                  -> (Concourse.Job -> Concourse.Job)
   763                                  -> BuildStatus
   764                                  -> (Concourse.Job -> Concourse.Job)
   765                                  -> Query.Single ApplicationMsgs.TopLevelMessage
   766                              givenTwoJobsWithModifiers firstStatus firstModifier secondStatus secondModifier =
   767                                  whenOnDashboard { highDensity = True }
   768                                      |> Application.handleCallback
   769                                          (Callback.AllJobsFetched <|
   770                                              Ok
   771                                                  [ job firstStatus |> firstModifier
   772                                                  , otherJob secondStatus |> secondModifier
   773                                                  ]
   774                                          )
   775                                      |> Tuple.first
   776                                      |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   777                                      |> Tuple.first
   778                                      |> Application.handleCallback
   779                                          (Callback.AllPipelinesFetched <|
   780                                              Ok
   781                                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   782                                          )
   783                                      |> Tuple.first
   784                                      |> Common.queryView
   785  
   786                              givenTwoJobs :
   787                                  BuildStatus
   788                                  -> BuildStatus
   789                                  -> Query.Single ApplicationMsgs.TopLevelMessage
   790                              givenTwoJobs firstStatus secondStatus =
   791                                  givenTwoJobsWithModifiers firstStatus identity secondStatus identity
   792                          in
   793                          [ test "failed is more important than errored" <|
   794                              \_ ->
   795                                  givenTwoJobs
   796                                      BuildStatusFailed
   797                                      BuildStatusErrored
   798                                      |> findBanner
   799                                      |> isSolid red
   800                          , test "errored is more important than aborted" <|
   801                              \_ ->
   802                                  givenTwoJobs
   803                                      BuildStatusErrored
   804                                      BuildStatusAborted
   805                                      |> findBanner
   806                                      |> isSolid amber
   807                          , test "aborted is more important than succeeding" <|
   808                              \_ ->
   809                                  givenTwoJobs
   810                                      BuildStatusAborted
   811                                      BuildStatusSucceeded
   812                                      |> findBanner
   813                                      |> isSolid brown
   814                          , test "succeeding is more important than pending" <|
   815                              \_ ->
   816                                  givenTwoJobs
   817                                      BuildStatusSucceeded
   818                                      BuildStatusPending
   819                                      |> findBanner
   820                                      |> isSolid green
   821                          , test "paused jobs are ignored" <|
   822                              \_ ->
   823                                  givenTwoJobsWithModifiers
   824                                      BuildStatusSucceeded
   825                                      identity
   826                                      BuildStatusFailed
   827                                      (Data.withPaused True)
   828                                      |> findBanner
   829                                      |> isSolid green
   830                          ]
   831                      ]
   832                  ]
   833              ]
   834          , describe "on HD view" <|
   835              let
   836                  setup : () -> Query.Single ApplicationMsgs.TopLevelMessage
   837                  setup _ =
   838                      whenOnDashboard { highDensity = True }
   839                          |> givenDataUnauthenticated
   840                              (apiData [ ( "team", [] ) ])
   841                          |> Tuple.first
   842                          |> Application.handleCallback
   843                              (Callback.AllPipelinesFetched <|
   844                                  Ok
   845                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   846                              )
   847                          |> Tuple.first
   848                          |> Common.queryView
   849  
   850                  noPipelines : () -> Query.Single ApplicationMsgs.TopLevelMessage
   851                  noPipelines _ =
   852                      whenOnDashboard { highDensity = True }
   853                          |> givenDataUnauthenticated
   854                              (apiData
   855                                  [ ( "some-team", [] )
   856                                  , ( "other-team", [] )
   857                                  ]
   858                              )
   859                          |> Tuple.first
   860                          |> Application.handleCallback
   861                              (Callback.AllPipelinesFetched <|
   862                                  Ok
   863                                      [ Data.pipeline "other-team" 0 |> Data.withName "pipeline" ]
   864                              )
   865                          |> Tuple.first
   866                          |> Common.queryView
   867  
   868                  card : Query.Single ApplicationMsgs.TopLevelMessage -> Query.Single ApplicationMsgs.TopLevelMessage
   869                  card =
   870                      Query.find
   871                          [ class "card"
   872                          , containing [ text "pipeline" ]
   873                          ]
   874  
   875                  cardText : Query.Single ApplicationMsgs.TopLevelMessage -> Query.Single ApplicationMsgs.TopLevelMessage
   876                  cardText =
   877                      card
   878                          >> Query.children []
   879                          >> Query.index 1
   880  
   881                  noPipelinesCard =
   882                      Query.find
   883                          [ class "card"
   884                          , containing [ text "no pipeline" ]
   885                          ]
   886              in
   887              [ test "no pipelines card has 14px font and 1px spacing" <|
   888                  noPipelines
   889                      >> noPipelinesCard
   890                      >> Query.has
   891                          [ style "font-size" "14px"
   892                          , style "letter-spacing" "1px"
   893                          ]
   894              , test "no pipelines card text is vertically centered" <|
   895                  noPipelines
   896                      >> noPipelinesCard
   897                      >> Query.has
   898                          [ style "display" "flex"
   899                          , style "align-items" "center"
   900                          ]
   901              , test "no pipelines card is 60px tall" <|
   902                  noPipelines
   903                      >> noPipelinesCard
   904                      >> Query.has [ style "height" "60px" ]
   905              , test "no pipelines card has 60px right margin" <|
   906                  noPipelines
   907                      >> noPipelinesCard
   908                      >> Query.has [ style "margin-right" "60px" ]
   909              , test "no pipelines card text has 10px padding" <|
   910                  noPipelines
   911                      >> noPipelinesCard
   912                      >> Query.children []
   913                      >> Query.first
   914                      >> Query.has [ style "padding" "10px" ]
   915              , test "no pipelines card is 200px wide" <|
   916                  noPipelines
   917                      >> noPipelinesCard
   918                      >> Query.has [ style "width" "200px" ]
   919              , test "no pipelines card has dark grey background" <|
   920                  noPipelines
   921                      >> noPipelinesCard
   922                      >> Query.has [ style "background-color" ColorValues.grey90 ]
   923              , test "card has larger tighter font" <|
   924                  setup
   925                      >> card
   926                      >> Query.has
   927                          [ style "font-size" "19px"
   928                          , style "letter-spacing" "1px"
   929                          ]
   930              , test "card text does not overflow or wrap" <|
   931                  setup
   932                      >> cardText
   933                      >> Query.has
   934                          [ style "width" "180px"
   935                          , style "white-space" "nowrap"
   936                          , style "overflow" "hidden"
   937                          , style "text-overflow" "ellipsis"
   938                          ]
   939              , test "card text is vertically centered" <|
   940                  setup
   941                      >> cardText
   942                      >> Query.has
   943                          [ style "align-self" "center" ]
   944              , test "card text has 10px padding" <|
   945                  setup
   946                      >> cardText
   947                      >> Query.has
   948                          [ style "padding" "10px" ]
   949              , test "card lays out contents horizontally" <|
   950                  setup
   951                      >> card
   952                      >> Query.has
   953                          [ style "display" "flex" ]
   954              , test "card is 60px tall" <|
   955                  setup
   956                      >> card
   957                      >> Query.has [ style "height" "60px" ]
   958              , test "card is 200px wide" <|
   959                  setup
   960                      >> card
   961                      >> Query.has [ style "width" "200px" ]
   962              , test "no triangle when there is no resource error" <|
   963                  setup
   964                      >> card
   965                      >> Query.children []
   966                      >> Query.count (Expect.equal 2)
   967              , describe "resource error triangle" <|
   968                  let
   969                      givenResourceFailingToCheck : () -> Query.Single ApplicationMsgs.TopLevelMessage
   970                      givenResourceFailingToCheck _ =
   971                          whenOnDashboard { highDensity = True }
   972                              |> Application.handleCallback
   973                                  (Callback.AllResourcesFetched <|
   974                                      Ok
   975                                          [ { teamName = "team"
   976                                            , pipelineName = "pipeline"
   977                                            , name = "resource"
   978                                            , lastChecked = Nothing
   979                                            , pinnedVersion = Nothing
   980                                            , pinnedInConfig = False
   981                                            , pinComment = Nothing
   982                                            , icon = Nothing
   983                                            , build = Just (Data.build Concourse.BuildStatus.BuildStatusFailed)
   984                                            }
   985                                          ]
   986                                  )
   987                              |> Tuple.first
   988                              |> givenDataUnauthenticated [ { id = 0, name = "team" } ]
   989                              |> Tuple.first
   990                              |> Application.handleCallback
   991                                  (Callback.AllPipelinesFetched <|
   992                                      Ok
   993                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   994                                  )
   995                              |> Tuple.first
   996                              |> Common.queryView
   997  
   998                      resourceErrorTriangle =
   999                          Query.children []
  1000                              >> Query.index -1
  1001                  in
  1002                  [ test "exists" <|
  1003                      givenResourceFailingToCheck
  1004                          >> card
  1005                          >> Query.children []
  1006                          >> Query.count (Expect.equal 3)
  1007                  , test "is at the top right of card" <|
  1008                      givenResourceFailingToCheck
  1009                          >> card
  1010                          >> Expect.all
  1011                              [ Query.has [ style "position" "relative" ]
  1012                              , resourceErrorTriangle
  1013                                  >> Query.has
  1014                                      [ style "position" "absolute"
  1015                                      , style "top" "0"
  1016                                      , style "right" "0"
  1017                                      ]
  1018                              ]
  1019                  , test "is an orange 'top right' triangle" <|
  1020                      givenResourceFailingToCheck
  1021                          >> card
  1022                          >> resourceErrorTriangle
  1023                          >> Query.has
  1024                              [ style "width" "0"
  1025                              , style "height" "0"
  1026                              , style "border-top" <| "30px solid " ++ orange
  1027                              , style "border-left" "30px solid transparent"
  1028                              ]
  1029                  ]
  1030              , test
  1031                  ("cards are spaced 4px apart vertically and "
  1032                      ++ "60px apart horizontally"
  1033                  )
  1034                <|
  1035                  setup
  1036                      >> card
  1037                      >> Query.has
  1038                          [ style "margin" "0 60px 4px 0" ]
  1039              , test "card is faded green when pipeline is succeeding" <|
  1040                  \_ ->
  1041                      whenOnDashboard { highDensity = True }
  1042                          |> pipelineWithStatus
  1043                              BuildStatusSucceeded
  1044                              False
  1045                          |> card
  1046                          |> Query.has [ style "background-color" fadedGreen ]
  1047              , test "card is red when pipeline is failing" <|
  1048                  \_ ->
  1049                      whenOnDashboard { highDensity = True }
  1050                          |> pipelineWithStatus
  1051                              BuildStatusFailed
  1052                              False
  1053                          |> card
  1054                          |> Query.has [ style "background-color" red ]
  1055              , test "card is amber when pipeline is erroring" <|
  1056                  \_ ->
  1057                      whenOnDashboard { highDensity = True }
  1058                          |> pipelineWithStatus
  1059                              BuildStatusErrored
  1060                              False
  1061                          |> card
  1062                          |> Query.has [ style "background-color" amber ]
  1063              , test "card is not affected by jobs from other pipelines" <|
  1064                  \_ ->
  1065                      whenOnDashboard { highDensity = True }
  1066                          |> Application.handleCallback
  1067                              (Callback.AllPipelinesFetched <|
  1068                                  Ok
  1069                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1070                              )
  1071                          |> Tuple.first
  1072                          |> Application.handleCallback
  1073                              (Callback.AllJobsFetched <|
  1074                                  let
  1075                                      baseJob =
  1076                                          job BuildStatusErrored
  1077                                  in
  1078                                  Ok
  1079                                      [ { baseJob | pipelineName = "other-pipeline" } ]
  1080                              )
  1081                          |> Tuple.first
  1082                          |> Common.queryView
  1083                          |> card
  1084                          |> Query.hasNot [ style "background-color" amber ]
  1085              ]
  1086          , describe "body" <|
  1087              let
  1088                  setup : () -> Query.Single ApplicationMsgs.TopLevelMessage
  1089                  setup _ =
  1090                      whenOnDashboard { highDensity = False }
  1091                          |> givenDataUnauthenticated
  1092                              (apiData [ ( "team", [] ) ])
  1093                          |> Tuple.first
  1094                          |> Application.handleCallback
  1095                              (Callback.AllPipelinesFetched <|
  1096                                  Ok
  1097                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1098                              )
  1099                          |> Tuple.first
  1100                          |> Common.queryView
  1101                          |> Query.find
  1102                              [ class "card"
  1103                              , containing [ text "pipeline" ]
  1104                              ]
  1105              in
  1106              [ test "has dark grey background" <|
  1107                  setup
  1108                      >> findBody
  1109                      >> Query.has [ style "background-color" ColorValues.grey90 ]
  1110              , test "has 2px margin above and below" <|
  1111                  setup
  1112                      >> findBody
  1113                      >> Query.has [ style "margin" "2px 0" ]
  1114              , test "fills available height" <|
  1115                  setup
  1116                      >> findBody
  1117                      >> Query.has [ style "flex-grow" "1" ]
  1118              , test "allows pipeline-grid to fill available height" <|
  1119                  setup
  1120                      >> findBody
  1121                      >> Query.has [ style "display" "flex" ]
  1122              , test "pipeline-grid fills available width" <|
  1123                  setup
  1124                      >> findBody
  1125                      >> Query.find [ class "pipeline-grid" ]
  1126                      >> Query.has
  1127                          [ style "box-sizing" "border-box"
  1128                          , style "width" "100%"
  1129                          ]
  1130              ]
  1131          , describe "footer" <|
  1132              let
  1133                  hasStyle : String -> String -> Expectation
  1134                  hasStyle property value =
  1135                      whenOnDashboard { highDensity = False }
  1136                          |> givenDataAndUser
  1137                              (apiData [ ( "team", [] ) ])
  1138                              (userWithRoles [ ( "team", [ "owner" ] ) ])
  1139                          |> Tuple.first
  1140                          |> Application.handleCallback
  1141                              (Callback.AllPipelinesFetched <|
  1142                                  Ok
  1143                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1144                              )
  1145                          |> Tuple.first
  1146                          |> Common.queryView
  1147                          |> Query.find [ class "card-footer" ]
  1148                          |> Query.has [ style property value ]
  1149              in
  1150              [ test "has dark grey background" <|
  1151                  \_ ->
  1152                      hasStyle "background-color" ColorValues.grey90
  1153              , test "has medium padding" <|
  1154                  \_ ->
  1155                      hasStyle "padding" "13.5px"
  1156              , test "lays out contents horizontally" <|
  1157                  \_ ->
  1158                      hasStyle "display" "flex"
  1159              , test "is divided into a left and right section, spread apart" <|
  1160                  \_ ->
  1161                      whenOnDashboard { highDensity = False }
  1162                          |> givenDataAndUser
  1163                              (apiData [ ( "team", [] ) ])
  1164                              (userWithRoles [ ( "team", [ "owner" ] ) ])
  1165                          |> Tuple.first
  1166                          |> Application.handleCallback
  1167                              (Callback.AllPipelinesFetched <|
  1168                                  Ok
  1169                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1170                              )
  1171                          |> Tuple.first
  1172                          |> Common.queryView
  1173                          |> Query.find [ class "card-footer" ]
  1174                          |> Expect.all
  1175                              [ Query.children []
  1176                                  >> Query.count (Expect.equal 2)
  1177                              , Query.has
  1178                                  [ style "justify-content" "space-between" ]
  1179                              ]
  1180              , test "both sections lay out contents horizontally" <|
  1181                  \_ ->
  1182                      whenOnDashboard { highDensity = False }
  1183                          |> givenDataAndUser
  1184                              (apiData [ ( "team", [] ) ])
  1185                              (userWithRoles [ ( "team", [ "owner" ] ) ])
  1186                          |> Tuple.first
  1187                          |> Application.handleCallback
  1188                              (Callback.AllPipelinesFetched <|
  1189                                  Ok
  1190                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1191                              )
  1192                          |> Tuple.first
  1193                          |> Common.queryView
  1194                          |> Query.find [ class "card-footer" ]
  1195                          |> Query.children []
  1196                          |> Query.each (Query.has [ style "display" "flex" ])
  1197              , describe "left-hand section" <|
  1198                  let
  1199                      findStatusIcon =
  1200                          Query.find [ class "pipeline-status" ]
  1201                              >> Query.children []
  1202                              >> Query.first
  1203  
  1204                      findStatusText =
  1205                          Query.find [ class "pipeline-status" ]
  1206                              >> Query.children []
  1207                              >> Query.index -1
  1208                  in
  1209                  [ describe "when pipeline is paused" <|
  1210                      let
  1211                          setup =
  1212                              whenOnDashboard { highDensity = False }
  1213                                  |> givenDataUnauthenticated
  1214                                      [ { id = 0, name = "team" } ]
  1215                                  |> Tuple.first
  1216                                  |> Application.handleCallback
  1217                                      (Callback.AllPipelinesFetched <|
  1218                                          Ok
  1219                                              [ Data.pipeline "team" 0
  1220                                                  |> Data.withName "pipeline"
  1221                                                  |> Data.withPaused True
  1222                                              ]
  1223                                      )
  1224                                  |> Tuple.first
  1225                                  |> Common.queryView
  1226                      in
  1227                      [ test "status icon is blue pause" <|
  1228                          \_ ->
  1229                              setup
  1230                                  |> findStatusIcon
  1231                                  |> Query.has
  1232                                      (iconSelector
  1233                                          { size = "20px"
  1234                                          , image = PipelineStatusPaused |> Assets.PipelineStatusIcon
  1235                                          }
  1236                                          ++ [ style "background-size" "contain" ]
  1237                                      )
  1238                      , test "status text is blue" <|
  1239                          \_ ->
  1240                              setup
  1241                                  |> findStatusText
  1242                                  |> Query.has [ style "color" blue ]
  1243                      , test "status text is larger and spaced more widely" <|
  1244                          \_ ->
  1245                              setup
  1246                                  |> findStatusText
  1247                                  |> Query.has
  1248                                      [ style "font-size" "18px"
  1249                                      , style "line-height" "20px"
  1250                                      , style "letter-spacing" "0.05em"
  1251                                      ]
  1252                      , test "status text is offset to the right of the icon" <|
  1253                          \_ ->
  1254                              setup
  1255                                  |> findStatusText
  1256                                  |> Query.has [ style "margin-left" "8px" ]
  1257                      , test "status text says 'paused'" <|
  1258                          \_ ->
  1259                              setup
  1260                                  |> findStatusText
  1261                                  |> Query.has [ text "paused" ]
  1262                      ]
  1263                  , describe "when a pipeline is based on cache" <|
  1264                      let
  1265                          setup =
  1266                              whenOnDashboard { highDensity = False }
  1267                                  |> givenDataUnauthenticated
  1268                                      [ { id = 0, name = "team" } ]
  1269                                  |> Tuple.first
  1270                                  |> Application.handleDelivery
  1271                                      (CachedPipelinesReceived <|
  1272                                          Ok
  1273                                              [ Data.pipeline "team" 0
  1274                                                  |> Data.withName "pipeline"
  1275                                                  |> Data.withPaused True
  1276                                              ]
  1277                                      )
  1278                                  |> Tuple.first
  1279                                  |> Common.queryView
  1280                      in
  1281                      [ test "status icon is grey pending" <|
  1282                          \_ ->
  1283                              setup
  1284                                  |> findStatusIcon
  1285                                  |> Query.has
  1286                                      (iconSelector
  1287                                          { size = "20px"
  1288                                          , image = Assets.PipelineStatusIconStale
  1289                                          }
  1290                                          ++ [ style "background-size" "contain" ]
  1291                                      )
  1292                      , test "status text is grey" <|
  1293                          \_ ->
  1294                              setup
  1295                                  |> findStatusText
  1296                                  |> Query.has [ style "color" lightGrey ]
  1297                      , test "status text says 'loading...'" <|
  1298                          \_ ->
  1299                              setup
  1300                                  |> findStatusText
  1301                                  |> Query.has [ text "loading..." ]
  1302                      , test "pipeline card is faded" <|
  1303                          \_ ->
  1304                              setup
  1305                                  |> Query.find [ class "card" ]
  1306                                  |> Query.has [ style "opacity" "0.45" ]
  1307                      ]
  1308                  , describe "when pipeline has no jobs due to a disabled endpoint" <|
  1309                      let
  1310                          setup =
  1311                              whenOnDashboard { highDensity = False }
  1312                                  |> givenDataUnauthenticated
  1313                                      [ { id = 0, name = "team" } ]
  1314                                  |> Tuple.first
  1315                                  |> Application.handleDelivery
  1316                                      (CachedJobsReceived <| Ok [ Data.job 0 ])
  1317                                  |> Tuple.first
  1318                                  |> Application.handleCallback
  1319                                      (Callback.AllPipelinesFetched <|
  1320                                          Ok
  1321                                              [ Data.pipeline "team" 0 ]
  1322                                      )
  1323                                  |> Tuple.first
  1324                                  |> Application.handleCallback
  1325                                      (Callback.AllJobsFetched <|
  1326                                          Data.httpNotImplemented
  1327                                      )
  1328  
  1329                          domID =
  1330                              Msgs.PipelineStatusIcon AllPipelinesSection
  1331                                  (Data.pipelineId
  1332                                      |> Data.withPipelineName "pipeline-0"
  1333                                  )
  1334                      in
  1335                      [ test "status icon is faded sync" <|
  1336                          \_ ->
  1337                              setup
  1338                                  |> Tuple.first
  1339                                  |> Common.queryView
  1340                                  |> findStatusIcon
  1341                                  |> Query.has
  1342                                      (iconSelector
  1343                                          { size = "20px"
  1344                                          , image = Assets.PipelineStatusIconJobsDisabled
  1345                                          }
  1346                                          ++ [ style "background-size" "contain"
  1347                                             , style "opacity" "0.5"
  1348                                             ]
  1349                                      )
  1350                      , test "status icon is hoverable" <|
  1351                          \_ ->
  1352                              setup
  1353                                  |> Tuple.first
  1354                                  |> Common.queryView
  1355                                  |> findStatusIcon
  1356                                  |> Event.simulate Event.mouseEnter
  1357                                  |> Event.expect
  1358                                      (ApplicationMsgs.Update <|
  1359                                          Msgs.Hover <|
  1360                                              Just domID
  1361                                      )
  1362                      , test "hovering status icon sends location request" <|
  1363                          \_ ->
  1364                              setup
  1365                                  |> Tuple.first
  1366                                  |> Application.update
  1367                                      (ApplicationMsgs.Update <|
  1368                                          Msgs.Hover <|
  1369                                              Just domID
  1370                                      )
  1371                                  |> Tuple.second
  1372                                  |> Common.contains
  1373                                      (Effects.GetViewportOf domID)
  1374                      , test "hovering status icon shows tooltip" <|
  1375                          \_ ->
  1376                              setup
  1377                                  |> Tuple.first
  1378                                  |> Application.update
  1379                                      (ApplicationMsgs.Update <|
  1380                                          Msgs.Hover <|
  1381                                              Just domID
  1382                                      )
  1383                                  |> Tuple.first
  1384                                  |> Application.handleCallback
  1385                                      (Callback.GotViewport domID
  1386                                          (Ok
  1387                                              { scene =
  1388                                                  { width = 1
  1389                                                  , height = 0
  1390                                                  }
  1391                                              , viewport =
  1392                                                  { width = 1
  1393                                                  , height = 0
  1394                                                  , x = 0
  1395                                                  , y = 0
  1396                                                  }
  1397                                              }
  1398                                          )
  1399                                      )
  1400                                  |> Tuple.first
  1401                                  |> Application.handleCallback
  1402                                      (Callback.GotElement <|
  1403                                          Ok
  1404                                              { scene =
  1405                                                  { width = 0
  1406                                                  , height = 0
  1407                                                  }
  1408                                              , viewport =
  1409                                                  { width = 0
  1410                                                  , height = 0
  1411                                                  , x = 0
  1412                                                  , y = 0
  1413                                                  }
  1414                                              , element =
  1415                                                  { x = 0
  1416                                                  , y = 0
  1417                                                  , width = 1
  1418                                                  , height = 1
  1419                                                  }
  1420                                              }
  1421                                      )
  1422                                  |> Tuple.first
  1423                                  |> Common.queryView
  1424                                  |> Query.has
  1425                                      [ style "position" "fixed"
  1426                                      , containing [ text "automatic job monitoring disabled" ]
  1427                                      ]
  1428                      , test "status text says 'no data'" <|
  1429                          \_ ->
  1430                              setup
  1431                                  |> Tuple.first
  1432                                  |> Common.queryView
  1433                                  |> findStatusText
  1434                                  |> Query.has [ text "no data" ]
  1435                      , test "job preview is empty placeholder" <|
  1436                          \_ ->
  1437                              setup
  1438                                  |> Tuple.first
  1439                                  |> Common.queryView
  1440                                  |> Query.find [ class "card-body" ]
  1441                                  |> Query.has [ style "background-color" ColorValues.grey90 ]
  1442                      , test "job data is cleared" <|
  1443                          \_ ->
  1444                              setup
  1445                                  |> Tuple.first
  1446                                  |> Common.queryView
  1447                                  |> Query.find [ class "parallel-grid" ]
  1448                                  |> Query.hasNot [ tag "a" ]
  1449                      , test "job data is cleared from local cache" <|
  1450                          \_ ->
  1451                              setup
  1452                                  |> Tuple.second
  1453                                  |> Common.contains Effects.DeleteCachedJobs
  1454                      ]
  1455                  , describe "when pipeline is archived" <|
  1456                      let
  1457                          setup =
  1458                              whenOnDashboardViewingAllPipelines { highDensity = False }
  1459                                  |> givenDataUnauthenticated
  1460                                      [ { id = 0, name = "team" } ]
  1461                                  |> Tuple.first
  1462                                  |> Application.handleCallback
  1463                                      (Callback.AllPipelinesFetched <|
  1464                                          Ok
  1465                                              [ Data.pipeline "team" 0
  1466                                                  |> Data.withArchived True
  1467                                              ]
  1468                                      )
  1469                                  |> Tuple.first
  1470                                  |> Application.handleCallback
  1471                                      (Callback.AllJobsFetched <|
  1472                                          Ok
  1473                                              [ Data.job 0 ]
  1474                                      )
  1475                      in
  1476                      [ test "status section is empty" <|
  1477                          \_ ->
  1478                              setup
  1479                                  |> Tuple.first
  1480                                  |> Common.queryView
  1481                                  |> Query.find [ class "pipeline-status" ]
  1482                                  |> Query.children []
  1483                                  |> Query.count (Expect.equal 0)
  1484                      , test "job preview is empty placeholder" <|
  1485                          \_ ->
  1486                              setup
  1487                                  |> Tuple.first
  1488                                  |> Common.queryView
  1489                                  |> Query.find [ class "card-body" ]
  1490                                  |> Query.has [ style "background-color" ColorValues.grey90 ]
  1491                      , test "there is no pause button" <|
  1492                          \_ ->
  1493                              setup
  1494                                  |> Tuple.first
  1495                                  |> Common.queryView
  1496                                  |> Query.hasNot [ class "pause-toggle" ]
  1497                      ]
  1498                  , describe "when pipeline is pending" <|
  1499                      [ test "status icon is grey" <|
  1500                          \_ ->
  1501                              whenOnDashboard { highDensity = False }
  1502                                  |> pipelineWithStatus
  1503                                      BuildStatusPending
  1504                                      False
  1505                                  |> findStatusIcon
  1506                                  |> Query.has
  1507                                      (iconSelector
  1508                                          { size = "20px"
  1509                                          , image = PipelineStatusPending True |> Assets.PipelineStatusIcon
  1510                                          }
  1511                                          ++ [ style "background-size" "contain" ]
  1512                                      )
  1513                      , test "status text is grey" <|
  1514                          \_ ->
  1515                              whenOnDashboard { highDensity = False }
  1516                                  |> pipelineWithStatus
  1517                                      BuildStatusPending
  1518                                      False
  1519                                  |> findStatusText
  1520                                  |> Query.has [ style "color" lightGrey ]
  1521                      , test "status text says 'pending'" <|
  1522                          \_ ->
  1523                              whenOnDashboard { highDensity = False }
  1524                                  |> pipelineWithStatus
  1525                                      BuildStatusPending
  1526                                      False
  1527                                  |> findStatusText
  1528                                  |> Query.has
  1529                                      [ text "pending" ]
  1530                      , test "when running, status text says 'running'" <|
  1531                          \_ ->
  1532                              whenOnDashboard { highDensity = False }
  1533                                  |> pipelineWithStatus
  1534                                      BuildStatusPending
  1535                                      True
  1536                                  |> findStatusText
  1537                                  |> Query.has
  1538                                      [ text "running" ]
  1539                      ]
  1540                  , describe "when pipeline is succeeding"
  1541                      [ test "status icon is a green check" <|
  1542                          \_ ->
  1543                              whenOnDashboard { highDensity = False }
  1544                                  |> pipelineWithStatus
  1545                                      BuildStatusSucceeded
  1546                                      False
  1547                                  |> findStatusIcon
  1548                                  |> Query.has
  1549                                      (iconSelector
  1550                                          { size = "20px"
  1551                                          , image = PipelineStatusSucceeded Running |> Assets.PipelineStatusIcon
  1552                                          }
  1553                                          ++ [ style "background-size" "contain" ]
  1554                                      )
  1555                      , test "status text is green" <|
  1556                          \_ ->
  1557                              whenOnDashboard { highDensity = False }
  1558                                  |> pipelineWithStatus
  1559                                      BuildStatusSucceeded
  1560                                      False
  1561                                  |> findStatusText
  1562                                  |> Query.has [ style "color" green ]
  1563                      , test "when running, status text says 'running'" <|
  1564                          \_ ->
  1565                              whenOnDashboard { highDensity = False }
  1566                                  |> pipelineWithStatus
  1567                                      BuildStatusSucceeded
  1568                                      True
  1569                                  |> findStatusText
  1570                                  |> Query.has
  1571                                      [ text "running" ]
  1572                      , test "when not running, status text shows age" <|
  1573                          \_ ->
  1574                              whenOnDashboard { highDensity = False }
  1575                                  |> Application.handleCallback
  1576                                      (Callback.AllJobsFetched <|
  1577                                          Ok
  1578                                              [ jobWithNameTransitionedAt
  1579                                                  "job"
  1580                                                  (Just <| Time.millisToPosix 0)
  1581                                                  BuildStatusSucceeded
  1582                                              ]
  1583                                      )
  1584                                  |> Tuple.first
  1585                                  |> givenDataUnauthenticated
  1586                                      [ { id = 0, name = "team" } ]
  1587                                  |> Tuple.first
  1588                                  |> Application.handleCallback
  1589                                      (Callback.AllPipelinesFetched <|
  1590                                          Ok
  1591                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1592                                      )
  1593                                  |> Tuple.first
  1594                                  |> afterSeconds 1
  1595                                  |> Common.queryView
  1596                                  |> findStatusText
  1597                                  |> Query.has
  1598                                      [ text "1s" ]
  1599                      ]
  1600                  , describe "when pipeline is failing"
  1601                      [ test "status icon is a red !" <|
  1602                          \_ ->
  1603                              whenOnDashboard { highDensity = False }
  1604                                  |> pipelineWithStatus
  1605                                      BuildStatusFailed
  1606                                      False
  1607                                  |> findStatusIcon
  1608                                  |> Query.has
  1609                                      (iconSelector
  1610                                          { size = "20px"
  1611                                          , image = PipelineStatusFailed Running |> Assets.PipelineStatusIcon
  1612                                          }
  1613                                          ++ [ style "background-size" "contain" ]
  1614                                      )
  1615                      , test "status text is red" <|
  1616                          \_ ->
  1617                              whenOnDashboard { highDensity = False }
  1618                                  |> pipelineWithStatus
  1619                                      BuildStatusFailed
  1620                                      False
  1621                                  |> findStatusText
  1622                                  |> Query.has [ style "color" red ]
  1623                      ]
  1624                  , test "when pipeline is aborted, status icon is a brown x" <|
  1625                      \_ ->
  1626                          whenOnDashboard { highDensity = False }
  1627                              |> pipelineWithStatus
  1628                                  BuildStatusAborted
  1629                                  False
  1630                              |> findStatusIcon
  1631                              |> Query.has
  1632                                  (iconSelector
  1633                                      { size = "20px"
  1634                                      , image = PipelineStatusAborted Running |> Assets.PipelineStatusIcon
  1635                                      }
  1636                                      ++ [ style "background-size" "contain" ]
  1637                                  )
  1638                  , test "when pipeline is errored, status icon is an amber triangle" <|
  1639                      \_ ->
  1640                          whenOnDashboard { highDensity = False }
  1641                              |> pipelineWithStatus
  1642                                  BuildStatusErrored
  1643                                  False
  1644                              |> findStatusIcon
  1645                              |> Query.has
  1646                                  (iconSelector
  1647                                      { size = "20px"
  1648                                      , image = PipelineStatusErrored Running |> Assets.PipelineStatusIcon
  1649                                      }
  1650                                      ++ [ style "background-size" "contain" ]
  1651                                  )
  1652                  ]
  1653              , describe "right-hand section"
  1654                  [ describe "visibility toggle" <|
  1655                      let
  1656                          pipelineId =
  1657                              Data.pipelineId
  1658  
  1659                          visibilityToggle =
  1660                              Common.queryView
  1661                                  >> Query.findAll [ class "card-footer" ]
  1662                                  >> Query.first
  1663                                  >> Query.children []
  1664                                  >> Query.index -1
  1665                                  >> Query.children []
  1666                                  >> Query.index 2
  1667  
  1668                          openEye =
  1669                              iconSelector
  1670                                  { size = "20px"
  1671                                  , image = Assets.VisibilityToggleIcon True
  1672                                  }
  1673                                  ++ [ style "background-size" "contain" ]
  1674  
  1675                          slashedOutEye =
  1676                              iconSelector
  1677                                  { size = "20px"
  1678                                  , image = Assets.VisibilityToggleIcon False
  1679                                  }
  1680                                  ++ [ style "background-size" "contain" ]
  1681  
  1682                          openEyeClickable setup =
  1683                              [ defineHoverBehaviour
  1684                                  { name = "open eye toggle"
  1685                                  , setup =
  1686                                      whenOnDashboard { highDensity = False }
  1687                                          |> setup
  1688                                          |> Tuple.first
  1689                                  , query = visibilityToggle
  1690                                  , unhoveredSelector =
  1691                                      { description = "faded 20px square"
  1692                                      , selector =
  1693                                          openEye
  1694                                              ++ [ style "opacity" "0.5"
  1695                                                 , style "cursor" "pointer"
  1696                                                 ]
  1697                                      }
  1698                                  , hoverable =
  1699                                      Msgs.VisibilityButton AllPipelinesSection pipelineId
  1700                                  , hoveredSelector =
  1701                                      { description = "bright 20px square"
  1702                                      , selector =
  1703                                          openEye
  1704                                              ++ [ style "opacity" "1"
  1705                                                 , style "cursor" "pointer"
  1706                                                 ]
  1707                                      }
  1708                                  }
  1709                              , test "has click handler" <|
  1710                                  \_ ->
  1711                                      whenOnDashboard { highDensity = False }
  1712                                          |> setup
  1713                                          |> Tuple.first
  1714                                          |> visibilityToggle
  1715                                          |> Event.simulate Event.click
  1716                                          |> Event.expect
  1717                                              (ApplicationMsgs.Update <|
  1718                                                  Msgs.Click <|
  1719                                                      Msgs.VisibilityButton AllPipelinesSection
  1720                                                          pipelineId
  1721                                              )
  1722                              , test "click has HidePipeline effect" <|
  1723                                  \_ ->
  1724                                      whenOnDashboard { highDensity = False }
  1725                                          |> setup
  1726                                          |> Tuple.first
  1727                                          |> Application.update
  1728                                              (ApplicationMsgs.Update <|
  1729                                                  Msgs.Click <|
  1730                                                      Msgs.VisibilityButton AllPipelinesSection
  1731                                                          pipelineId
  1732                                              )
  1733                                          |> Tuple.second
  1734                                          |> Expect.equal
  1735                                              [ Effects.ChangeVisibility
  1736                                                  Msgs.Hide
  1737                                                  pipelineId
  1738                                              ]
  1739                              , defineHoverBehaviour
  1740                                  { name = "open eye toggle in favorites section"
  1741                                  , setup =
  1742                                      whenOnDashboard { highDensity = False }
  1743                                          |> Application.handleDelivery
  1744                                              (Message.Subscription.FavoritedPipelinesReceived <| Ok <| Set.singleton 0)
  1745                                          |> Tuple.first
  1746                                          |> setup
  1747                                          |> Tuple.first
  1748                                  , query = visibilityToggle
  1749                                  , unhoveredSelector =
  1750                                      { description = "faded 20px square"
  1751                                      , selector =
  1752                                          openEye
  1753                                              ++ [ style "opacity" "0.5"
  1754                                                 , style "cursor" "pointer"
  1755                                                 ]
  1756                                      }
  1757                                  , hoverable =
  1758                                      Msgs.VisibilityButton FavoritesSection pipelineId
  1759                                  , hoveredSelector =
  1760                                      { description = "bright 20px square"
  1761                                      , selector =
  1762                                          openEye
  1763                                              ++ [ style "opacity" "1"
  1764                                                 , style "cursor" "pointer"
  1765                                                 ]
  1766                                      }
  1767                                  }
  1768                              , defineHoverBehaviour
  1769                                  { name = "visibility spinner"
  1770                                  , setup =
  1771                                      whenOnDashboard { highDensity = False }
  1772                                          |> setup
  1773                                          |> Tuple.first
  1774                                          |> Application.update
  1775                                              (ApplicationMsgs.Update <|
  1776                                                  Msgs.Click <|
  1777                                                      Msgs.VisibilityButton AllPipelinesSection
  1778                                                          pipelineId
  1779                                              )
  1780                                          |> Tuple.first
  1781                                  , query = visibilityToggle
  1782                                  , unhoveredSelector =
  1783                                      { description = "20px spinner"
  1784                                      , selector =
  1785                                          [ style "animation"
  1786                                              "container-rotate 1568ms linear infinite"
  1787                                          , style "height" "20px"
  1788                                          , style "width" "20px"
  1789                                          ]
  1790                                      }
  1791                                  , hoverable =
  1792                                      Msgs.VisibilityButton AllPipelinesSection pipelineId
  1793                                  , hoveredSelector =
  1794                                      { description = "20px spinner"
  1795                                      , selector =
  1796                                          [ style "animation"
  1797                                              "container-rotate 1568ms linear infinite"
  1798                                          , style "height" "20px"
  1799                                          , style "width" "20px"
  1800                                          ]
  1801                                      }
  1802                                  }
  1803                              , test "success resolves spinner to slashed-out eye" <|
  1804                                  \_ ->
  1805                                      whenOnDashboard { highDensity = False }
  1806                                          |> setup
  1807                                          |> Tuple.first
  1808                                          |> Application.update
  1809                                              (ApplicationMsgs.Update <|
  1810                                                  Msgs.Click <|
  1811                                                      Msgs.VisibilityButton AllPipelinesSection
  1812                                                          pipelineId
  1813                                              )
  1814                                          |> Tuple.first
  1815                                          |> Application.handleCallback
  1816                                              (Callback.VisibilityChanged
  1817                                                  Msgs.Hide
  1818                                                  pipelineId
  1819                                                  (Ok ())
  1820                                              )
  1821                                          |> Tuple.first
  1822                                          |> visibilityToggle
  1823                                          |> Query.has slashedOutEye
  1824                              , test "error resolves spinner to open eye" <|
  1825                                  \_ ->
  1826                                      whenOnDashboard { highDensity = False }
  1827                                          |> setup
  1828                                          |> Tuple.first
  1829                                          |> Application.update
  1830                                              (ApplicationMsgs.Update <|
  1831                                                  Msgs.Click <|
  1832                                                      Msgs.VisibilityButton AllPipelinesSection
  1833                                                          pipelineId
  1834                                              )
  1835                                          |> Tuple.first
  1836                                          |> Application.handleCallback
  1837                                              (Callback.VisibilityChanged
  1838                                                  Msgs.Hide
  1839                                                  pipelineId
  1840                                                  Data.httpInternalServerError
  1841                                              )
  1842                                          |> Tuple.first
  1843                                          |> visibilityToggle
  1844                                          |> Query.has openEye
  1845                              , test "401 redirects to login" <|
  1846                                  \_ ->
  1847                                      whenOnDashboard { highDensity = False }
  1848                                          |> setup
  1849                                          |> Tuple.first
  1850                                          |> Application.update
  1851                                              (ApplicationMsgs.Update <|
  1852                                                  Msgs.Click <|
  1853                                                      Msgs.VisibilityButton AllPipelinesSection
  1854                                                          pipelineId
  1855                                              )
  1856                                          |> Tuple.first
  1857                                          |> Application.handleCallback
  1858                                              (Callback.VisibilityChanged
  1859                                                  Msgs.Hide
  1860                                                  pipelineId
  1861                                                  Data.httpUnauthorized
  1862                                              )
  1863                                          |> Tuple.second
  1864                                          |> Expect.equal
  1865                                              [ Effects.RedirectToLogin ]
  1866                              ]
  1867  
  1868                          openEyeUnclickable setup =
  1869                              [ defineHoverBehaviour
  1870                                  { name = "open eye toggle"
  1871                                  , setup =
  1872                                      whenOnDashboard { highDensity = False }
  1873                                          |> setup
  1874                                          |> Tuple.first
  1875                                  , query = visibilityToggle
  1876                                  , unhoveredSelector =
  1877                                      { description = "faded 20px square"
  1878                                      , selector =
  1879                                          openEye
  1880                                              ++ [ style "opacity" "0.5"
  1881                                                 , style "cursor" "default"
  1882                                                 ]
  1883                                      }
  1884                                  , hoverable =
  1885                                      Msgs.VisibilityButton AllPipelinesSection pipelineId
  1886                                  , hoveredSelector =
  1887                                      { description = "faded 20px square"
  1888                                      , selector =
  1889                                          openEye
  1890                                              ++ [ style "opacity" "0.5"
  1891                                                 , style "cursor" "default"
  1892                                                 ]
  1893                                      }
  1894                                  }
  1895                              , test "has no click handler" <|
  1896                                  \_ ->
  1897                                      whenOnDashboard { highDensity = False }
  1898                                          |> setup
  1899                                          |> Tuple.first
  1900                                          |> visibilityToggle
  1901                                          |> Event.simulate Event.click
  1902                                          |> Event.toResult
  1903                                          |> Expect.err
  1904                              ]
  1905  
  1906                          slashedOutEyeClickable setup =
  1907                              [ defineHoverBehaviour
  1908                                  { name = "slashed-out eye toggle"
  1909                                  , setup =
  1910                                      whenOnDashboard { highDensity = False }
  1911                                          |> setup
  1912                                          |> Tuple.first
  1913                                  , query = visibilityToggle
  1914                                  , unhoveredSelector =
  1915                                      { description = "faded 20px square"
  1916                                      , selector =
  1917                                          slashedOutEye
  1918                                              ++ [ style "opacity" "0.5"
  1919                                                 , style "cursor" "pointer"
  1920                                                 ]
  1921                                      }
  1922                                  , hoverable =
  1923                                      Msgs.VisibilityButton AllPipelinesSection pipelineId
  1924                                  , hoveredSelector =
  1925                                      { description = "bright 20px square"
  1926                                      , selector =
  1927                                          slashedOutEye
  1928                                              ++ [ style "opacity" "1"
  1929                                                 , style "cursor" "pointer"
  1930                                                 ]
  1931                                      }
  1932                                  }
  1933                              , test "has click handler" <|
  1934                                  \_ ->
  1935                                      whenOnDashboard { highDensity = False }
  1936                                          |> setup
  1937                                          |> Tuple.first
  1938                                          |> visibilityToggle
  1939                                          |> Event.simulate Event.click
  1940                                          |> Event.expect
  1941                                              (ApplicationMsgs.Update <|
  1942                                                  Msgs.Click <|
  1943                                                      Msgs.VisibilityButton AllPipelinesSection
  1944                                                          pipelineId
  1945                                              )
  1946                              , test "click has ExposePipeline effect" <|
  1947                                  \_ ->
  1948                                      whenOnDashboard { highDensity = False }
  1949                                          |> setup
  1950                                          |> Tuple.first
  1951                                          |> Application.update
  1952                                              (ApplicationMsgs.Update <|
  1953                                                  Msgs.Click <|
  1954                                                      Msgs.VisibilityButton AllPipelinesSection
  1955                                                          pipelineId
  1956                                              )
  1957                                          |> Tuple.second
  1958                                          |> Expect.equal
  1959                                              [ Effects.ChangeVisibility
  1960                                                  Msgs.Expose
  1961                                                  pipelineId
  1962                                              ]
  1963                              , defineHoverBehaviour
  1964                                  { name = "visibility spinner"
  1965                                  , setup =
  1966                                      whenOnDashboard { highDensity = False }
  1967                                          |> setup
  1968                                          |> Tuple.first
  1969                                          |> Application.update
  1970                                              (ApplicationMsgs.Update <|
  1971                                                  Msgs.Click <|
  1972                                                      Msgs.VisibilityButton AllPipelinesSection
  1973                                                          pipelineId
  1974                                              )
  1975                                          |> Tuple.first
  1976                                  , query = visibilityToggle
  1977                                  , unhoveredSelector =
  1978                                      { description = "20px spinner"
  1979                                      , selector =
  1980                                          [ style "animation"
  1981                                              "container-rotate 1568ms linear infinite"
  1982                                          , style "height" "20px"
  1983                                          , style "width" "20px"
  1984                                          ]
  1985                                      }
  1986                                  , hoverable =
  1987                                      Msgs.VisibilityButton AllPipelinesSection pipelineId
  1988                                  , hoveredSelector =
  1989                                      { description = "20px spinner"
  1990                                      , selector =
  1991                                          [ style "animation"
  1992                                              "container-rotate 1568ms linear infinite"
  1993                                          , style "height" "20px"
  1994                                          , style "width" "20px"
  1995                                          ]
  1996                                      }
  1997                                  }
  1998                              , test "success resolves spinner to open eye" <|
  1999                                  \_ ->
  2000                                      whenOnDashboard { highDensity = False }
  2001                                          |> setup
  2002                                          |> Tuple.first
  2003                                          |> Application.update
  2004                                              (ApplicationMsgs.Update <|
  2005                                                  Msgs.Click <|
  2006                                                      Msgs.VisibilityButton AllPipelinesSection
  2007                                                          pipelineId
  2008                                              )
  2009                                          |> Tuple.first
  2010                                          |> Application.handleCallback
  2011                                              (Callback.VisibilityChanged
  2012                                                  Msgs.Expose
  2013                                                  pipelineId
  2014                                                  (Ok ())
  2015                                              )
  2016                                          |> Tuple.first
  2017                                          |> visibilityToggle
  2018                                          |> Query.has openEye
  2019                              , test "error resolves spinner to slashed-out eye" <|
  2020                                  \_ ->
  2021                                      whenOnDashboard { highDensity = False }
  2022                                          |> setup
  2023                                          |> Tuple.first
  2024                                          |> Application.update
  2025                                              (ApplicationMsgs.Update <|
  2026                                                  Msgs.Click <|
  2027                                                      Msgs.VisibilityButton AllPipelinesSection
  2028                                                          pipelineId
  2029                                              )
  2030                                          |> Tuple.first
  2031                                          |> Application.handleCallback
  2032                                              (Callback.VisibilityChanged
  2033                                                  Msgs.Expose
  2034                                                  pipelineId
  2035                                                  Data.httpInternalServerError
  2036                                              )
  2037                                          |> Tuple.first
  2038                                          |> visibilityToggle
  2039                                          |> Query.has slashedOutEye
  2040                              ]
  2041  
  2042                          slashedOutEyeUnclickable setup =
  2043                              [ defineHoverBehaviour
  2044                                  { name = "slashed-out eye toggle"
  2045                                  , setup =
  2046                                      whenOnDashboard { highDensity = False }
  2047                                          |> setup
  2048                                          |> Tuple.first
  2049                                  , query = visibilityToggle
  2050                                  , unhoveredSelector =
  2051                                      { description = "faded 20px square"
  2052                                      , selector =
  2053                                          slashedOutEye
  2054                                              ++ [ style "opacity" "0.5"
  2055                                                 , style "cursor" "default"
  2056                                                 ]
  2057                                      }
  2058                                  , hoverable =
  2059                                      Msgs.VisibilityButton AllPipelinesSection pipelineId
  2060                                  , hoveredSelector =
  2061                                      { description = "faded 20px square"
  2062                                      , selector =
  2063                                          slashedOutEye
  2064                                              ++ [ style "opacity" "0.5"
  2065                                                 , style "cursor" "default"
  2066                                                 ]
  2067                                      }
  2068                                  }
  2069                              , test "has no click handler" <|
  2070                                  \_ ->
  2071                                      whenOnDashboard { highDensity = False }
  2072                                          |> setup
  2073                                          |> Tuple.first
  2074                                          |> visibilityToggle
  2075                                          |> Event.simulate Event.click
  2076                                          |> Event.toResult
  2077                                          |> Expect.err
  2078                              ]
  2079                      in
  2080                      [ describe "when authorized" <|
  2081                          let
  2082                              whenAuthorizedPublic =
  2083                                  givenDataAndUser
  2084                                      (apiData [ ( "team", [] ) ])
  2085                                      (userWithRoles
  2086                                          [ ( "team", [ "owner" ] ) ]
  2087                                      )
  2088                                      >> Tuple.first
  2089                                      >> Application.handleCallback
  2090                                          (Callback.AllPipelinesFetched <|
  2091                                              Ok
  2092                                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2093                                          )
  2094  
  2095                              whenAuthorizedNonPublic =
  2096                                  givenDataAndUser
  2097                                      (apiData [ ( "team", [] ) ])
  2098                                      (userWithRoles
  2099                                          [ ( "team", [ "owner" ] ) ]
  2100                                      )
  2101                                      >> Tuple.first
  2102                                      >> Application.handleCallback
  2103                                          (Callback.AllPipelinesFetched <|
  2104                                              Ok
  2105                                                  [ Data.pipeline "team" 0
  2106                                                      |> Data.withName "pipeline"
  2107                                                      |> Data.withPublic False
  2108                                                  ]
  2109                                          )
  2110                          in
  2111                          [ describe "on public pipeline" <|
  2112                              openEyeClickable whenAuthorizedPublic
  2113                          , describe "on a non-public pipeline" <|
  2114                              slashedOutEyeClickable whenAuthorizedNonPublic
  2115                          ]
  2116                      , describe "when unauthorized" <|
  2117                          let
  2118                              whenUnauthorizedPublic =
  2119                                  givenDataAndUser
  2120                                      (apiData [ ( "team", [] ) ])
  2121                                      (userWithRoles
  2122                                          [ ( "team", [ "viewer" ] ) ]
  2123                                      )
  2124                                      >> Tuple.first
  2125                                      >> Application.handleCallback
  2126                                          (Callback.AllPipelinesFetched <|
  2127                                              Ok
  2128                                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2129                                          )
  2130  
  2131                              whenUnauthorizedNonPublic =
  2132                                  givenDataAndUser
  2133                                      (apiData [ ( "team", [] ) ])
  2134                                      (userWithRoles
  2135                                          [ ( "team", [ "viewer" ] ) ]
  2136                                      )
  2137                                      >> Tuple.first
  2138                                      >> Application.handleCallback
  2139                                          (Callback.AllPipelinesFetched <|
  2140                                              Ok
  2141                                                  [ Data.pipeline "team" 0
  2142                                                      |> Data.withName "pipeline"
  2143                                                      |> Data.withPublic False
  2144                                                  ]
  2145                                          )
  2146                          in
  2147                          [ describe "on public pipeline" <|
  2148                              openEyeUnclickable whenUnauthorizedPublic
  2149                          , describe "on a non-public pipeline" <|
  2150                              slashedOutEyeUnclickable
  2151                                  whenUnauthorizedNonPublic
  2152                          ]
  2153                      , describe "when unauthenticated" <|
  2154                          let
  2155                              whenUnauthenticated =
  2156                                  givenDataUnauthenticated
  2157                                      (apiData [ ( "team", [] ) ])
  2158                                      >> Tuple.first
  2159                                      >> Application.handleCallback
  2160                                          (Callback.AllPipelinesFetched <|
  2161                                              Ok
  2162                                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2163                                          )
  2164                          in
  2165                          [ describe "on public pipeline" <|
  2166                              openEyeClickable whenUnauthenticated
  2167                          ]
  2168                      ]
  2169                  , test "there is medium spacing between the eye and the play/pause button" <|
  2170                      \_ ->
  2171                          whenOnDashboard { highDensity = False }
  2172                              |> givenDataAndUser
  2173                                  (apiData [ ( "team", [] ) ])
  2174                                  (userWithRoles [ ( "team", [ "owner" ] ) ])
  2175                              |> Tuple.first
  2176                              |> Application.handleCallback
  2177                                  (Callback.AllPipelinesFetched <|
  2178                                      Ok
  2179                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2180                                  )
  2181                              |> Tuple.first
  2182                              |> Common.queryView
  2183                              |> Query.find [ class "card-footer" ]
  2184                              |> Query.children []
  2185                              |> Query.index -1
  2186                              |> Query.children []
  2187                              |> Expect.all
  2188                                  [ Query.count (Expect.equal 5)
  2189                                  , Query.index 1 >> Query.has [ style "width" "12px" ]
  2190                                  ]
  2191                  , test "there is medium spacing between the eye and the favorited icon" <|
  2192                      \_ ->
  2193                          whenOnDashboard { highDensity = False }
  2194                              |> givenDataAndUser
  2195                                  (apiData [ ( "team", [] ) ])
  2196                                  (userWithRoles [ ( "team", [ "owner" ] ) ])
  2197                              |> Tuple.first
  2198                              |> Application.handleCallback
  2199                                  (Callback.AllPipelinesFetched <|
  2200                                      Ok
  2201                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2202                                  )
  2203                              |> Tuple.first
  2204                              |> Common.queryView
  2205                              |> Query.find [ class "card-footer" ]
  2206                              |> Query.children []
  2207                              |> Query.index -1
  2208                              |> Query.children []
  2209                              |> Expect.all
  2210                                  [ Query.count (Expect.equal 5)
  2211                                  , Query.index 3 >> Query.has [ style "width" "12px" ]
  2212                                  ]
  2213                  , describe "pause toggle"
  2214                      [ test "the right section has a 20px square pause button on the left" <|
  2215                          \_ ->
  2216                              whenOnDashboard { highDensity = False }
  2217                                  |> givenDataAndUser
  2218                                      (apiData [ ( "team", [] ) ])
  2219                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2220                                  |> Tuple.first
  2221                                  |> Application.handleCallback
  2222                                      (Callback.AllPipelinesFetched <|
  2223                                          Ok
  2224                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2225                                      )
  2226                                  |> Tuple.first
  2227                                  |> Common.queryView
  2228                                  |> Query.find [ class "card-footer" ]
  2229                                  |> Query.children []
  2230                                  |> Query.index -1
  2231                                  |> Query.children []
  2232                                  |> Query.index 0
  2233                                  |> Query.has
  2234                                      (iconSelector
  2235                                          { size = "20px"
  2236                                          , image = Assets.PauseIcon
  2237                                          }
  2238                                      )
  2239                      , test "pause button has pointer cursor when authorized" <|
  2240                          \_ ->
  2241                              whenOnDashboard { highDensity = False }
  2242                                  |> givenDataAndUser
  2243                                      (apiData [ ( "team", [] ) ])
  2244                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2245                                  |> Tuple.first
  2246                                  |> Application.handleCallback
  2247                                      (Callback.AllPipelinesFetched <|
  2248                                          Ok
  2249                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2250                                      )
  2251                                  |> Tuple.first
  2252                                  |> Common.queryView
  2253                                  |> Query.find [ class "card-footer" ]
  2254                                  |> Query.find
  2255                                      (iconSelector
  2256                                          { size = "20px"
  2257                                          , image = Assets.PauseIcon
  2258                                          }
  2259                                      )
  2260                                  |> Query.has [ style "cursor" "pointer" ]
  2261                      , test "pause button is transparent" <|
  2262                          \_ ->
  2263                              whenOnDashboard { highDensity = False }
  2264                                  |> givenDataAndUser
  2265                                      (apiData [ ( "team", [] ) ])
  2266                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2267                                  |> Tuple.first
  2268                                  |> Application.handleCallback
  2269                                      (Callback.AllPipelinesFetched <|
  2270                                          Ok
  2271                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2272                                      )
  2273                                  |> Tuple.first
  2274                                  |> Common.queryView
  2275                                  |> Query.find [ class "card-footer" ]
  2276                                  |> Query.find
  2277                                      (iconSelector
  2278                                          { size = "20px"
  2279                                          , image = Assets.PauseIcon
  2280                                          }
  2281                                      )
  2282                                  |> Query.has [ style "opacity" "0.5" ]
  2283                      , defineHoverBehaviour
  2284                          { name = "pause button"
  2285                          , setup =
  2286                              whenOnDashboard { highDensity = False }
  2287                                  |> givenDataAndUser
  2288                                      (apiData [ ( "team", [] ) ])
  2289                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2290                                  |> Tuple.first
  2291                                  |> Application.handleCallback
  2292                                      (Callback.AllPipelinesFetched <|
  2293                                          Ok
  2294                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2295                                      )
  2296                                  |> Tuple.first
  2297                          , query =
  2298                              Common.queryView
  2299                                  >> Query.find [ class "card-footer" ]
  2300                                  >> Query.children []
  2301                                  >> Query.index -1
  2302                                  >> Query.children []
  2303                                  >> Query.index 0
  2304                          , unhoveredSelector =
  2305                              { description = "a faded 20px square pause button with pointer cursor"
  2306                              , selector =
  2307                                  iconSelector
  2308                                      { size = "20px"
  2309                                      , image = Assets.PauseIcon
  2310                                      }
  2311                                      ++ [ style "cursor" "pointer"
  2312                                         , style "opacity" "0.5"
  2313                                         ]
  2314                              }
  2315                          , hoverable = Msgs.PipelineCardPauseToggle AllPipelinesSection Data.pipelineId
  2316                          , hoveredSelector =
  2317                              { description = "a bright 20px square pause button with pointer cursor"
  2318                              , selector =
  2319                                  iconSelector
  2320                                      { size = "20px"
  2321                                      , image = Assets.PauseIcon
  2322                                      }
  2323                                      ++ [ style "cursor" "pointer"
  2324                                         , style "opacity" "1"
  2325                                         ]
  2326                              }
  2327                          }
  2328                      , defineHoverBehaviour
  2329                          { name = "pause button in favorites section"
  2330                          , setup =
  2331                              whenOnDashboard { highDensity = False }
  2332                                  |> givenDataAndUser
  2333                                      (apiData [ ( "team", [] ) ])
  2334                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2335                                  |> Tuple.first
  2336                                  |> Application.handleCallback
  2337                                      (Callback.AllPipelinesFetched <|
  2338                                          Ok
  2339                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2340                                      )
  2341                                  |> Tuple.first
  2342                                  |> Application.handleDelivery
  2343                                      (Message.Subscription.FavoritedPipelinesReceived <| Ok <| Set.singleton 0)
  2344                                  |> Tuple.first
  2345                          , query =
  2346                              Common.queryView
  2347                                  >> Query.findAll [ class "card-footer" ]
  2348                                  >> Query.first
  2349                                  >> Query.children []
  2350                                  >> Query.index -1
  2351                                  >> Query.children []
  2352                                  >> Query.index 0
  2353                          , unhoveredSelector =
  2354                              { description = "a faded 20px square pause button with pointer cursor"
  2355                              , selector =
  2356                                  iconSelector
  2357                                      { size = "20px"
  2358                                      , image = Assets.PauseIcon
  2359                                      }
  2360                                      ++ [ style "cursor" "pointer"
  2361                                         , style "opacity" "0.5"
  2362                                         ]
  2363                              }
  2364                          , hoverable =
  2365                              Msgs.PipelineCardPauseToggle FavoritesSection Data.pipelineId
  2366                          , hoveredSelector =
  2367                              { description = "a bright 20px square pause button with pointer cursor"
  2368                              , selector =
  2369                                  iconSelector
  2370                                      { size = "20px"
  2371                                      , image = Assets.PauseIcon
  2372                                      }
  2373                                      ++ [ style "cursor" "pointer"
  2374                                         , style "opacity" "1"
  2375                                         ]
  2376                              }
  2377                          }
  2378                      , defineHoverBehaviour
  2379                          { name = "play button"
  2380                          , setup =
  2381                              whenOnDashboard { highDensity = False }
  2382                                  |> givenDataAndUser
  2383                                      (apiData [ ( "team", [] ) ])
  2384                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2385                                  |> Tuple.first
  2386                                  |> Application.handleCallback
  2387                                      (Callback.AllPipelinesFetched <|
  2388                                          Ok
  2389                                              [ Data.pipeline "team" 0
  2390                                                  |> Data.withName "pipeline"
  2391                                                  |> Data.withPaused True
  2392                                              ]
  2393                                      )
  2394                                  |> Tuple.first
  2395                          , query =
  2396                              Common.queryView
  2397                                  >> Query.find [ class "card-footer" ]
  2398                                  >> Query.children []
  2399                                  >> Query.index -1
  2400                                  >> Query.children []
  2401                                  >> Query.index 0
  2402                          , unhoveredSelector =
  2403                              { description = "a transparent 20px square play button with pointer cursor"
  2404                              , selector =
  2405                                  iconSelector
  2406                                      { size = "20px"
  2407                                      , image = Assets.PlayIcon
  2408                                      }
  2409                                      ++ [ style "cursor" "pointer"
  2410                                         , style "opacity" "0.5"
  2411                                         ]
  2412                              }
  2413                          , hoverable = Msgs.PipelineCardPauseToggle AllPipelinesSection Data.pipelineId
  2414                          , hoveredSelector =
  2415                              { description = "an opaque 20px square play button with pointer cursor"
  2416                              , selector =
  2417                                  iconSelector
  2418                                      { size = "20px"
  2419                                      , image = Assets.PlayIcon
  2420                                      }
  2421                                      ++ [ style "cursor" "pointer"
  2422                                         , style "opacity" "1"
  2423                                         ]
  2424                              }
  2425                          }
  2426                      , test "clicking pause button sends TogglePipeline msg" <|
  2427                          \_ ->
  2428                              whenOnDashboard { highDensity = False }
  2429                                  |> givenDataAndUser
  2430                                      (apiData [ ( "team", [] ) ])
  2431                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2432                                  |> Tuple.first
  2433                                  |> Application.handleCallback
  2434                                      (Callback.AllPipelinesFetched <|
  2435                                          Ok
  2436                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2437                                      )
  2438                                  |> Tuple.first
  2439                                  |> Common.queryView
  2440                                  |> Query.find [ class "card-footer" ]
  2441                                  |> Query.find [ class "pause-toggle" ]
  2442                                  |> Event.simulate Event.click
  2443                                  |> Event.expect
  2444                                      (ApplicationMsgs.Update <|
  2445                                          Msgs.Click <|
  2446                                              Msgs.PipelineCardPauseToggle AllPipelinesSection Data.pipelineId
  2447                                      )
  2448                      , test "pause button turns into spinner on click" <|
  2449                          \_ ->
  2450                              let
  2451                                  animation =
  2452                                      "container-rotate 1568ms linear infinite"
  2453                              in
  2454                              whenOnDashboard { highDensity = False }
  2455                                  |> givenDataAndUser
  2456                                      (apiData [ ( "team", [] ) ])
  2457                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2458                                  |> Tuple.first
  2459                                  |> Application.handleCallback
  2460                                      (Callback.AllPipelinesFetched <|
  2461                                          Ok
  2462                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2463                                      )
  2464                                  |> Tuple.first
  2465                                  |> Application.update
  2466                                      (ApplicationMsgs.Update <|
  2467                                          Msgs.Click <|
  2468                                              Msgs.PipelineCardPauseToggle AllPipelinesSection Data.pipelineId
  2469                                      )
  2470                                  |> Tuple.first
  2471                                  |> Common.queryView
  2472                                  |> Query.find [ class "card-footer" ]
  2473                                  |> Query.has [ style "animation" animation ]
  2474                      , test "clicking pause button sends toggle api call" <|
  2475                          \_ ->
  2476                              whenOnDashboard { highDensity = False }
  2477                                  |> givenDataAndUser
  2478                                      (apiData [ ( "team", [] ) ])
  2479                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2480                                  |> Tuple.first
  2481                                  |> Application.handleCallback
  2482                                      (Callback.AllPipelinesFetched <|
  2483                                          Ok
  2484                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2485                                      )
  2486                                  |> Tuple.first
  2487                                  |> Application.update
  2488                                      (ApplicationMsgs.Update <|
  2489                                          Msgs.Click <|
  2490                                              Msgs.PipelineCardPauseToggle AllPipelinesSection Data.pipelineId
  2491                                      )
  2492                                  |> Tuple.second
  2493                                  |> Expect.equal [ Effects.SendTogglePipelineRequest Data.pipelineId False ]
  2494                      , test "all pipelines are refetched after ok toggle call" <|
  2495                          \_ ->
  2496                              whenOnDashboard { highDensity = False }
  2497                                  |> givenDataAndUser
  2498                                      (apiData [ ( "team", [] ) ])
  2499                                      (userWithRoles [ ( "team", [ "owner" ] ) ])
  2500                                  |> Tuple.first
  2501                                  |> Application.handleCallback
  2502                                      (Callback.AllPipelinesFetched <|
  2503                                          Ok
  2504                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2505                                      )
  2506                                  |> Tuple.first
  2507                                  |> Application.update
  2508                                      (ApplicationMsgs.Update <|
  2509                                          Msgs.Click <|
  2510                                              Msgs.PipelineCardPauseToggle AllPipelinesSection Data.pipelineId
  2511                                      )
  2512                                  |> Tuple.first
  2513                                  |> Application.handleCallback
  2514                                      (Callback.PipelineToggled Data.pipelineId (Ok ()))
  2515                                  |> Tuple.second
  2516                                  |> Expect.equal [ Effects.FetchAllPipelines ]
  2517                      , test "401 toggle call redirects to login" <|
  2518                          \_ ->
  2519                              whenOnDashboard { highDensity = False }
  2520                                  |> givenDataUnauthenticated
  2521                                      (apiData [ ( "team", [] ) ])
  2522                                  |> Tuple.first
  2523                                  |> Application.handleCallback
  2524                                      (Callback.AllPipelinesFetched <|
  2525                                          Ok
  2526                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2527                                      )
  2528                                  |> Tuple.first
  2529                                  |> Application.update
  2530                                      (ApplicationMsgs.Update <|
  2531                                          Msgs.Click <|
  2532                                              Msgs.PipelineCardPauseToggle AllPipelinesSection Data.pipelineId
  2533                                      )
  2534                                  |> Tuple.first
  2535                                  |> Application.handleCallback
  2536                                      (Callback.PipelineToggled Data.pipelineId Data.httpUnauthorized)
  2537                                  |> Tuple.second
  2538                                  |> Expect.equal [ Effects.RedirectToLogin ]
  2539                      ]
  2540                  , describe "favorited icon" <|
  2541                      let
  2542                          pipelineId =
  2543                              0
  2544  
  2545                          unfilledFavoritedIcon =
  2546                              iconSelector
  2547                                  { size = "20px"
  2548                                  , image = Assets.FavoritedToggleIcon { isFavorited = False, isHovered = False, isSideBar = False }
  2549                                  }
  2550                                  ++ [ style "background-size" "contain" ]
  2551  
  2552                          unfilledBrightFavoritedIcon =
  2553                              iconSelector
  2554                                  { size = "20px"
  2555                                  , image = Assets.FavoritedToggleIcon { isFavorited = False, isHovered = True, isSideBar = False }
  2556                                  }
  2557                                  ++ [ style "background-size" "contain" ]
  2558  
  2559                          filledFavoritedIcon =
  2560                              iconSelector
  2561                                  { size = "20px"
  2562                                  , image = Assets.FavoritedToggleIcon { isFavorited = True, isHovered = False, isSideBar = False }
  2563                                  }
  2564                                  ++ [ style "background-size" "contain" ]
  2565  
  2566                          favoritedToggle =
  2567                              Common.queryView
  2568                                  >> Query.findAll [ class "card-footer" ]
  2569                                  >> Query.first
  2570                                  >> Query.children []
  2571                                  >> Query.index -1
  2572                                  >> Query.children []
  2573                                  >> Query.index -1
  2574  
  2575                          favoritedIconClickable setup =
  2576                              [ defineHoverBehaviour
  2577                                  { name = "favorited icon toggle"
  2578                                  , setup =
  2579                                      whenOnDashboard { highDensity = False }
  2580                                          |> setup
  2581                                          |> Tuple.first
  2582                                  , query = favoritedToggle
  2583                                  , unhoveredSelector =
  2584                                      { description = "faded 20px square"
  2585                                      , selector =
  2586                                          unfilledFavoritedIcon
  2587                                              ++ [ style "cursor" "pointer" ]
  2588                                      }
  2589                                  , hoverable =
  2590                                      Msgs.PipelineCardFavoritedIcon AllPipelinesSection pipelineId
  2591                                  , hoveredSelector =
  2592                                      { description = "bright 20px square"
  2593                                      , selector =
  2594                                          unfilledBrightFavoritedIcon
  2595                                              ++ [ style "cursor" "pointer" ]
  2596                                      }
  2597                                  }
  2598                              , test "has click handler" <|
  2599                                  \_ ->
  2600                                      whenOnDashboard { highDensity = False }
  2601                                          |> setup
  2602                                          |> Tuple.first
  2603                                          |> favoritedToggle
  2604                                          |> Event.simulate Event.click
  2605                                          |> Event.expect
  2606                                              (ApplicationMsgs.Update <|
  2607                                                  Msgs.Click <|
  2608                                                      Msgs.PipelineCardFavoritedIcon
  2609                                                          AllPipelinesSection
  2610                                                          pipelineId
  2611                                              )
  2612                              , test "click has FavoritedPipeline effect" <|
  2613                                  \_ ->
  2614                                      whenOnDashboard { highDensity = False }
  2615                                          |> setup
  2616                                          |> Tuple.first
  2617                                          |> Application.update
  2618                                              (ApplicationMsgs.Update <|
  2619                                                  Msgs.Click <|
  2620                                                      Msgs.PipelineCardFavoritedIcon
  2621                                                          AllPipelinesSection
  2622                                                          pipelineId
  2623                                              )
  2624                                          |> Tuple.second
  2625                                          |> Expect.equal
  2626                                              [ Effects.SaveFavoritedPipelines <|
  2627                                                  Set.singleton pipelineId
  2628                                              ]
  2629                              , test "favorited pipeline card has a bright filled star icon" <|
  2630                                  \_ ->
  2631                                      whenOnDashboard { highDensity = False }
  2632                                          |> setup
  2633                                          |> Tuple.first
  2634                                          |> Application.handleDelivery
  2635                                              (FavoritedPipelinesReceived <|
  2636                                                  Ok <|
  2637                                                      Set.singleton pipelineId
  2638                                              )
  2639                                          |> Tuple.first
  2640                                          |> favoritedToggle
  2641                                          |> Expect.all
  2642                                              [ Query.has filledFavoritedIcon
  2643                                              ]
  2644                              ]
  2645                      in
  2646                      favoritedIconClickable
  2647                          (givenDataAndUser
  2648                              (apiData [ ( "team", [] ) ])
  2649                              (userWithRoles
  2650                                  [ ( "team", [ "owner" ] ) ]
  2651                              )
  2652                              >> Tuple.first
  2653                              >> Application.handleCallback
  2654                                  (Callback.AllPipelinesFetched <|
  2655                                      Ok
  2656                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  2657                                  )
  2658                          )
  2659                  ]
  2660              ]
  2661          ]