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

     1  module DashboardTests exposing
     2      ( afterSeconds
     3      , all
     4      , almostBlack
     5      , amber
     6      , apiData
     7      , blue
     8      , brown
     9      , circularJobs
    10      , darkGrey
    11      , fadedGreen
    12      , givenDataAndUser
    13      , givenDataUnauthenticated
    14      , green
    15      , iconSelector
    16      , job
    17      , jobWithNameTransitionedAt
    18      , lightGrey
    19      , middleGrey
    20      , orange
    21      , otherJob
    22      , red
    23      , running
    24      , userWithRoles
    25      , whenOnDashboard
    26      , whenOnDashboardViewingAllPipelines
    27      , white
    28      )
    29  
    30  import Application.Application as Application
    31  import Assets
    32  import ColorValues
    33  import Common
    34      exposing
    35          ( defineHoverBehaviour
    36          , isColorWithStripes
    37          , pipelineRunningKeyframes
    38          )
    39  import Concourse
    40  import Concourse.BuildStatus exposing (BuildStatus(..))
    41  import Concourse.Cli as Cli
    42  import Concourse.PipelineStatus exposing (PipelineStatus(..))
    43  import Data
    44  import Dict
    45  import Expect exposing (Expectation)
    46  import Html.Attributes as Attr
    47  import Http
    48  import Keyboard
    49  import Message.Callback as Callback
    50  import Message.Effects as Effects
    51  import Message.Message as Msgs
    52  import Message.Subscription as Subscription exposing (Delivery(..), Interval(..))
    53  import Message.TopLevelMessage as ApplicationMsgs
    54  import Routes
    55  import Set
    56  import Test exposing (..)
    57  import Test.Html.Event as Event
    58  import Test.Html.Query as Query
    59  import Test.Html.Selector
    60      exposing
    61          ( Selector
    62          , attribute
    63          , class
    64          , containing
    65          , id
    66          , style
    67          , tag
    68          , text
    69          )
    70  import Time
    71  import Url
    72  
    73  
    74  almostBlack : String
    75  almostBlack =
    76      "#1e1d1d"
    77  
    78  
    79  middleGrey : String
    80  middleGrey =
    81      "#3d3c3c"
    82  
    83  
    84  lightGrey : String
    85  lightGrey =
    86      "#9b9b9b"
    87  
    88  
    89  menuGrey : String
    90  menuGrey =
    91      "#868585"
    92  
    93  
    94  green : String
    95  green =
    96      "#11c560"
    97  
    98  
    99  blue : String
   100  blue =
   101      "#3498db"
   102  
   103  
   104  darkGrey : String
   105  darkGrey =
   106      "#2a2929"
   107  
   108  
   109  red : String
   110  red =
   111      "#ed4b35"
   112  
   113  
   114  amber : String
   115  amber =
   116      "#f5a623"
   117  
   118  
   119  brown : String
   120  brown =
   121      "#8b572a"
   122  
   123  
   124  white : String
   125  white =
   126      "#ffffff"
   127  
   128  
   129  fadedGreen : String
   130  fadedGreen =
   131      "#419867"
   132  
   133  
   134  orange : String
   135  orange =
   136      "#e67e22"
   137  
   138  
   139  pipelineRunningKeyframes : String
   140  pipelineRunningKeyframes =
   141      "pipeline-running"
   142  
   143  
   144  flags : Application.Flags
   145  flags =
   146      { turbulenceImgSrc = ""
   147      , notFoundImgSrc = ""
   148      , csrfToken = csrfToken
   149      , authToken = ""
   150      , pipelineRunningKeyframes = pipelineRunningKeyframes
   151      }
   152  
   153  
   154  all : Test
   155  all =
   156      describe "Dashboard"
   157          [ test "requests screen size on page load" <|
   158              \_ ->
   159                  Application.init
   160                      { turbulenceImgSrc = ""
   161                      , notFoundImgSrc = "notfound.svg"
   162                      , csrfToken = "csrf_token"
   163                      , authToken = ""
   164                      , pipelineRunningKeyframes = "pipeline-running"
   165                      }
   166                      { protocol = Url.Http
   167                      , host = ""
   168                      , port_ = Nothing
   169                      , path = "/"
   170                      , query = Nothing
   171                      , fragment = Nothing
   172                      }
   173                      |> Tuple.second
   174                      |> Common.contains Effects.GetScreenSize
   175          , test "requests cluster info on page load" <|
   176              \_ ->
   177                  Application.init
   178                      { turbulenceImgSrc = ""
   179                      , notFoundImgSrc = "notfound.svg"
   180                      , csrfToken = "csrf_token"
   181                      , authToken = ""
   182                      , pipelineRunningKeyframes = "pipeline-running"
   183                      }
   184                      { protocol = Url.Http
   185                      , host = ""
   186                      , port_ = Nothing
   187                      , path = "/"
   188                      , query = Nothing
   189                      , fragment = Nothing
   190                      }
   191                      |> Tuple.second
   192                      |> Common.contains Effects.FetchClusterInfo
   193          , test "requests all resources on page load" <|
   194              \_ ->
   195                  Application.init
   196                      { turbulenceImgSrc = ""
   197                      , notFoundImgSrc = "notfound.svg"
   198                      , csrfToken = "csrf_token"
   199                      , authToken = ""
   200                      , pipelineRunningKeyframes = ""
   201                      }
   202                      { protocol = Url.Http
   203                      , host = ""
   204                      , port_ = Nothing
   205                      , path = "/"
   206                      , query = Nothing
   207                      , fragment = Nothing
   208                      }
   209                      |> Tuple.second
   210                      |> Common.contains Effects.FetchAllResources
   211          , test "requests all jobs on page load" <|
   212              \_ ->
   213                  Application.init
   214                      { turbulenceImgSrc = ""
   215                      , notFoundImgSrc = "notfound.svg"
   216                      , csrfToken = "csrf_token"
   217                      , authToken = ""
   218                      , pipelineRunningKeyframes = ""
   219                      }
   220                      { protocol = Url.Http
   221                      , host = ""
   222                      , port_ = Nothing
   223                      , path = "/"
   224                      , query = Nothing
   225                      , fragment = Nothing
   226                      }
   227                      |> Tuple.second
   228                      |> Common.contains Effects.FetchAllJobs
   229          , test "requests all pipelines on page load" <|
   230              \_ ->
   231                  Application.init
   232                      { turbulenceImgSrc = ""
   233                      , notFoundImgSrc = "notfound.svg"
   234                      , csrfToken = "csrf_token"
   235                      , authToken = ""
   236                      , pipelineRunningKeyframes = ""
   237                      }
   238                      { protocol = Url.Http
   239                      , host = ""
   240                      , port_ = Nothing
   241                      , path = "/"
   242                      , query = Nothing
   243                      , fragment = Nothing
   244                      }
   245                      |> Tuple.second
   246                      |> Common.contains Effects.FetchAllPipelines
   247          , test "redirects to login if any data call gives a 401" <|
   248              \_ ->
   249                  Common.init "/"
   250                      |> Application.handleCallback
   251                          (Callback.AllTeamsFetched <|
   252                              Data.httpUnauthorized
   253                          )
   254                      |> Tuple.second
   255                      |> Expect.equal [ Effects.RedirectToLogin ]
   256          , test "retries the request after 1 second if ListAllJobs call gives a 503" <|
   257              \_ ->
   258                  Common.init "/"
   259                      |> Application.handleCallback
   260                          (Callback.AllJobsFetched <|
   261                              Err <|
   262                                  Http.BadStatus
   263                                      { url = "http://example.com"
   264                                      , status =
   265                                          { code = 503
   266                                          , message = "service unavailable"
   267                                          }
   268                                      , headers = Dict.empty
   269                                      , body = ""
   270                                      }
   271                          )
   272                      |> Tuple.first
   273                      |> Application.handleDelivery
   274                          (ClockTicked OneSecond <|
   275                              Time.millisToPosix 1000
   276                          )
   277                      |> Tuple.second
   278                      |> Expect.equal [ Effects.FetchAllJobs ]
   279          , test "only retries the request once per 503 response" <|
   280              \_ ->
   281                  Common.init "/"
   282                      |> Application.handleCallback
   283                          (Callback.AllJobsFetched <|
   284                              Err <|
   285                                  Http.BadStatus
   286                                      { url = "http://example.com"
   287                                      , status =
   288                                          { code = 503
   289                                          , message = "service unavailable"
   290                                          }
   291                                      , headers = Dict.empty
   292                                      , body = ""
   293                                      }
   294                          )
   295                      |> Tuple.first
   296                      |> Application.handleDelivery
   297                          (ClockTicked OneSecond <|
   298                              Time.millisToPosix 1000
   299                          )
   300                      |> Tuple.first
   301                      |> Application.handleDelivery
   302                          (ClockTicked OneSecond <|
   303                              Time.millisToPosix 1000
   304                          )
   305                      |> Tuple.second
   306                      |> Expect.equal []
   307          , test "does not show turbulence screen on 503" <|
   308              \_ ->
   309                  Common.init "/"
   310                      |> Application.handleCallback
   311                          (Callback.AllJobsFetched <|
   312                              Err <|
   313                                  Http.BadStatus
   314                                      { url = "http://example.com"
   315                                      , status =
   316                                          { code = 503
   317                                          , message = "service unavailable"
   318                                          }
   319                                      , headers = Dict.empty
   320                                      , body = ""
   321                                      }
   322                          )
   323                      |> Tuple.first
   324                      |> Common.queryView
   325                      |> Query.hasNot [ text "experiencing turbulence" ]
   326          , test "shows turbulence view if the all teams call gives a bad status error" <|
   327              \_ ->
   328                  Common.init "/"
   329                      |> Application.handleCallback
   330                          (Callback.AllTeamsFetched <| Data.httpInternalServerError)
   331                      |> Tuple.first
   332                      |> Common.queryView
   333                      |> Query.has [ text "experiencing turbulence" ]
   334          , test "recovers from turbulence view if all teams call succeeds" <|
   335              \_ ->
   336                  Common.init "/"
   337                      |> Application.handleCallback
   338                          (Callback.AllTeamsFetched <| Data.httpInternalServerError)
   339                      |> Tuple.first
   340                      |> Application.handleCallback
   341                          (Callback.AllTeamsFetched <| Ok [])
   342                      |> Tuple.first
   343                      |> Common.queryView
   344                      |> Query.hasNot [ text "experiencing turbulence" ]
   345          , test "shows turbulence view if the all resources call gives a bad status error" <|
   346              \_ ->
   347                  Common.init "/"
   348                      |> Application.handleCallback
   349                          (Callback.AllResourcesFetched <| Data.httpInternalServerError)
   350                      |> Tuple.first
   351                      |> Common.queryView
   352                      |> Query.has [ text "experiencing turbulence" ]
   353          , test "recovers from turbulence view if all resources call succeeds" <|
   354              \_ ->
   355                  Common.init "/"
   356                      |> Application.handleCallback
   357                          (Callback.AllResourcesFetched <| Data.httpInternalServerError)
   358                      |> Tuple.first
   359                      |> Application.handleCallback
   360                          (Callback.AllResourcesFetched <| Ok [])
   361                      |> Tuple.first
   362                      |> Common.queryView
   363                      |> Query.hasNot [ text "experiencing turbulence" ]
   364          , test "shows turbulence view if the all jobs call gives a bad status error" <|
   365              \_ ->
   366                  Common.init "/"
   367                      |> Application.handleCallback
   368                          (Callback.AllJobsFetched <| Data.httpInternalServerError)
   369                      |> Tuple.first
   370                      |> Common.queryView
   371                      |> Query.has [ text "experiencing turbulence" ]
   372          , test "recovers from turbulence view if all jobs call succeeds" <|
   373              \_ ->
   374                  Common.init "/"
   375                      |> Application.handleCallback
   376                          (Callback.AllJobsFetched <| Data.httpInternalServerError)
   377                      |> Tuple.first
   378                      |> Application.handleCallback
   379                          (Callback.AllJobsFetched <| Ok [])
   380                      |> Tuple.first
   381                      |> Common.queryView
   382                      |> Query.hasNot [ text "experiencing turbulence" ]
   383          , test "shows turbulence view if the all pipelines call gives a bad status error" <|
   384              \_ ->
   385                  Common.init "/"
   386                      |> Application.handleCallback
   387                          (Callback.AllPipelinesFetched <| Data.httpInternalServerError)
   388                      |> Tuple.first
   389                      |> Common.queryView
   390                      |> Query.has [ text "experiencing turbulence" ]
   391          , test "recovers from turbulence view if all pipelines call succeeds" <|
   392              \_ ->
   393                  Common.init "/"
   394                      |> Application.handleCallback
   395                          (Callback.AllPipelinesFetched <| Data.httpInternalServerError)
   396                      |> Tuple.first
   397                      |> Application.handleCallback
   398                          (Callback.AllPipelinesFetched <| Ok [])
   399                      |> Tuple.first
   400                      |> Common.queryView
   401                      |> Query.hasNot [ text "experiencing turbulence" ]
   402          , test "does not recover from turbulence view if some endpoints are still errored" <|
   403              \_ ->
   404                  Common.init "/"
   405                      |> Application.handleCallback
   406                          (Callback.AllJobsFetched <| Data.httpInternalServerError)
   407                      |> Tuple.first
   408                      |> Application.handleCallback
   409                          (Callback.AllPipelinesFetched <| Data.httpInternalServerError)
   410                      |> Tuple.first
   411                      |> Application.handleCallback
   412                          (Callback.AllPipelinesFetched <| Ok [])
   413                      |> Tuple.first
   414                      |> Common.queryView
   415                      |> Query.has [ text "experiencing turbulence" ]
   416          , test "title says 'Dashboard - Concourse'" <|
   417              \_ ->
   418                  Common.init "/"
   419                      |> Application.view
   420                      |> .title
   421                      |> Expect.equal "Dashboard - Concourse"
   422          , test "renders cluster name at top left" <|
   423              \_ ->
   424                  Common.init "/"
   425                      |> givenClusterInfo "0.0.0-dev" "foobar"
   426                      |> Tuple.first
   427                      |> Common.queryView
   428                      |> Query.find [ id "top-bar-app" ]
   429                      |> Query.children []
   430                      |> Query.first
   431                      |> Query.has
   432                          [ style "display" "flex"
   433                          , style "align-items" "center"
   434                          , containing
   435                              [ style "font-size" "21px"
   436                              , style "color" ColorValues.white
   437                              , style "letter-spacing" "0.1em"
   438                              , style "margin-left" "10px"
   439                              , containing [ text "foobar" ]
   440                              ]
   441                          ]
   442          , test "top bar is 54px tall" <|
   443              \_ ->
   444                  Common.init "/"
   445                      |> Common.queryView
   446                      |> Query.find [ id "top-bar-app" ]
   447                      |> Query.has [ style "height" "54px" ]
   448          , describe "loading section" <|
   449              [ test "has a loading section when awaiting API data" <|
   450                  \_ ->
   451                      Common.init "/"
   452                          |> Common.queryView
   453                          |> Query.has [ class "loading" ]
   454              , test "centers spinner" <|
   455                  \_ ->
   456                      Common.init "/"
   457                          |> Common.queryView
   458                          |> Query.has
   459                              [ style "display" "flex"
   460                              , style "justify-content" "center"
   461                              , style "align-items" "center"
   462                              , style "width" "100%"
   463                              , style "height" "100%"
   464                              ]
   465              , test "contains a spinner" <|
   466                  \_ ->
   467                      Common.init "/"
   468                          |> Common.queryView
   469                          |> Query.find [ class "loading" ]
   470                          |> Query.has
   471                              [ style "animation" "container-rotate 1568ms linear infinite"
   472                              , style "height" "36px"
   473                              , style "width" "36px"
   474                              ]
   475              ]
   476          , test "high density view has no vertical scroll" <|
   477              \_ ->
   478                  whenOnDashboard { highDensity = True }
   479                      |> givenDataAndUser
   480                          (apiData [ ( "team", [] ) ])
   481                          (userWithRoles [])
   482                      |> Tuple.first
   483                      |> Application.handleCallback
   484                          (Callback.AllPipelinesFetched <|
   485                              Ok
   486                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   487                          )
   488                      |> Tuple.first
   489                      |> Common.queryView
   490                      |> Query.find [ id "page-below-top-bar" ]
   491                      |> Query.has
   492                          [ style "height" "100%"
   493                          , style "box-sizing" "border-box"
   494                          ]
   495          , test "high density body aligns contents vertically" <|
   496              \_ ->
   497                  whenOnDashboard { highDensity = True }
   498                      |> givenDataAndUser
   499                          (apiData [ ( "team", [] ) ])
   500                          (userWithRoles [])
   501                      |> Tuple.first
   502                      |> Application.handleCallback
   503                          (Callback.AllPipelinesFetched <|
   504                              Ok
   505                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   506                          )
   507                      |> Tuple.first
   508                      |> Common.queryView
   509                      |> Query.find [ id "page-below-top-bar" ]
   510                      |> Query.has
   511                          [ style "display" "flex"
   512                          , style "flex-direction" "column"
   513                          ]
   514          , test "high density pipelines view fills vertical space" <|
   515              \_ ->
   516                  whenOnDashboard { highDensity = True }
   517                      |> givenDataAndUser
   518                          (apiData [ ( "team", [] ) ])
   519                          (userWithRoles [])
   520                      |> Tuple.first
   521                      |> Application.handleCallback
   522                          (Callback.AllPipelinesFetched <|
   523                              Ok
   524                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   525                          )
   526                      |> Tuple.first
   527                      |> Common.queryView
   528                      |> Query.find [ id "page-below-top-bar" ]
   529                      |> Query.find [ class "dashboard" ]
   530                      |> Query.has [ style "flex-grow" "1" ]
   531          , test "high density pipelines view has padding" <|
   532              \_ ->
   533                  whenOnDashboard { highDensity = True }
   534                      |> givenDataAndUser
   535                          (apiData [ ( "team", [] ) ])
   536                          (userWithRoles [])
   537                      |> Tuple.first
   538                      |> Application.handleCallback
   539                          (Callback.AllPipelinesFetched <|
   540                              Ok
   541                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   542                          )
   543                      |> Tuple.first
   544                      |> Common.queryView
   545                      |> Query.find [ id "page-below-top-bar" ]
   546                      |> Query.find [ class "dashboard" ]
   547                      |> Query.has [ style "padding" "60px" ]
   548          , test "high density pipelines view wraps columns" <|
   549              \_ ->
   550                  whenOnDashboard { highDensity = True }
   551                      |> givenDataAndUser
   552                          (apiData [ ( "team", [] ) ])
   553                          (userWithRoles [])
   554                      |> Tuple.first
   555                      |> Application.handleCallback
   556                          (Callback.AllPipelinesFetched <|
   557                              Ok
   558                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   559                          )
   560                      |> Tuple.first
   561                      |> Common.queryView
   562                      |> Query.find [ id "page-below-top-bar" ]
   563                      |> Query.find [ class "dashboard" ]
   564                      |> Query.has
   565                          [ style "display" "flex"
   566                          , style "flex-flow" "column wrap"
   567                          ]
   568          , test "normal density pipelines view has default layout" <|
   569              \_ ->
   570                  whenOnDashboard { highDensity = False }
   571                      |> givenDataAndUser
   572                          (apiData [ ( "team", [] ) ])
   573                          (userWithRoles [])
   574                      |> Tuple.first
   575                      |> Application.handleCallback
   576                          (Callback.AllPipelinesFetched <|
   577                              Ok
   578                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   579                          )
   580                      |> Tuple.first
   581                      |> Common.queryView
   582                      |> Query.find [ id "page-below-top-bar" ]
   583                      |> Query.find [ class "dashboard" ]
   584                      |> Query.has
   585                          [ style "display" "initial"
   586                          , style "padding" "0"
   587                          ]
   588          , test "high density view left-aligns contents" <|
   589              \_ ->
   590                  whenOnDashboard { highDensity = True }
   591                      |> givenDataAndUser
   592                          (apiData [ ( "team", [] ) ])
   593                          (userWithRoles [])
   594                      |> Tuple.first
   595                      |> Application.handleCallback
   596                          (Callback.AllPipelinesFetched <|
   597                              Ok
   598                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   599                          )
   600                      |> Tuple.first
   601                      |> Common.queryView
   602                      |> Query.find [ id "page-below-top-bar" ]
   603                      |> Query.find [ class "dashboard" ]
   604                      |> Query.has [ style "align-content" "flex-start" ]
   605          , test "high density view has no overlapping top bar" <|
   606              \_ ->
   607                  whenOnDashboard { highDensity = True }
   608                      |> Common.queryView
   609                      |> Query.find [ id "page-below-top-bar" ]
   610                      |> Query.has [ style "padding-top" "54px" ]
   611          , test "high density view has no overlapping bottom bar" <|
   612              \_ ->
   613                  whenOnDashboard { highDensity = True }
   614                      |> givenDataAndUser
   615                          (apiData [ ( "team", [] ) ])
   616                          (userWithRoles [])
   617                      |> Tuple.first
   618                      |> Application.handleCallback
   619                          (Callback.AllPipelinesFetched <|
   620                              Ok
   621                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   622                          )
   623                      |> Tuple.first
   624                      |> Common.queryView
   625                      |> Query.find [ id "page-below-top-bar" ]
   626                      |> Query.has [ style "padding-bottom" "50px" ]
   627          , test "no bottom padding when footer dismisses" <|
   628              \_ ->
   629                  whenOnDashboard { highDensity = True }
   630                      |> givenDataAndUser
   631                          (apiData [ ( "team", [] ) ])
   632                          (userWithRoles [])
   633                      |> Tuple.first
   634                      |> Application.handleCallback
   635                          (Callback.AllPipelinesFetched <|
   636                              Ok
   637                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   638                          )
   639                      |> Tuple.first
   640                      |> afterSeconds 6
   641                      |> Common.queryView
   642                      |> Query.find [ id "page-below-top-bar" ]
   643                      |> Query.hasNot [ style "padding-bottom" "50px" ]
   644          , test "logging out causes pipeline list to reload" <|
   645              let
   646                  showsLoadingState : Application.Model -> Expectation
   647                  showsLoadingState =
   648                      Common.queryView
   649                          >> Query.findAll [ class "dashboard-team-group" ]
   650                          >> Query.count (Expect.equal 0)
   651              in
   652              \_ ->
   653                  whenOnDashboard { highDensity = False }
   654                      |> givenDataAndUser
   655                          (apiData [ ( "team", [] ) ])
   656                          (userWithRoles [ ( "team", [ "owner" ] ) ])
   657                      |> Tuple.first
   658                      |> Application.handleCallback
   659                          (Callback.AllPipelinesFetched <|
   660                              Ok
   661                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   662                          )
   663                      |> Tuple.first
   664                      |> Application.update
   665                          (ApplicationMsgs.Update <|
   666                              Msgs.Click Msgs.LogoutButton
   667                          )
   668                      |> Tuple.first
   669                      |> showsLoadingState
   670          , test "pipeline cards continue to show when teams refresh" <|
   671              \_ ->
   672                  whenOnDashboard { highDensity = False }
   673                      |> Application.handleCallback
   674                          (Callback.AllPipelinesFetched <|
   675                              Ok
   676                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   677                          )
   678                      |> Tuple.first
   679                      |> givenDataUnauthenticated []
   680                      |> Tuple.first
   681                      |> Common.queryView
   682                      |> Query.has [ class "card", containing [ text "pipeline" ] ]
   683          , test "high-density pipeline cards continue to show when teams refresh" <|
   684              \_ ->
   685                  whenOnDashboard { highDensity = True }
   686                      |> Application.handleCallback
   687                          (Callback.AllPipelinesFetched <|
   688                              Ok
   689                                  [ Data.pipeline "team" 0 |> Data.withName "a-pipeline" ]
   690                          )
   691                      |> Tuple.first
   692                      |> givenDataUnauthenticated []
   693                      |> Tuple.first
   694                      |> Common.queryView
   695                      |> Query.has [ class "card", containing [ text "a-pipeline" ] ]
   696          , test "links to specific builds" <|
   697              \_ ->
   698                  whenOnDashboard { highDensity = False }
   699                      |> Application.handleCallback
   700                          (Callback.AllJobsFetched <|
   701                              Ok
   702                                  [ { name = "job"
   703                                    , pipelineName = "pipeline"
   704                                    , teamName = "team"
   705                                    , nextBuild = Nothing
   706                                    , finishedBuild =
   707                                          Just
   708                                              { id = 0
   709                                              , name = "1"
   710                                              , job = Just Data.jobId
   711                                              , status = BuildStatusSucceeded
   712                                              , duration = { startedAt = Nothing, finishedAt = Nothing }
   713                                              , reapTime = Nothing
   714                                              }
   715                                    , transitionBuild = Nothing
   716                                    , paused = False
   717                                    , disableManualTrigger = False
   718                                    , inputs = []
   719                                    , outputs = []
   720                                    , groups = []
   721                                    }
   722                                  ]
   723                          )
   724                      |> Tuple.first
   725                      |> givenDataUnauthenticated []
   726                      |> Tuple.first
   727                      |> Application.handleCallback
   728                          (Callback.AllPipelinesFetched <|
   729                              Ok
   730                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   731                          )
   732                      |> Tuple.first
   733                      |> Common.queryView
   734                      |> Query.find
   735                          [ class "dashboard-team-group"
   736                          , attribute <| Attr.attribute "data-team-name" "team"
   737                          ]
   738                      |> Query.find
   739                          [ attribute <| Attr.attribute "data-tooltip" "job" ]
   740                      |> Query.find
   741                          [ tag "a" ]
   742                      |> Query.has
   743                          [ attribute <|
   744                              Attr.href "/teams/team/pipelines/pipeline/jobs/job/builds/1"
   745                          ]
   746          , test "HD view redirects to no pipelines view when there are no pipelines" <|
   747              \_ ->
   748                  whenOnDashboard { highDensity = True }
   749                      |> Application.handleCallback
   750                          (Callback.AllTeamsFetched <|
   751                              Ok <|
   752                                  apiData [ ( "team", [] ) ]
   753                          )
   754                      |> Tuple.first
   755                      |> Application.handleCallback
   756                          (Callback.AllPipelinesFetched <|
   757                              Ok []
   758                          )
   759                      |> Expect.all
   760                          [ Tuple.second
   761                              >> Common.contains (Effects.ModifyUrl "/")
   762                          , Tuple.first
   763                              >> Common.queryView
   764                              >> Query.has [ text "welcome to concourse!" ]
   765                          ]
   766          , test "HD view does not redirect when there are pipelines" <|
   767              \_ ->
   768                  whenOnDashboard { highDensity = True }
   769                      |> Application.handleCallback
   770                          (Callback.AllTeamsFetched <|
   771                              Ok <|
   772                                  apiData [ ( "team", [] ) ]
   773                          )
   774                      |> Tuple.first
   775                      |> Application.handleCallback
   776                          (Callback.AllPipelinesFetched <|
   777                              Ok
   778                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   779                          )
   780                      |> Expect.all
   781                          [ Tuple.second
   782                              >> Expect.notEqual [ Effects.ModifyUrl "/" ]
   783                          , Tuple.first
   784                              >> Common.queryView
   785                              >> Query.hasNot [ text "welcome to concourse!" ]
   786                          ]
   787          , test "no search bar when there are no pipelines" <|
   788              \_ ->
   789                  whenOnDashboard { highDensity = False }
   790                      |> Application.handleCallback
   791                          (Callback.AllTeamsFetched <|
   792                              Ok <|
   793                                  apiData [ ( "team", [] ) ]
   794                          )
   795                      |> Tuple.first
   796                      |> Common.queryView
   797                      |> Query.hasNot [ tag "input" ]
   798          , test "typing '?' in search bar does not toggle help" <|
   799              \_ ->
   800                  whenOnDashboard { highDensity = False }
   801                      |> Application.handleCallback
   802                          (Callback.AllTeamsFetched <|
   803                              Ok <|
   804                                  apiData [ ( "team", [] ) ]
   805                          )
   806                      |> Tuple.first
   807                      |> Application.handleCallback
   808                          (Callback.AllPipelinesFetched <|
   809                              Ok
   810                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   811                          )
   812                      |> Tuple.first
   813                      |> Application.update (ApplicationMsgs.Update Msgs.FocusMsg)
   814                      |> Tuple.first
   815                      |> Application.handleDelivery
   816                          (KeyDown
   817                              { ctrlKey = False
   818                              , shiftKey = True
   819                              , metaKey = False
   820                              , code = Keyboard.Slash
   821                              }
   822                          )
   823                      |> Tuple.first
   824                      |> Common.queryView
   825                      |> Query.hasNot [ id "keyboard-help" ]
   826          , test "bottom bar appears when there are no pipelines" <|
   827              \_ ->
   828                  whenOnDashboard { highDensity = False }
   829                      |> Application.handleCallback
   830                          (Callback.AllTeamsFetched <|
   831                              Ok <|
   832                                  apiData [ ( "team", [] ) ]
   833                          )
   834                      |> Tuple.first
   835                      |> Common.queryView
   836                      |> Query.has [ id "dashboard-info" ]
   837          , test "bottom bar has no legend when there are no pipelines" <|
   838              \_ ->
   839                  whenOnDashboard { highDensity = False }
   840                      |> Application.handleCallback
   841                          (Callback.AllTeamsFetched <|
   842                              Ok <|
   843                                  apiData [ ( "team", [] ) ]
   844                          )
   845                      |> Tuple.first
   846                      |> Common.queryView
   847                      |> Query.hasNot [ id "legend" ]
   848          , test "concourse info is right-justified when there are no pipelines" <|
   849              \_ ->
   850                  whenOnDashboard { highDensity = False }
   851                      |> Application.handleCallback
   852                          (Callback.AllTeamsFetched <|
   853                              Ok <|
   854                                  apiData [ ( "team", [] ) ]
   855                          )
   856                      |> Tuple.first
   857                      |> Common.queryView
   858                      |> Query.find [ id "dashboard-info" ]
   859                      |> Query.has [ style "justify-content" "flex-end" ]
   860          , test "pressing '?' does nothing when there are no pipelines" <|
   861              \_ ->
   862                  whenOnDashboard { highDensity = False }
   863                      |> Application.handleCallback
   864                          (Callback.AllTeamsFetched <|
   865                              Ok <|
   866                                  apiData [ ( "team", [] ) ]
   867                          )
   868                      |> Tuple.first
   869                      |> Application.handleDelivery
   870                          (KeyDown
   871                              { ctrlKey = False
   872                              , shiftKey = True
   873                              , metaKey = False
   874                              , code = Keyboard.Slash
   875                              }
   876                          )
   877                      |> Tuple.first
   878                      |> Common.queryView
   879                      |> Query.has [ id "dashboard-info" ]
   880          , test "on HD view, team names have increased letter spacing" <|
   881              \_ ->
   882                  whenOnDashboard { highDensity = True }
   883                      |> givenDataAndUser
   884                          (apiData [ ( "team", [] ) ])
   885                          (userWithRoles [])
   886                      |> Tuple.first
   887                      |> Application.handleCallback
   888                          (Callback.AllPipelinesFetched <|
   889                              Ok
   890                                  [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   891                          )
   892                      |> Tuple.first
   893                      |> Common.queryView
   894                      |> Query.find [ class "dashboard-team-name-wrapper" ]
   895                      |> Query.has [ style "letter-spacing" ".2em" ]
   896          , describe "team pills"
   897              [ test
   898                  ("shows team name with no pill when unauthenticated "
   899                      ++ "and team has an exposed pipeline"
   900                  )
   901                <|
   902                  \_ ->
   903                      whenOnDashboard { highDensity = False }
   904                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
   905                          |> Tuple.first
   906                          |> Application.handleCallback
   907                              (Callback.AllPipelinesFetched <|
   908                                  Ok
   909                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   910                              )
   911                          |> Tuple.first
   912                          |> Common.queryView
   913                          |> teamHeaderHasNoPill "team"
   914              , test "shows OWNER pill on team header for team on which user has owner role" <|
   915                  \_ ->
   916                      whenOnDashboard { highDensity = False }
   917                          |> givenDataAndUser
   918                              (apiData [ ( "team", [] ) ])
   919                              (userWithRoles [ ( "team", [ "owner" ] ) ])
   920                          |> Tuple.first
   921                          |> Application.handleCallback
   922                              (Callback.AllPipelinesFetched <|
   923                                  Ok
   924                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   925                              )
   926                          |> Tuple.first
   927                          |> Common.queryView
   928                          |> teamHeaderHasPill "team" "OWNER"
   929              , test "shows MEMBER pill on team header for team on which user has member role" <|
   930                  \_ ->
   931                      whenOnDashboard { highDensity = False }
   932                          |> givenDataAndUser
   933                              (apiData [ ( "team", [] ) ])
   934                              (userWithRoles [ ( "team", [ "member" ] ) ])
   935                          |> Tuple.first
   936                          |> Application.handleCallback
   937                              (Callback.AllPipelinesFetched <|
   938                                  Ok
   939                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   940                              )
   941                          |> Tuple.first
   942                          |> Common.queryView
   943                          |> teamHeaderHasPill "team" "MEMBER"
   944              , test "shows PIPELINE_OPERATOR pill on team header for team on which user has member role" <|
   945                  \_ ->
   946                      whenOnDashboard { highDensity = False }
   947                          |> givenDataAndUser
   948                              (apiData [ ( "team", [] ) ])
   949                              (userWithRoles [ ( "team", [ "pipeline-operator" ] ) ])
   950                          |> Tuple.first
   951                          |> Application.handleCallback
   952                              (Callback.AllPipelinesFetched <|
   953                                  Ok
   954                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   955                              )
   956                          |> Tuple.first
   957                          |> Common.queryView
   958                          |> teamHeaderHasPill "team" "PIPELINE_OPERATOR"
   959              , test "shows VIEWER pill on team header for team on which user has viewer role" <|
   960                  \_ ->
   961                      whenOnDashboard { highDensity = False }
   962                          |> givenDataAndUser
   963                              (apiData [ ( "team", [] ) ])
   964                              (userWithRoles [ ( "team", [ "viewer" ] ) ])
   965                          |> Tuple.first
   966                          |> Application.handleCallback
   967                              (Callback.AllPipelinesFetched <|
   968                                  Ok
   969                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   970                              )
   971                          |> Tuple.first
   972                          |> Common.queryView
   973                          |> teamHeaderHasPill "team" "VIEWER"
   974              , test "shows no pill on team header for team on which user has no role" <|
   975                  \_ ->
   976                      whenOnDashboard { highDensity = False }
   977                          |> givenDataAndUser
   978                              (apiData [ ( "team", [] ) ])
   979                              (userWithRoles [])
   980                          |> Tuple.first
   981                          |> Application.handleCallback
   982                              (Callback.AllPipelinesFetched <|
   983                                  Ok
   984                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
   985                              )
   986                          |> Tuple.first
   987                          |> Common.queryView
   988                          |> teamHeaderHasNoPill "team"
   989              , test
   990                  ("shows pill for most-privileged role on team header for team "
   991                      ++ "on which user has multiple roles"
   992                  )
   993                <|
   994                  \_ ->
   995                      whenOnDashboard { highDensity = False }
   996                          |> givenDataAndUser
   997                              (apiData [ ( "team", [] ) ])
   998                              (userWithRoles [ ( "team", [ "viewer", "member" ] ) ])
   999                          |> Tuple.first
  1000                          |> Application.handleCallback
  1001                              (Callback.AllPipelinesFetched <|
  1002                                  Ok
  1003                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1004                              )
  1005                          |> Tuple.first
  1006                          |> Common.queryView
  1007                          |> teamHeaderHasPill "team" "MEMBER"
  1008              , test "sorts teams according to user role" <|
  1009                  \_ ->
  1010                      whenOnDashboard { highDensity = False }
  1011                          |> givenDataAndUser
  1012                              (apiData
  1013                                  [ ( "owner-team", [] )
  1014                                  , ( "nonmember-team", [] )
  1015                                  , ( "viewer-team", [] )
  1016                                  , ( "member-team", [] )
  1017                                  ]
  1018                              )
  1019                              (userWithRoles
  1020                                  [ ( "owner-team", [ "owner" ] )
  1021                                  , ( "member-team", [ "member" ] )
  1022                                  , ( "viewer-team", [ "viewer" ] )
  1023                                  , ( "nonmember-team", [] )
  1024                                  ]
  1025                              )
  1026                          |> Tuple.first
  1027                          |> Application.handleCallback
  1028                              (Callback.AllPipelinesFetched <|
  1029                                  Ok
  1030                                      [ Data.pipeline "owner-team" 0 |> Data.withName "pipeline" ]
  1031                              )
  1032                          |> Tuple.first
  1033                          |> Common.queryView
  1034                          |> Query.findAll teamHeaderSelector
  1035                          |> Expect.all
  1036                              [ Query.count (Expect.equal 4)
  1037                              , Query.index 0 >> Query.has [ text "owner-team" ]
  1038                              , Query.index 1 >> Query.has [ text "member-team" ]
  1039                              , Query.index 2 >> Query.has [ text "viewer-team" ]
  1040                              , Query.index 3 >> Query.has [ text "nonmember-team" ]
  1041                              ]
  1042              , test "team headers lay out contents horizontally, centering vertically" <|
  1043                  \_ ->
  1044                      whenOnDashboard { highDensity = False }
  1045                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1046                          |> Tuple.first
  1047                          |> Application.handleCallback
  1048                              (Callback.AllPipelinesFetched <|
  1049                                  Ok
  1050                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1051                              )
  1052                          |> Tuple.first
  1053                          |> Common.queryView
  1054                          |> Query.findAll teamHeaderSelector
  1055                          |> Query.each
  1056                              (Query.has
  1057                                  [ style "display" "flex"
  1058                                  , style "align-items" "center"
  1059                                  ]
  1060                              )
  1061              , test "team headers have a bottom margin of 25px" <|
  1062                  \_ ->
  1063                      whenOnDashboard { highDensity = False }
  1064                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1065                          |> Tuple.first
  1066                          |> Application.handleCallback
  1067                              (Callback.AllPipelinesFetched <|
  1068                                  Ok
  1069                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1070                              )
  1071                          |> Tuple.first
  1072                          |> Common.queryView
  1073                          |> Query.findAll teamHeaderSelector
  1074                          |> Query.each
  1075                              (Query.has [ style "margin-bottom" "25px" ])
  1076              , test "on HD view, there is space between the list of pipelines and the role pill" <|
  1077                  \_ ->
  1078                      whenOnDashboard { highDensity = True }
  1079                          |> givenDataAndUser
  1080                              (apiData [ ( "team", [] ) ])
  1081                              (userWithRoles [ ( "team", [ "owner" ] ) ])
  1082                          |> Tuple.first
  1083                          |> Application.handleCallback
  1084                              (Callback.AllPipelinesFetched <|
  1085                                  Ok
  1086                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1087                              )
  1088                          |> Tuple.first
  1089                          |> Common.queryView
  1090                          |> Query.find [ class "dashboard-team-name-wrapper" ]
  1091                          |> Query.find [ containing [ text "OWNER" ] ]
  1092                          |> Query.has [ style "margin-bottom" "1em" ]
  1093              , test "on non-HD view, the role pill on a group has no margin below" <|
  1094                  \_ ->
  1095                      whenOnDashboard { highDensity = False }
  1096                          |> givenDataAndUser
  1097                              (apiData [ ( "team", [] ) ])
  1098                              (userWithRoles [ ( "team", [ "owner" ] ) ])
  1099                          |> Tuple.first
  1100                          |> Application.handleCallback
  1101                              (Callback.AllPipelinesFetched <|
  1102                                  Ok
  1103                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1104                              )
  1105                          |> Tuple.first
  1106                          |> Common.queryView
  1107                          |> Query.find teamHeaderSelector
  1108                          |> Query.find [ containing [ text "OWNER" ] ]
  1109                          |> Query.has [ style "margin-bottom" "" ]
  1110              , test "has momentum based scrolling" <|
  1111                  \_ ->
  1112                      whenOnDashboard { highDensity = True }
  1113                          |> givenDataAndUser
  1114                              (apiData [ ( "team", [] ) ])
  1115                              (userWithRoles [])
  1116                          |> Tuple.first
  1117                          |> Application.handleCallback
  1118                              (Callback.AllPipelinesFetched <|
  1119                                  Ok
  1120                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1121                              )
  1122                          |> Tuple.first
  1123                          |> Common.queryView
  1124                          |> Query.find [ id "page-below-top-bar" ]
  1125                          |> Query.find [ class "dashboard" ]
  1126                          |> Query.has [ style "-webkit-overflow-scrolling" "touch" ]
  1127              ]
  1128          , describe "bottom bar"
  1129              [ test "appears by default" <|
  1130                  \_ ->
  1131                      whenOnDashboard { highDensity = False }
  1132                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1133                          |> Tuple.first
  1134                          |> Application.handleCallback
  1135                              (Callback.AllPipelinesFetched <|
  1136                                  Ok
  1137                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1138                              )
  1139                          |> Tuple.first
  1140                          |> Common.queryView
  1141                          |> Query.has [ id "dashboard-info" ]
  1142              , test "is 50px tall, almost black, fixed to the bottom of the viewport and covers entire width" <|
  1143                  \_ ->
  1144                      whenOnDashboard { highDensity = False }
  1145                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1146                          |> Tuple.first
  1147                          |> Application.handleCallback
  1148                              (Callback.AllPipelinesFetched <|
  1149                                  Ok
  1150                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1151                              )
  1152                          |> Tuple.first
  1153                          |> Common.queryView
  1154                          |> Query.find [ id "dashboard-info" ]
  1155                          |> Query.has
  1156                              [ style "line-height" "35px"
  1157                              , style "padding" "7.5px 30px"
  1158                              , style "position" "fixed"
  1159                              , style "bottom" "0"
  1160                              , style "background-color" ColorValues.grey100
  1161                              , style "width" "100%"
  1162                              , style "box-sizing" "border-box"
  1163                              ]
  1164              , test "lays out contents horizontally, maximizing space between children" <|
  1165                  \_ ->
  1166                      whenOnDashboard { highDensity = False }
  1167                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1168                          |> Tuple.first
  1169                          |> Application.handleCallback
  1170                              (Callback.AllPipelinesFetched <|
  1171                                  Ok
  1172                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1173                              )
  1174                          |> Tuple.first
  1175                          |> Common.queryView
  1176                          |> Query.find [ id "dashboard-info" ]
  1177                          |> Query.has
  1178                              [ style "display" "flex"
  1179                              , style "justify-content" "space-between"
  1180                              ]
  1181              , test "has a z-index of 2" <|
  1182                  \_ ->
  1183                      whenOnDashboard { highDensity = False }
  1184                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1185                          |> Tuple.first
  1186                          |> Application.handleCallback
  1187                              (Callback.AllPipelinesFetched <|
  1188                                  Ok
  1189                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1190                              )
  1191                          |> Tuple.first
  1192                          |> Common.queryView
  1193                          |> Query.find [ id "dashboard-info" ]
  1194                          |> Query.has [ style "z-index" "2" ]
  1195              , test "two children are legend and concourse-info" <|
  1196                  \_ ->
  1197                      whenOnDashboard { highDensity = False }
  1198                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1199                          |> Tuple.first
  1200                          |> Application.handleCallback
  1201                              (Callback.AllPipelinesFetched <|
  1202                                  Ok
  1203                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1204                              )
  1205                          |> Tuple.first
  1206                          |> Common.queryView
  1207                          |> Query.find [ id "dashboard-info" ]
  1208                          |> Query.children []
  1209                          |> Expect.all
  1210                              [ Query.count (Expect.equal 2)
  1211                              , Query.index 0 >> Query.has [ id "legend" ]
  1212                              , Query.index 1 >> Query.has [ id "concourse-info" ]
  1213                              ]
  1214              , test "lays out children on two lines when view width is below 1230px" <|
  1215                  \_ ->
  1216                      Common.init "/"
  1217                          |> givenDataUnauthenticated
  1218                              (apiData [ ( "team", [] ) ])
  1219                          |> Tuple.first
  1220                          |> Application.handleCallback
  1221                              (Callback.AllPipelinesFetched <|
  1222                                  Ok
  1223                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1224                              )
  1225                          |> Tuple.first
  1226                          |> Application.update
  1227                              (ApplicationMsgs.DeliveryReceived <|
  1228                                  WindowResized 1229 300
  1229                              )
  1230                          |> Tuple.first
  1231                          |> Common.queryView
  1232                          |> Query.find [ id "dashboard-info" ]
  1233                          |> Query.has [ style "flex-direction" "column" ]
  1234              , describe "legend"
  1235                  [ test "lays out contents horizontally" <|
  1236                      \_ ->
  1237                          whenOnDashboard { highDensity = False }
  1238                              |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1239                              |> Tuple.first
  1240                              |> Application.handleCallback
  1241                                  (Callback.AllPipelinesFetched <|
  1242                                      Ok
  1243                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1244                                  )
  1245                              |> Tuple.first
  1246                              |> Common.queryView
  1247                              |> Query.find [ id "legend" ]
  1248                              |> Query.has [ style "display" "flex" ]
  1249                  , test "shows pipeline statuses" <|
  1250                      \_ ->
  1251                          whenOnDashboard { highDensity = False }
  1252                              |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1253                              |> Tuple.first
  1254                              |> Application.handleCallback
  1255                                  (Callback.AllPipelinesFetched <|
  1256                                      Ok
  1257                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1258                                  )
  1259                              |> Tuple.first
  1260                              |> Common.queryView
  1261                              |> Query.find [ id "legend" ]
  1262                              |> Query.children []
  1263                              |> Expect.all
  1264                                  [ Query.count (Expect.equal 9)
  1265                                  , Query.index 0
  1266                                      >> Query.children []
  1267                                      >> Expect.all
  1268                                          [ Query.count (Expect.equal 3)
  1269                                          , Query.index 0
  1270                                              >> Query.has
  1271                                                  (iconSelector
  1272                                                      { size = "20px"
  1273                                                      , image = PipelineStatusPending True |> Assets.PipelineStatusIcon
  1274                                                      }
  1275                                                  )
  1276                                          , Query.index 1
  1277                                              >> Query.has [ style "width" "10px" ]
  1278                                          , Query.index 2 >> Query.has [ text "pending" ]
  1279                                          ]
  1280                                  , Query.index 1
  1281                                      >> Query.children []
  1282                                      >> Expect.all
  1283                                          [ Query.count (Expect.equal 3)
  1284                                          , Query.index 0
  1285                                              >> Query.has
  1286                                                  (iconSelector
  1287                                                      { size = "20px"
  1288                                                      , image = PipelineStatusPaused |> Assets.PipelineStatusIcon
  1289                                                      }
  1290                                                  )
  1291                                          , Query.index 1
  1292                                              >> Query.has [ style "width" "10px" ]
  1293                                          , Query.index 2 >> Query.has [ text "paused" ]
  1294                                          ]
  1295                                  ]
  1296                  , test "the legend separator is grey" <|
  1297                      \_ ->
  1298                          whenOnDashboard { highDensity = False }
  1299                              |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1300                              |> Tuple.first
  1301                              |> Application.handleCallback
  1302                                  (Callback.AllPipelinesFetched <|
  1303                                      Ok
  1304                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1305                                  )
  1306                              |> Tuple.first
  1307                              |> Common.queryView
  1308                              |> Query.find [ id "legend" ]
  1309                              |> Query.children []
  1310                              |> Query.index -2
  1311                              |> Query.has [ style "color" ColorValues.grey40 ]
  1312                  , test "the legend separator centers contents vertically" <|
  1313                      \_ ->
  1314                          whenOnDashboard { highDensity = False }
  1315                              |> givenDataUnauthenticated
  1316                                  (apiData [ ( "team", [] ) ])
  1317                              |> Tuple.first
  1318                              |> Application.handleCallback
  1319                                  (Callback.AllPipelinesFetched <|
  1320                                      Ok
  1321                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1322                                  )
  1323                              |> Tuple.first
  1324                              |> Common.queryView
  1325                              |> Query.find [ id "legend" ]
  1326                              |> Query.children []
  1327                              |> Query.index -2
  1328                              |> Query.has [ style "display" "flex", style "align-items" "center" ]
  1329                  , test "the legend separator is gone when the window width is below 812px" <|
  1330                      \_ ->
  1331                          Common.init "/"
  1332                              |> givenDataUnauthenticated
  1333                                  (apiData [ ( "team", [] ) ])
  1334                              |> Tuple.first
  1335                              |> Application.handleCallback
  1336                                  (Callback.AllPipelinesFetched <|
  1337                                      Ok
  1338                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1339                                  )
  1340                              |> Tuple.first
  1341                              |> Application.update
  1342                                  (ApplicationMsgs.DeliveryReceived <|
  1343                                      WindowResized 800 300
  1344                                  )
  1345                              |> Tuple.first
  1346                              |> Common.queryView
  1347                              |> Query.find [ id "legend" ]
  1348                              |> Expect.all
  1349                                  [ Query.hasNot [ text "|" ]
  1350                                  , Query.children [] >> Query.count (Expect.equal 8)
  1351                                  ]
  1352                  , test "legend items wrap when window width is below 812px" <|
  1353                      \_ ->
  1354                          Common.init "/"
  1355                              |> givenDataUnauthenticated
  1356                                  (apiData [ ( "team", [] ) ])
  1357                              |> Tuple.first
  1358                              |> Application.handleCallback
  1359                                  (Callback.AllPipelinesFetched <|
  1360                                      Ok
  1361                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1362                                  )
  1363                              |> Tuple.first
  1364                              |> Application.update
  1365                                  (ApplicationMsgs.DeliveryReceived <|
  1366                                      WindowResized 800 300
  1367                                  )
  1368                              |> Tuple.first
  1369                              |> Common.queryView
  1370                              |> Query.find [ id "legend" ]
  1371                              |> Query.has [ style "flex-wrap" "wrap" ]
  1372                  , test "legend items lay out contents horizontally, centered vertically in grey caps" <|
  1373                      \_ ->
  1374                          whenOnDashboard { highDensity = False }
  1375                              |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1376                              |> Tuple.first
  1377                              |> Application.handleCallback
  1378                                  (Callback.AllPipelinesFetched <|
  1379                                      Ok
  1380                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1381                                  )
  1382                              |> Tuple.first
  1383                              |> Common.queryView
  1384                              |> Query.find [ id "legend" ]
  1385                              |> Query.children []
  1386                              |> Query.index 0
  1387                              |> Query.has
  1388                                  [ style "text-transform" "uppercase"
  1389                                  , style "display" "flex"
  1390                                  , style "align-items" "center"
  1391                                  , style "color" ColorValues.grey40
  1392                                  ]
  1393                  , test "legend items have 20px space between them" <|
  1394                      \_ ->
  1395                          whenOnDashboard { highDensity = False }
  1396                              |> givenDataUnauthenticated
  1397                                  (apiData [ ( "team", [] ) ])
  1398                              |> Tuple.first
  1399                              |> Application.handleCallback
  1400                                  (Callback.AllPipelinesFetched <|
  1401                                      Ok
  1402                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1403                                  )
  1404                              |> Tuple.first
  1405                              |> Common.queryView
  1406                              |> Query.find [ id "legend" ]
  1407                              |> Query.children []
  1408                              |> Query.each
  1409                                  (Query.has [ style "margin-right" "20px" ])
  1410                  , test "third legend item shows running indicator" <|
  1411                      \_ ->
  1412                          whenOnDashboard { highDensity = False }
  1413                              |> givenDataUnauthenticated
  1414                                  (apiData [ ( "team", [] ) ])
  1415                              |> Tuple.first
  1416                              |> Application.handleCallback
  1417                                  (Callback.AllPipelinesFetched <|
  1418                                      Ok
  1419                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1420                                  )
  1421                              |> Tuple.first
  1422                              |> Common.queryView
  1423                              |> Query.find [ id "legend" ]
  1424                              |> Query.children []
  1425                              |> Query.index 2
  1426                              |> Expect.all
  1427                                  [ Query.has
  1428                                      [ style "text-transform" "uppercase"
  1429                                      , style "display" "flex"
  1430                                      ]
  1431                                  , Query.children []
  1432                                      >> Expect.all
  1433                                          [ Query.count (Expect.equal 3)
  1434                                          , Query.index 0
  1435                                              >> Query.has
  1436                                                  (iconSelector
  1437                                                      { size = "20px"
  1438                                                      , image = Assets.RunningLegend
  1439                                                      }
  1440                                                  )
  1441                                          , Query.index 1
  1442                                              >> Query.has
  1443                                                  [ style "width" "10px" ]
  1444                                          , Query.index 2 >> Query.has [ text "running" ]
  1445                                          ]
  1446                                  ]
  1447                  ]
  1448              , describe "HD toggle" <|
  1449                  let
  1450                      findHDToggle =
  1451                          Query.find [ id "legend" ]
  1452                              >> Query.children []
  1453                              >> Query.index -1
  1454  
  1455                      hdToggle =
  1456                          whenOnDashboard { highDensity = False }
  1457                              |> givenDataUnauthenticated
  1458                                  (apiData [ ( "team", [] ) ])
  1459                              |> Tuple.first
  1460                              |> Application.handleCallback
  1461                                  (Callback.AllPipelinesFetched <|
  1462                                      Ok
  1463                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1464                                  )
  1465                              |> Tuple.first
  1466                              |> Common.queryView
  1467                              |> findHDToggle
  1468                  in
  1469                  [ describe "on non-hd view"
  1470                      [ test "lays out contents horizontally" <|
  1471                          \_ ->
  1472                              hdToggle
  1473                                  |> Query.has [ style "display" "flex" ]
  1474                      , test "centers contents vertically" <|
  1475                          \_ ->
  1476                              hdToggle
  1477                                  |> Query.has [ style "align-items" "center" ]
  1478                      , test "has a margin of 10px between the button and the label" <|
  1479                          \_ ->
  1480                              hdToggle
  1481                                  |> Query.children []
  1482                                  |> Query.index 0
  1483                                  |> Query.has
  1484                                      [ style "margin-right" "10px" ]
  1485                      , test "displays the label using a grey color" <|
  1486                          \_ ->
  1487                              hdToggle
  1488                                  |> Query.has [ style "color" ColorValues.grey40 ]
  1489                      , test "label text is all caps" <|
  1490                          \_ ->
  1491                              hdToggle
  1492                                  |> Query.has
  1493                                      [ style "text-transform" "uppercase" ]
  1494                      , test "displays label on the right" <|
  1495                          \_ ->
  1496                              hdToggle
  1497                                  |> Query.has [ style "flex-direction" "row" ]
  1498                      , test "links to HD view" <|
  1499                          \_ ->
  1500                              hdToggle
  1501                                  |> Query.has [ attribute <| Attr.href "/hd" ]
  1502                      , test "displays the off state" <|
  1503                          \_ ->
  1504                              hdToggle
  1505                                  |> Query.children []
  1506                                  |> Query.index 0
  1507                                  |> Query.has
  1508                                      [ style "background-image" <|
  1509                                          Assets.backgroundImage <|
  1510                                              Just (Assets.ToggleSwitch False)
  1511                                      , style "background-size" "contain"
  1512                                      , style "height" "20px"
  1513                                      , style "width" "35px"
  1514                                      ]
  1515                      , test "will not shrink on resizing" <|
  1516                          \_ ->
  1517                              hdToggle
  1518                                  |> Query.children []
  1519                                  |> Query.index 0
  1520                                  |> Query.has [ style "flex-shrink" "0" ]
  1521                      ]
  1522                  , describe "on HD view"
  1523                      [ test "displays the on state" <|
  1524                          \_ ->
  1525                              whenOnDashboard { highDensity = True }
  1526                                  |> givenDataUnauthenticated
  1527                                      (apiData [ ( "team", [] ) ])
  1528                                  |> Tuple.first
  1529                                  |> Application.handleCallback
  1530                                      (Callback.AllPipelinesFetched <|
  1531                                          Ok
  1532                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1533                                      )
  1534                                  |> Tuple.first
  1535                                  |> Common.queryView
  1536                                  |> findHDToggle
  1537                                  |> Query.children []
  1538                                  |> Query.index 0
  1539                                  |> Query.has
  1540                                      [ style "background-image" <|
  1541                                          Assets.backgroundImage <|
  1542                                              Just (Assets.ToggleSwitch True)
  1543                                      , style "background-size" "contain"
  1544                                      , style "height" "20px"
  1545                                      , style "width" "35px"
  1546                                      ]
  1547                      , test "links to normal dashboard view" <|
  1548                          \_ ->
  1549                              whenOnDashboard { highDensity = True }
  1550                                  |> givenDataUnauthenticated
  1551                                      (apiData [ ( "team", [] ) ])
  1552                                  |> Tuple.first
  1553                                  |> Application.handleCallback
  1554                                      (Callback.AllPipelinesFetched <|
  1555                                          Ok
  1556                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1557                                      )
  1558                                  |> Tuple.first
  1559                                  |> Common.queryView
  1560                                  |> findHDToggle
  1561                                  |> Query.has [ attribute <| Attr.href "/" ]
  1562                      , test "will not shrink on resizing" <|
  1563                          \_ ->
  1564                              whenOnDashboard { highDensity = True }
  1565                                  |> givenDataUnauthenticated
  1566                                      (apiData [ ( "team", [] ) ])
  1567                                  |> Tuple.first
  1568                                  |> Application.handleCallback
  1569                                      (Callback.AllPipelinesFetched <|
  1570                                          Ok
  1571                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1572                                      )
  1573                                  |> Tuple.first
  1574                                  |> Common.queryView
  1575                                  |> findHDToggle
  1576                                  |> Query.children []
  1577                                  |> Query.index 0
  1578                                  |> Query.has
  1579                                      [ style "flex-shrink" "0" ]
  1580                      ]
  1581                  ]
  1582              , describe "when there are favorited pipelines" <|
  1583                  let
  1584                      setup params =
  1585                          whenOnDashboard params
  1586                              |> givenDataUnauthenticated
  1587                                  (apiData [ ( "team", [] ) ])
  1588                              |> Tuple.first
  1589                              |> Application.handleCallback
  1590                                  (Callback.AllPipelinesFetched <|
  1591                                      Ok
  1592                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1593                                  )
  1594                              |> Tuple.first
  1595                              |> Application.handleDelivery
  1596                                  (Subscription.FavoritedPipelinesReceived <|
  1597                                      Ok <|
  1598                                          Set.singleton 0
  1599                                  )
  1600                  in
  1601                  [ test "displays favorite pipelines header" <|
  1602                      \_ ->
  1603                          setup { highDensity = False }
  1604                              |> Tuple.first
  1605                              |> Common.queryView
  1606                              |> Query.has [ text "favorite pipelines" ]
  1607                  , test "does not display header when on the HD view" <|
  1608                      \_ ->
  1609                          setup { highDensity = True }
  1610                              |> Tuple.first
  1611                              |> Common.queryView
  1612                              |> Query.hasNot [ text "favorite pipelines" ]
  1613                  ]
  1614              , describe "when there are no favorited pipelines"
  1615                  [ test "does not display header" <|
  1616                      \_ ->
  1617                          whenOnDashboard { highDensity = False }
  1618                              |> givenDataUnauthenticated
  1619                                  (apiData [ ( "team", [] ) ])
  1620                              |> Tuple.first
  1621                              |> Application.handleCallback
  1622                                  (Callback.AllPipelinesFetched <|
  1623                                      Ok
  1624                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1625                                  )
  1626                              |> Tuple.first
  1627                              |> Common.queryView
  1628                              |> Query.hasNot [ text "favorite pipelines" ]
  1629                  ]
  1630              , describe "all pipelines header"
  1631                  [ test "displayed when there are pipelines" <|
  1632                      \_ ->
  1633                          whenOnDashboard { highDensity = False }
  1634                              |> givenDataUnauthenticated
  1635                                  (apiData [ ( "team", [] ) ])
  1636                              |> Tuple.first
  1637                              |> Application.handleCallback
  1638                                  (Callback.AllPipelinesFetched <|
  1639                                      Ok
  1640                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1641                                  )
  1642                              |> Tuple.first
  1643                              |> Common.queryView
  1644                              |> Query.has [ text "all pipelines" ]
  1645                  , test "displayed when there are no pipelines" <|
  1646                      \_ ->
  1647                          whenOnDashboard { highDensity = False }
  1648                              |> givenDataUnauthenticated
  1649                                  (apiData [ ( "team", [] ) ])
  1650                              |> Tuple.first
  1651                              |> Application.handleCallback
  1652                                  (Callback.AllPipelinesFetched <|
  1653                                      Ok []
  1654                                  )
  1655                              |> Tuple.first
  1656                              |> Common.queryView
  1657                              |> Query.has [ text "all pipelines" ]
  1658                  , test "not displayed when there are no teams" <|
  1659                      \_ ->
  1660                          whenOnDashboard { highDensity = False }
  1661                              |> givenDataUnauthenticated
  1662                                  (apiData [])
  1663                              |> Tuple.first
  1664                              |> Application.handleCallback
  1665                                  (Callback.AllPipelinesFetched <|
  1666                                      Ok []
  1667                                  )
  1668                              |> Tuple.first
  1669                              |> Common.queryView
  1670                              |> Query.hasNot [ text "all pipelines" ]
  1671                  ]
  1672              , describe "info section" <|
  1673                  let
  1674                      info =
  1675                          whenOnDashboard { highDensity = False }
  1676                              |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1677                              |> Tuple.first
  1678                              |> Application.handleCallback
  1679                                  (Callback.AllPipelinesFetched <|
  1680                                      Ok
  1681                                          [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1682                                  )
  1683                              |> Tuple.first
  1684                              |> Common.queryView
  1685                              |> Query.find [ id "concourse-info" ]
  1686                  in
  1687                  [ test "lays out contents horizontally" <|
  1688                      \_ ->
  1689                          info
  1690                              |> Query.has [ style "display" "flex" ]
  1691                  , test "displays info in a grey color" <|
  1692                      \_ ->
  1693                          info
  1694                              |> Query.has [ style "color" ColorValues.grey40 ]
  1695                  , test "displays text slightly larger" <|
  1696                      \_ ->
  1697                          info
  1698                              |> Query.has [ style "font-size" "1.25em" ]
  1699                  , test "each info item is spaced out by 30px" <|
  1700                      \_ ->
  1701                          info
  1702                              |> Query.children []
  1703                              |> Query.each
  1704                                  (Query.has [ style "margin-right" "30px" ])
  1705                  , test "each info item centers contents vertically" <|
  1706                      \_ ->
  1707                          info
  1708                              |> Query.children []
  1709                              |> Query.each
  1710                                  (Query.has
  1711                                      [ style "align-items" "center"
  1712                                      , style "display" "flex"
  1713                                      ]
  1714                                  )
  1715                  , test "items in CLI section are 10 px apart" <|
  1716                      \_ ->
  1717                          info
  1718                              |> Query.children []
  1719                              |> Query.index -1
  1720                              |> Query.children []
  1721                              |> Query.each
  1722                                  (Query.has [ style "margin-right" "10px" ])
  1723                  , describe "cli download icons" <|
  1724                      let
  1725                          cliIcons =
  1726                              info
  1727                                  |> Query.children []
  1728                                  |> Query.index -1
  1729                                  |> Query.children [ tag "a" ]
  1730                      in
  1731                      [ test "icons are grey" <|
  1732                          \_ ->
  1733                              cliIcons
  1734                                  |> Query.each
  1735                                      (Query.has [ style "opacity" "0.5" ])
  1736                      , test "have 'download' attribute" <|
  1737                          \_ ->
  1738                              cliIcons
  1739                                  |> Query.each
  1740                                      (Query.has
  1741                                          [ attribute <| Attr.download "" ]
  1742                                      )
  1743                      , test "icons have descriptive ARIA labels" <|
  1744                          \_ ->
  1745                              cliIcons
  1746                                  |> Expect.all
  1747                                      [ Query.count (Expect.equal 3)
  1748                                      , Query.index 0
  1749                                          >> Query.has
  1750                                              [ attribute <|
  1751                                                  Attr.attribute
  1752                                                      "aria-label"
  1753                                                      "Download OS X CLI"
  1754                                              ]
  1755                                      , Query.index 1
  1756                                          >> Query.has
  1757                                              [ attribute <|
  1758                                                  Attr.attribute
  1759                                                      "aria-label"
  1760                                                      "Download Windows CLI"
  1761                                              ]
  1762                                      , Query.index 2
  1763                                          >> Query.has
  1764                                              [ attribute <|
  1765                                                  Attr.attribute
  1766                                                      "aria-label"
  1767                                                      "Download Linux CLI"
  1768                                              ]
  1769                                      ]
  1770                      , defineHoverBehaviour
  1771                          { name = "os x cli icon"
  1772                          , setup =
  1773                              whenOnDashboard { highDensity = False }
  1774                                  |> givenDataUnauthenticated
  1775                                      (apiData [ ( "team", [] ) ])
  1776                                  |> Tuple.first
  1777                                  |> Application.handleCallback
  1778                                      (Callback.AllPipelinesFetched <|
  1779                                          Ok
  1780                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1781                                      )
  1782                                  |> Tuple.first
  1783                          , query = Common.queryView >> Query.find [ id "cli-osx" ]
  1784                          , unhoveredSelector =
  1785                              { description = "grey apple icon"
  1786                              , selector =
  1787                                  [ style "opacity" "0.5"
  1788                                  , style "background-size" "contain"
  1789                                  ]
  1790                                      ++ iconSelector
  1791                                          { image = Assets.CliIcon Cli.OSX
  1792                                          , size = "20px"
  1793                                          }
  1794                              }
  1795                          , hoverable =
  1796                              Msgs.FooterCliIcon Cli.OSX
  1797                          , hoveredSelector =
  1798                              { description = "white apple icon"
  1799                              , selector =
  1800                                  [ style "opacity" "1"
  1801                                  , style "background-size" "contain"
  1802                                  ]
  1803                                      ++ iconSelector
  1804                                          { image = Assets.CliIcon Cli.OSX
  1805                                          , size = "20px"
  1806                                          }
  1807                              }
  1808                          }
  1809                      , defineHoverBehaviour
  1810                          { name = "windows cli icon"
  1811                          , setup =
  1812                              whenOnDashboard { highDensity = False }
  1813                                  |> givenDataUnauthenticated
  1814                                      (apiData [ ( "team", [] ) ])
  1815                                  |> Tuple.first
  1816                                  |> Application.handleCallback
  1817                                      (Callback.AllPipelinesFetched <|
  1818                                          Ok
  1819                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1820                                      )
  1821                                  |> Tuple.first
  1822                          , query =
  1823                              Common.queryView
  1824                                  >> Query.find [ id "cli-windows" ]
  1825                          , unhoveredSelector =
  1826                              { description = "grey windows icon"
  1827                              , selector =
  1828                                  [ style "opacity" "0.5"
  1829                                  , style "background-size" "contain"
  1830                                  ]
  1831                                      ++ iconSelector
  1832                                          { image = Assets.CliIcon Cli.Windows
  1833                                          , size = "20px"
  1834                                          }
  1835                              }
  1836                          , hoverable =
  1837                              Msgs.FooterCliIcon Cli.Windows
  1838                          , hoveredSelector =
  1839                              { description = "white windows icon"
  1840                              , selector =
  1841                                  [ style "opacity" "1"
  1842                                  , style "background-size" "contain"
  1843                                  ]
  1844                                      ++ iconSelector
  1845                                          { image = Assets.CliIcon Cli.Windows
  1846                                          , size = "20px"
  1847                                          }
  1848                              }
  1849                          }
  1850                      , defineHoverBehaviour
  1851                          { name = "linux cli icon"
  1852                          , setup =
  1853                              whenOnDashboard { highDensity = False }
  1854                                  |> givenDataUnauthenticated
  1855                                      (apiData
  1856                                          [ ( "team", [] ) ]
  1857                                      )
  1858                                  |> Tuple.first
  1859                                  |> Application.handleCallback
  1860                                      (Callback.AllPipelinesFetched <|
  1861                                          Ok
  1862                                              [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1863                                      )
  1864                                  |> Tuple.first
  1865                          , query =
  1866                              Common.queryView
  1867                                  >> Query.find [ id "cli-linux" ]
  1868                          , unhoveredSelector =
  1869                              { description = "grey linux icon"
  1870                              , selector =
  1871                                  [ style "opacity" "0.5"
  1872                                  , style "background-size" "contain"
  1873                                  ]
  1874                                      ++ iconSelector
  1875                                          { image = Assets.CliIcon Cli.Linux
  1876                                          , size = "20px"
  1877                                          }
  1878                              }
  1879                          , hoverable =
  1880                              Msgs.FooterCliIcon Cli.Linux
  1881                          , hoveredSelector =
  1882                              { description = "white linux icon"
  1883                              , selector =
  1884                                  [ style "opacity" "1"
  1885                                  , style "background-size" "contain"
  1886                                  ]
  1887                                      ++ iconSelector
  1888                                          { image = Assets.CliIcon Cli.Linux
  1889                                          , size = "20px"
  1890                                          }
  1891                              }
  1892                          }
  1893                      ]
  1894                  , test "shows concourse version" <|
  1895                      \_ ->
  1896                          whenOnDashboard { highDensity = False }
  1897                              |> givenClusterInfo "1.2.3" "cluster-name"
  1898                              |> Tuple.first
  1899                              |> Common.queryView
  1900                              |> Query.find [ id "concourse-info" ]
  1901                              |> Query.has [ text "v1.2.3" ]
  1902                  ]
  1903              , test "hides after 6 seconds" <|
  1904                  \_ ->
  1905                      Common.init "/"
  1906                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1907                          |> Tuple.first
  1908                          |> Application.handleCallback
  1909                              (Callback.AllPipelinesFetched <|
  1910                                  Ok
  1911                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1912                              )
  1913                          |> Tuple.first
  1914                          |> afterSeconds 6
  1915                          |> Common.queryView
  1916                          |> Query.hasNot [ id "dashboard-info" ]
  1917              , test "reappears on mouse action" <|
  1918                  \_ ->
  1919                      Common.init "/"
  1920                          |> givenDataUnauthenticated (apiData [ ( "team", [] ) ])
  1921                          |> Tuple.first
  1922                          |> Application.handleCallback
  1923                              (Callback.AllPipelinesFetched <|
  1924                                  Ok
  1925                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1926                              )
  1927                          |> Tuple.first
  1928                          |> afterSeconds 6
  1929                          |> Application.update
  1930                              (ApplicationMsgs.DeliveryReceived <| Moused { x = 0, y = 0 })
  1931                          |> Tuple.first
  1932                          |> Common.queryView
  1933                          |> Query.has [ id "dashboard-info" ]
  1934              , test "is replaced by keyboard help when pressing '?'" <|
  1935                  \_ ->
  1936                      Common.init "/"
  1937                          |> givenDataUnauthenticated
  1938                              (apiData [ ( "team", [] ) ])
  1939                          |> Tuple.first
  1940                          |> Application.handleCallback
  1941                              (Callback.AllPipelinesFetched <|
  1942                                  Ok
  1943                                      [ Data.pipeline "team" 0 |> Data.withName "pipeline" ]
  1944                              )
  1945                          |> Tuple.first
  1946                          |> Application.update
  1947                              (ApplicationMsgs.DeliveryReceived <|
  1948                                  KeyDown
  1949                                      { ctrlKey = False
  1950                                      , shiftKey = True
  1951                                      , metaKey = False
  1952                                      , code = Keyboard.Slash
  1953                                      }
  1954                              )
  1955                          |> Tuple.first
  1956                          |> Common.queryView
  1957                          |> Expect.all
  1958                              [ Query.hasNot [ id "dashboard-info" ]
  1959                              , Query.has [ id "keyboard-help" ]
  1960                              ]
  1961              ]
  1962          , test "subscribes to one and five second timers" <|
  1963              \_ ->
  1964                  whenOnDashboard { highDensity = False }
  1965                      |> Application.subscriptions
  1966                      |> Expect.all
  1967                          [ Common.contains (Subscription.OnClockTick OneSecond)
  1968                          , Common.contains (Subscription.OnClockTick FiveSeconds)
  1969                          ]
  1970          , test "subscribes to keyups" <|
  1971              \_ ->
  1972                  whenOnDashboard { highDensity = False }
  1973                      |> Application.subscriptions
  1974                      |> Common.contains Subscription.OnKeyUp
  1975          , test "auto refreshes jobs on five-second tick after previous request finishes" <|
  1976              \_ ->
  1977                  Common.init "/"
  1978                      |> Application.handleCallback
  1979                          (Callback.AllJobsFetched <| Ok [])
  1980                      |> Tuple.first
  1981                      |> Application.handleDelivery
  1982                          (ClockTicked FiveSeconds <|
  1983                              Time.millisToPosix 0
  1984                          )
  1985                      |> Tuple.second
  1986                      |> Common.contains Effects.FetchAllJobs
  1987          , test "stops polling jobs if the endpoint is disabled" <|
  1988              \_ ->
  1989                  Common.init "/"
  1990                      |> Application.handleCallback
  1991                          (Callback.AllJobsFetched <| Data.httpNotImplemented)
  1992                      |> Tuple.first
  1993                      |> Application.handleDelivery
  1994                          (ClockTicked FiveSeconds <|
  1995                              Time.millisToPosix 0
  1996                          )
  1997                      |> Tuple.second
  1998                      |> Common.notContains Effects.FetchAllJobs
  1999          , test "auto refreshes jobs on next five-second tick after dropping" <|
  2000              \_ ->
  2001                  Common.init "/"
  2002                      |> Application.handleCallback
  2003                          (Callback.AllJobsFetched <| Ok [])
  2004                      |> Tuple.first
  2005                      |> Application.update
  2006                          (ApplicationMsgs.Update <| Msgs.DragStart "team" "pipeline")
  2007                      |> Tuple.first
  2008                      |> Application.handleDelivery
  2009                          (ClockTicked FiveSeconds <|
  2010                              Time.millisToPosix 0
  2011                          )
  2012                      |> Tuple.first
  2013                      |> Application.update
  2014                          (ApplicationMsgs.Update <| Msgs.DragEnd)
  2015                      |> Tuple.first
  2016                      |> Application.handleDelivery
  2017                          (ClockTicked FiveSeconds <|
  2018                              Time.millisToPosix 0
  2019                          )
  2020                      |> Tuple.second
  2021                      |> Common.contains Effects.FetchAllJobs
  2022          , test "don't fetch any jobs until the first request finishes" <|
  2023              \_ ->
  2024                  Common.init "/"
  2025                      |> Application.handleDelivery
  2026                          (ClockTicked FiveSeconds <| Time.millisToPosix 0)
  2027                      |> Tuple.second
  2028                      |> Common.notContains Effects.FetchAllJobs
  2029          , test "don't fetch all jobs until the last request finishes" <|
  2030              \_ ->
  2031                  Common.init "/"
  2032                      |> Application.handleCallback
  2033                          (Callback.AllJobsFetched <| Ok [])
  2034                      |> Tuple.first
  2035                      |> Application.handleDelivery
  2036                          (ClockTicked FiveSeconds <| Time.millisToPosix 0)
  2037                      |> Tuple.first
  2038                      |> Application.handleDelivery
  2039                          (ClockTicked FiveSeconds <| Time.millisToPosix 0)
  2040                      |> Tuple.second
  2041                      |> Common.notContains Effects.FetchAllJobs
  2042          , test "navigate to non-hd view on logged out when in non-hd view" <|
  2043              \_ ->
  2044                  Common.init "/"
  2045                      |> Application.handleCallback
  2046                          (Callback.LoggedOut <| Ok ())
  2047                      |> Tuple.second
  2048                      |> Common.contains (Effects.NavigateTo "/")
  2049          , test "navigate to hd view on logged out when in hd view" <|
  2050              \_ ->
  2051                  Common.init "/hd"
  2052                      |> Application.handleCallback
  2053                          (Callback.LoggedOut <| Ok ())
  2054                      |> Tuple.second
  2055                      |> Common.contains (Effects.NavigateTo "/hd")
  2056          , test "fetch all teams on logged out" <|
  2057              \_ ->
  2058                  Common.init "/"
  2059                      |> Application.handleCallback
  2060                          (Callback.LoggedOut <| Ok ())
  2061                      |> Tuple.second
  2062                      |> Common.contains Effects.FetchAllTeams
  2063          , test "fetch all resources on logged out" <|
  2064              \_ ->
  2065                  Common.init "/"
  2066                      |> Application.handleCallback
  2067                          (Callback.LoggedOut <| Ok ())
  2068                      |> Tuple.second
  2069                      |> Common.contains Effects.FetchAllResources
  2070          , test "fetch all jobs on logged out" <|
  2071              \_ ->
  2072                  Common.init "/"
  2073                      |> Application.handleCallback
  2074                          (Callback.LoggedOut <| Ok ())
  2075                      |> Tuple.second
  2076                      |> Common.contains Effects.FetchAllJobs
  2077          , test "fetch all pipelines on logged out" <|
  2078              \_ ->
  2079                  Common.init "/"
  2080                      |> Application.handleCallback
  2081                          (Callback.LoggedOut <| Ok ())
  2082                      |> Tuple.second
  2083                      |> Common.contains Effects.FetchAllPipelines
  2084          ]
  2085  
  2086  
  2087  afterSeconds : Int -> Application.Model -> Application.Model
  2088  afterSeconds n =
  2089      List.repeat n
  2090          (Application.update
  2091              (ApplicationMsgs.DeliveryReceived <|
  2092                  ClockTicked OneSecond <|
  2093                      Time.millisToPosix 1000
  2094              )
  2095              >> Tuple.first
  2096          )
  2097          |> List.foldr (>>) identity
  2098  
  2099  
  2100  csrfToken : String
  2101  csrfToken =
  2102      "csrf_token"
  2103  
  2104  
  2105  iconSelector : { size : String, image : Assets.Asset } -> List Selector
  2106  iconSelector { size, image } =
  2107      [ style "background-image" <| Assets.backgroundImage <| Just image
  2108      , style "background-position" "50% 50%"
  2109      , style "background-repeat" "no-repeat"
  2110      , style "width" size
  2111      , style "height" size
  2112      ]
  2113  
  2114  
  2115  whenOnDashboard : { highDensity : Bool } -> Application.Model
  2116  whenOnDashboard { highDensity } =
  2117      Common.init
  2118          (if highDensity then
  2119              "/hd"
  2120  
  2121           else
  2122              "/"
  2123          )
  2124          |> Application.handleCallback
  2125              (Callback.GotViewport Msgs.Dashboard <|
  2126                  Ok <|
  2127                      { scene =
  2128                          { width = 600
  2129                          , height = 600
  2130                          }
  2131                      , viewport =
  2132                          { width = 600
  2133                          , height = 600
  2134                          , x = 0
  2135                          , y = 0
  2136                          }
  2137                      }
  2138              )
  2139          |> Tuple.first
  2140  
  2141  
  2142  whenOnDashboardViewingAllPipelines : { highDensity : Bool } -> Application.Model
  2143  whenOnDashboardViewingAllPipelines { highDensity } =
  2144      whenOnDashboard { highDensity = highDensity }
  2145          |> Application.handleDelivery
  2146              (RouteChanged <|
  2147                  Routes.Dashboard
  2148                      { searchType =
  2149                          if highDensity then
  2150                              Routes.HighDensity
  2151  
  2152                          else
  2153                              Routes.Normal ""
  2154                      , dashboardView = Routes.ViewAllPipelines
  2155                      }
  2156              )
  2157          |> Tuple.first
  2158  
  2159  
  2160  givenDataAndUser :
  2161      List Concourse.Team
  2162      -> Concourse.User
  2163      -> Application.Model
  2164      -> ( Application.Model, List Effects.Effect )
  2165  givenDataAndUser data user =
  2166      Application.handleCallback
  2167          (Callback.AllTeamsFetched <| Ok data)
  2168          >> Tuple.first
  2169          >> Application.handleCallback (Callback.UserFetched <| Ok user)
  2170  
  2171  
  2172  userWithRoles : List ( String, List String ) -> Concourse.User
  2173  userWithRoles roles =
  2174      { id = "0"
  2175      , userName = "test"
  2176      , name = "test"
  2177      , email = "test"
  2178      , isAdmin = False
  2179      , teams =
  2180          Dict.fromList roles
  2181      }
  2182  
  2183  
  2184  givenDataUnauthenticated :
  2185      List Concourse.Team
  2186      -> Application.Model
  2187      -> ( Application.Model, List Effects.Effect )
  2188  givenDataUnauthenticated data =
  2189      Application.handleCallback
  2190          (Callback.AllTeamsFetched <| Ok data)
  2191          >> Tuple.first
  2192          >> Application.handleCallback
  2193              (Callback.UserFetched <| Data.httpUnauthorized)
  2194  
  2195  
  2196  givenClusterInfo :
  2197      String
  2198      -> String
  2199      -> Application.Model
  2200      -> ( Application.Model, List Effects.Effect )
  2201  givenClusterInfo version clusterName =
  2202      Application.handleCallback
  2203          (Callback.ClusterInfoFetched <|
  2204              Ok { version = version, clusterName = clusterName }
  2205          )
  2206  
  2207  
  2208  apiData : List ( String, List String ) -> List Concourse.Team
  2209  apiData pipelines =
  2210      pipelines |> List.map Tuple.first |> List.indexedMap Concourse.Team
  2211  
  2212  
  2213  running : Concourse.Job -> Concourse.Job
  2214  running j =
  2215      { j
  2216          | nextBuild =
  2217              Just
  2218                  { id = 1
  2219                  , name = "1"
  2220                  , job = Just Data.jobId
  2221                  , status = BuildStatusStarted
  2222                  , duration =
  2223                      { startedAt = Nothing
  2224                      , finishedAt = Nothing
  2225                      }
  2226                  , reapTime = Nothing
  2227                  }
  2228      }
  2229  
  2230  
  2231  otherJob : BuildStatus -> Concourse.Job
  2232  otherJob =
  2233      jobWithNameTransitionedAt "other-job" <| Just <| Time.millisToPosix 0
  2234  
  2235  
  2236  job : BuildStatus -> Concourse.Job
  2237  job =
  2238      jobWithNameTransitionedAt "job" <| Just <| Time.millisToPosix 0
  2239  
  2240  
  2241  jobWithNameTransitionedAt : String -> Maybe Time.Posix -> BuildStatus -> Concourse.Job
  2242  jobWithNameTransitionedAt jobName transitionedAt status =
  2243      { name = jobName
  2244      , pipelineName = "pipeline"
  2245      , teamName = "team"
  2246      , nextBuild = Nothing
  2247      , finishedBuild =
  2248          Just
  2249              { id = 0
  2250              , name = "0"
  2251              , job = Just Data.jobId
  2252              , status = status
  2253              , duration =
  2254                  { startedAt = Nothing
  2255                  , finishedAt = Nothing
  2256                  }
  2257              , reapTime = Nothing
  2258              }
  2259      , transitionBuild =
  2260          transitionedAt
  2261              |> Maybe.map
  2262                  (\t ->
  2263                      { id = 1
  2264                      , name = "1"
  2265                      , job = Just Data.jobId
  2266                      , status = status
  2267                      , duration =
  2268                          { startedAt = Nothing
  2269                          , finishedAt = Just <| t
  2270                          }
  2271                      , reapTime = Nothing
  2272                      }
  2273                  )
  2274      , paused = False
  2275      , disableManualTrigger = False
  2276      , inputs = []
  2277      , outputs = []
  2278      , groups = []
  2279      }
  2280  
  2281  
  2282  circularJobs : List Concourse.Job
  2283  circularJobs =
  2284      [ { name = "jobA"
  2285        , pipelineName = "pipeline"
  2286        , teamName = "team"
  2287        , nextBuild = Nothing
  2288        , finishedBuild =
  2289              Just
  2290                  { id = 0
  2291                  , name = "0"
  2292                  , job = Just (Data.jobId |> Data.withJobName "jobA")
  2293                  , status = BuildStatusSucceeded
  2294                  , duration =
  2295                      { startedAt = Nothing
  2296                      , finishedAt = Nothing
  2297                      }
  2298                  , reapTime = Nothing
  2299                  }
  2300        , transitionBuild =
  2301              Just
  2302                  { id = 1
  2303                  , name = "1"
  2304                  , job = Just (Data.jobId |> Data.withJobName "jobA")
  2305                  , status = BuildStatusSucceeded
  2306                  , duration =
  2307                      { startedAt = Nothing
  2308                      , finishedAt = Just <| Time.millisToPosix 0
  2309                      }
  2310                  , reapTime = Nothing
  2311                  }
  2312        , paused = False
  2313        , disableManualTrigger = False
  2314        , inputs =
  2315              [ { name = "inA"
  2316                , resource = "res0"
  2317                , passed = [ "jobB" ]
  2318                , trigger = True
  2319                }
  2320              ]
  2321        , outputs = []
  2322        , groups = []
  2323        }
  2324      , { name = "jobB"
  2325        , pipelineName = "pipeline"
  2326        , teamName = "team"
  2327        , nextBuild = Nothing
  2328        , finishedBuild =
  2329              Just
  2330                  { id = 0
  2331                  , name = "0"
  2332                  , job = Just (Data.jobId |> Data.withJobName "jobB")
  2333                  , status = BuildStatusSucceeded
  2334                  , duration =
  2335                      { startedAt = Nothing
  2336                      , finishedAt = Nothing
  2337                      }
  2338                  , reapTime = Nothing
  2339                  }
  2340        , transitionBuild =
  2341              Just
  2342                  { id = 1
  2343                  , name = "1"
  2344                  , job = Just (Data.jobId |> Data.withJobName "jobB")
  2345                  , status = BuildStatusSucceeded
  2346                  , duration =
  2347                      { startedAt = Nothing
  2348                      , finishedAt = Just <| Time.millisToPosix 0
  2349                      }
  2350                  , reapTime = Nothing
  2351                  }
  2352        , paused = False
  2353        , disableManualTrigger = False
  2354        , inputs =
  2355              [ { name = "inB"
  2356                , resource = "res0"
  2357                , passed = [ "jobA" ]
  2358                , trigger = True
  2359                }
  2360              ]
  2361        , outputs = []
  2362        , groups = []
  2363        }
  2364      ]
  2365  
  2366  
  2367  teamHeaderSelector : List Selector
  2368  teamHeaderSelector =
  2369      [ class <| .sectionHeaderClass Effects.stickyHeaderConfig ]
  2370  
  2371  
  2372  teamHeaderHasNoPill :
  2373      String
  2374      -> Query.Single ApplicationMsgs.TopLevelMessage
  2375      -> Expectation
  2376  teamHeaderHasNoPill teamName =
  2377      Query.find (teamHeaderSelector ++ [ containing [ text teamName ] ])
  2378          >> Query.children []
  2379          >> Query.count (Expect.equal 1)
  2380  
  2381  
  2382  teamHeaderHasPill :
  2383      String
  2384      -> String
  2385      -> Query.Single ApplicationMsgs.TopLevelMessage
  2386      -> Expectation
  2387  teamHeaderHasPill teamName pillText =
  2388      Query.find (teamHeaderSelector ++ [ containing [ text teamName ] ])
  2389          >> Query.children []
  2390          >> Expect.all
  2391              [ Query.count (Expect.equal 2)
  2392              , Query.index 1 >> Query.has [ text pillText ]
  2393              ]