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

     1  module BuildTests exposing (all)
     2  
     3  import Application.Application as Application
     4  import Array
     5  import Assets
     6  import Build.Build as Build
     7  import Build.Models as Models
     8  import Build.StepTree.Models as STModels
     9  import Char
    10  import Colors
    11  import Common exposing (defineHoverBehaviour, isColorWithStripes)
    12  import Concourse exposing (BuildPrepStatus(..))
    13  import Concourse.BuildStatus exposing (BuildStatus(..))
    14  import Concourse.Pagination exposing (Direction(..))
    15  import DashboardTests exposing (iconSelector, middleGrey)
    16  import Data
    17  import Dict
    18  import Expect
    19  import Html.Attributes as Attr
    20  import Http
    21  import Json.Encode as Encode
    22  import Keyboard
    23  import Message.Callback as Callback
    24  import Message.Effects as Effects
    25  import Message.Message
    26  import Message.ScrollDirection as ScrollDirection
    27  import Message.Subscription as Subscription exposing (Delivery(..), Interval(..))
    28  import Message.TopLevelMessage as Msgs
    29  import Routes
    30  import StrictEvents exposing (DeltaMode(..))
    31  import Test exposing (..)
    32  import Test.Html.Event as Event
    33  import Test.Html.Query as Query
    34  import Test.Html.Selector
    35      exposing
    36          ( attribute
    37          , class
    38          , containing
    39          , id
    40          , style
    41          , tag
    42          , text
    43          )
    44  import Time
    45  import Url
    46  import UserState
    47  
    48  
    49  all : Test
    50  all =
    51      describe "build page" <|
    52          let
    53              buildId =
    54                  Data.jobBuildId
    55  
    56              flags =
    57                  { turbulenceImgSrc = ""
    58                  , notFoundImgSrc = ""
    59                  , csrfToken = csrfToken
    60                  , authToken = ""
    61                  , pipelineRunningKeyframes = ""
    62                  }
    63  
    64              fetchBuild : BuildStatus -> Application.Model -> ( Application.Model, List Effects.Effect )
    65              fetchBuild status =
    66                  Application.handleCallback <|
    67                      Callback.BuildFetched <|
    68                          Ok (Data.jobBuild status)
    69  
    70              fetchBuildWithStatus :
    71                  BuildStatus
    72                  -> Application.Model
    73                  -> Application.Model
    74              fetchBuildWithStatus status =
    75                  Application.handleCallback
    76                      (Callback.BuildFetched <| Ok <| Data.jobBuild status)
    77                      >> Tuple.first
    78                      >> Application.handleCallback
    79                          (Callback.BuildHistoryFetched
    80                              (Ok
    81                                  { pagination =
    82                                      { previousPage = Nothing
    83                                      , nextPage = Nothing
    84                                      }
    85                                  , content =
    86                                      [ Data.jobBuild status
    87                                      ]
    88                                  }
    89                              )
    90                          )
    91                      >> Tuple.first
    92  
    93              fetchJobDetails :
    94                  Application.Model
    95                  -> ( Application.Model, List Effects.Effect )
    96              fetchJobDetails =
    97                  Application.handleCallback <|
    98                      Callback.BuildJobDetailsFetched <|
    99                          Ok
   100                              (Data.job 0 |> Data.withShortPipelineId |> Data.withName "j")
   101  
   102              fetchJobDetailsNoTrigger :
   103                  Application.Model
   104                  -> ( Application.Model, List Effects.Effect )
   105              fetchJobDetailsNoTrigger =
   106                  Application.handleCallback <|
   107                      Callback.BuildJobDetailsFetched <|
   108                          Ok
   109                              (Data.job 0
   110                                  |> Data.withShortPipelineId
   111                                  |> Data.withName "j"
   112                                  |> Data.withDisableManualTrigger True
   113                              )
   114  
   115              fetchHistory :
   116                  Application.Model
   117                  -> ( Application.Model, List Effects.Effect )
   118              fetchHistory =
   119                  Application.handleCallback
   120                      (Callback.BuildHistoryFetched
   121                          (Ok
   122                              { pagination =
   123                                  { previousPage = Nothing
   124                                  , nextPage = Nothing
   125                                  }
   126                              , content = [ Data.jobBuild BuildStatusSucceeded ]
   127                              }
   128                          )
   129                      )
   130  
   131              csrfToken : String
   132              csrfToken =
   133                  "csrf_token"
   134  
   135              eventsUrl : String
   136              eventsUrl =
   137                  "http://localhost:8080/api/v1/builds/1/events"
   138          in
   139          [ test "converts URL hash to highlighted line in view" <|
   140              \_ ->
   141                  Application.init
   142                      flags
   143                      { protocol = Url.Http
   144                      , host = ""
   145                      , port_ = Nothing
   146                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
   147                      , query = Nothing
   148                      , fragment = Just "Lstepid:1"
   149                      }
   150                      |> Tuple.first
   151                      |> fetchBuild BuildStatusStarted
   152                      |> Tuple.first
   153                      |> Application.handleCallback
   154                          (Callback.PlanAndResourcesFetched 1 <|
   155                              Ok <|
   156                                  ( { id = "stepid"
   157                                    , step =
   158                                          Concourse.BuildStepTask
   159                                              "step"
   160                                    }
   161                                  , { inputs = [], outputs = [] }
   162                                  )
   163                          )
   164                      |> Tuple.first
   165                      |> Application.update
   166                          (Msgs.DeliveryReceived <|
   167                              EventsReceived <|
   168                                  Ok <|
   169                                      [ { url = eventsUrl
   170                                        , data =
   171                                              STModels.StartTask
   172                                                  { source = "stdout"
   173                                                  , id = "stepid"
   174                                                  }
   175                                                  (Time.millisToPosix 0)
   176                                        }
   177                                      , { url = eventsUrl
   178                                        , data =
   179                                              STModels.Log
   180                                                  { source = "stdout"
   181                                                  , id = "stepid"
   182                                                  }
   183                                                  "log message"
   184                                                  Nothing
   185                                        }
   186                                      ]
   187                          )
   188                      |> Tuple.first
   189                      |> Common.queryView
   190                      |> Query.find
   191                          [ class "timestamped-line"
   192                          , containing [ text "log message" ]
   193                          ]
   194                      |> Query.has [ class "highlighted-line" ]
   195          , test "scrolls to highlighted line" <|
   196              \_ ->
   197                  Application.init
   198                      flags
   199                      { protocol = Url.Http
   200                      , host = ""
   201                      , port_ = Nothing
   202                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
   203                      , query = Nothing
   204                      , fragment = Just "Lstepid:1"
   205                      }
   206                      |> Tuple.first
   207                      |> fetchBuild BuildStatusStarted
   208                      |> Tuple.first
   209                      |> Application.handleCallback
   210                          (Callback.PlanAndResourcesFetched 1 <|
   211                              Ok <|
   212                                  ( { id = "stepid"
   213                                    , step =
   214                                          Concourse.BuildStepTask
   215                                              "step"
   216                                    }
   217                                  , { inputs = [], outputs = [] }
   218                                  )
   219                          )
   220                      |> Tuple.first
   221                      |> Application.update
   222                          (Msgs.DeliveryReceived <|
   223                              EventsReceived <|
   224                                  Ok <|
   225                                      [ { url = eventsUrl
   226                                        , data =
   227                                              STModels.StartTask
   228                                                  { source = "stdout"
   229                                                  , id = "stepid"
   230                                                  }
   231                                                  (Time.millisToPosix 0)
   232                                        }
   233                                      , { url = eventsUrl
   234                                        , data =
   235                                              STModels.Log
   236                                                  { source = "stdout"
   237                                                  , id = "stepid"
   238                                                  }
   239                                                  "log message"
   240                                                  Nothing
   241                                        }
   242                                      ]
   243                          )
   244                      |> Tuple.second
   245                      |> Common.contains (Effects.Scroll (ScrollDirection.ToId "stepid:1") "build-body")
   246          , test "scrolls to top of highlighted range" <|
   247              \_ ->
   248                  Application.init
   249                      flags
   250                      { protocol = Url.Http
   251                      , host = ""
   252                      , port_ = Nothing
   253                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
   254                      , query = Nothing
   255                      , fragment = Just "Lstepid:1:3"
   256                      }
   257                      |> Tuple.first
   258                      |> fetchBuild BuildStatusStarted
   259                      |> Tuple.first
   260                      |> Application.handleCallback
   261                          (Callback.PlanAndResourcesFetched 1 <|
   262                              Ok <|
   263                                  ( { id = "stepid"
   264                                    , step =
   265                                          Concourse.BuildStepTask
   266                                              "step"
   267                                    }
   268                                  , { inputs = [], outputs = [] }
   269                                  )
   270                          )
   271                      |> Tuple.first
   272                      |> Application.update
   273                          (Msgs.DeliveryReceived <|
   274                              EventsReceived <|
   275                                  Ok <|
   276                                      [ { url = eventsUrl
   277                                        , data =
   278                                              STModels.StartTask
   279                                                  { source = "stdout"
   280                                                  , id = "stepid"
   281                                                  }
   282                                                  (Time.millisToPosix 0)
   283                                        }
   284                                      , { url = eventsUrl
   285                                        , data =
   286                                              STModels.Log
   287                                                  { source = "stdout"
   288                                                  , id = "stepid"
   289                                                  }
   290                                                  "log message"
   291                                                  Nothing
   292                                        }
   293                                      ]
   294                          )
   295                      |> Tuple.second
   296                      |> Common.contains (Effects.Scroll (ScrollDirection.ToId "stepid:1") "build-body")
   297          , test "does not scroll to an invalid range" <|
   298              \_ ->
   299                  Application.init
   300                      flags
   301                      { protocol = Url.Http
   302                      , host = ""
   303                      , port_ = Nothing
   304                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
   305                      , query = Nothing
   306                      , fragment = Just "Lstepid:2:1"
   307                      }
   308                      |> Tuple.first
   309                      |> fetchBuild BuildStatusStarted
   310                      |> Tuple.first
   311                      |> Application.handleCallback
   312                          (Callback.PlanAndResourcesFetched 1 <|
   313                              Ok <|
   314                                  ( { id = "stepid"
   315                                    , step =
   316                                          Concourse.BuildStepTask
   317                                              "step"
   318                                    }
   319                                  , { inputs = [], outputs = [] }
   320                                  )
   321                          )
   322                      |> Tuple.first
   323                      |> Application.update
   324                          (Msgs.DeliveryReceived <|
   325                              EventsReceived <|
   326                                  Ok <|
   327                                      [ { url = eventsUrl
   328                                        , data =
   329                                              STModels.StartTask
   330                                                  { source = "stdout"
   331                                                  , id = "stepid"
   332                                                  }
   333                                                  (Time.millisToPosix 0)
   334                                        }
   335                                      , { url = eventsUrl
   336                                        , data =
   337                                              STModels.Log
   338                                                  { source = "stdout"
   339                                                  , id = "stepid"
   340                                                  }
   341                                                  "log message\n"
   342                                                  Nothing
   343                                        }
   344                                      , { url = eventsUrl
   345                                        , data =
   346                                              STModels.Log
   347                                                  { source = "stdout"
   348                                                  , id = "stepid"
   349                                                  }
   350                                                  "log message"
   351                                                  Nothing
   352                                        }
   353                                      ]
   354                          )
   355                      |> Tuple.second
   356                      |> Common.notContains (Effects.Scroll (ScrollDirection.ToId "stepid:2") "build-body")
   357          , test "does not re-scroll to an id multiple times" <|
   358              \_ ->
   359                  Application.init
   360                      flags
   361                      { protocol = Url.Http
   362                      , host = ""
   363                      , port_ = Nothing
   364                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
   365                      , query = Nothing
   366                      , fragment = Just "Lstepid:1"
   367                      }
   368                      |> Tuple.first
   369                      |> fetchBuild BuildStatusStarted
   370                      |> Tuple.first
   371                      |> Application.handleCallback
   372                          (Callback.PlanAndResourcesFetched 1 <|
   373                              Ok <|
   374                                  ( { id = "stepid"
   375                                    , step =
   376                                          Concourse.BuildStepTask
   377                                              "step"
   378                                    }
   379                                  , { inputs = [], outputs = [] }
   380                                  )
   381                          )
   382                      |> Tuple.first
   383                      |> Application.handleDelivery
   384                          (EventsReceived <|
   385                              Ok <|
   386                                  [ { url = eventsUrl
   387                                    , data =
   388                                          STModels.StartTask
   389                                              { source = "stdout"
   390                                              , id = "stepid"
   391                                              }
   392                                              (Time.millisToPosix 0)
   393                                    }
   394                                  , { url = eventsUrl
   395                                    , data =
   396                                          STModels.Log
   397                                              { source = "stdout"
   398                                              , id = "stepid"
   399                                              }
   400                                              "log message"
   401                                              Nothing
   402                                    }
   403                                  ]
   404                          )
   405                      |> Tuple.first
   406                      |> Application.handleDelivery
   407                          (EventsReceived <| Ok [])
   408                      |> Tuple.second
   409                      |> Common.notContains (Effects.Scroll (ScrollDirection.ToId "stepid:1") "build-body")
   410          , test "auto-scroll disallowed before scrolled to highlighted line" <|
   411              \_ ->
   412                  Application.init
   413                      flags
   414                      { protocol = Url.Http
   415                      , host = ""
   416                      , port_ = Nothing
   417                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
   418                      , query = Nothing
   419                      , fragment = Just "Lstepid:1"
   420                      }
   421                      |> Tuple.first
   422                      |> fetchBuild BuildStatusStarted
   423                      |> Tuple.first
   424                      |> Application.handleCallback
   425                          (Callback.PlanAndResourcesFetched 1 <|
   426                              Ok <|
   427                                  ( { id = "stepid"
   428                                    , step =
   429                                          Concourse.BuildStepTask
   430                                              "step"
   431                                    }
   432                                  , { inputs = [], outputs = [] }
   433                                  )
   434                          )
   435                      |> Tuple.first
   436                      |> Application.handleDelivery
   437                          (EventsReceived <|
   438                              Ok <|
   439                                  [ { url = eventsUrl
   440                                    , data =
   441                                          STModels.StartTask
   442                                              { source = "stdout"
   443                                              , id = "stepid"
   444                                              }
   445                                              (Time.millisToPosix 0)
   446                                    }
   447                                  , { url = eventsUrl
   448                                    , data =
   449                                          STModels.Log
   450                                              { source = "stdout"
   451                                              , id = "stepid"
   452                                              }
   453                                              "log message"
   454                                              Nothing
   455                                    }
   456                                  ]
   457                          )
   458                      |> Tuple.first
   459                      |> Application.update
   460                          (Msgs.Update <|
   461                              Message.Message.Scrolled
   462                                  { scrollHeight = 20
   463                                  , scrollTop = 10
   464                                  , clientHeight = 10
   465                                  }
   466                          )
   467                      |> Tuple.first
   468                      |> Application.handleDelivery
   469                          (EventsReceived <| Ok [])
   470                      |> Tuple.second
   471                      |> Common.notContains (Effects.Scroll ScrollDirection.ToBottom "build-body")
   472          , test "auto-scroll disallowed before scrolling away from highlighted line" <|
   473              \_ ->
   474                  Application.init
   475                      flags
   476                      { protocol = Url.Http
   477                      , host = ""
   478                      , port_ = Nothing
   479                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
   480                      , query = Nothing
   481                      , fragment = Just "Lstepid:1"
   482                      }
   483                      |> Tuple.first
   484                      |> fetchBuild BuildStatusStarted
   485                      |> Tuple.first
   486                      |> Application.handleCallback
   487                          (Callback.PlanAndResourcesFetched 1 <|
   488                              Ok <|
   489                                  ( { id = "stepid"
   490                                    , step =
   491                                          Concourse.BuildStepTask
   492                                              "step"
   493                                    }
   494                                  , { inputs = [], outputs = [] }
   495                                  )
   496                          )
   497                      |> Tuple.first
   498                      |> Application.handleDelivery
   499                          (EventsReceived <|
   500                              Ok <|
   501                                  [ { url = eventsUrl
   502                                    , data =
   503                                          STModels.StartTask
   504                                              { source = "stdout"
   505                                              , id = "stepid"
   506                                              }
   507                                              (Time.millisToPosix 0)
   508                                    }
   509                                  , { url = eventsUrl
   510                                    , data =
   511                                          STModels.Log
   512                                              { source = "stdout"
   513                                              , id = "stepid"
   514                                              }
   515                                              "log message"
   516                                              Nothing
   517                                    }
   518                                  ]
   519                          )
   520                      |> Tuple.first
   521                      |> Application.update
   522                          (Msgs.Update <|
   523                              Message.Message.Scrolled
   524                                  { scrollHeight = 20
   525                                  , scrollTop = 10
   526                                  , clientHeight = 10
   527                                  }
   528                          )
   529                      |> Tuple.first
   530                      |> Application.handleDelivery
   531                          (Subscription.ScrolledToId ( "Lstepid:1", "build-body" ))
   532                      |> Tuple.first
   533                      |> Application.handleDelivery
   534                          (EventsReceived <| Ok [])
   535                      |> Tuple.second
   536                      |> Common.notContains (Effects.Scroll ScrollDirection.ToBottom "build-body")
   537          , test "auto-scroll allowed after scrolling away from highlighted line" <|
   538              \_ ->
   539                  Application.init
   540                      flags
   541                      { protocol = Url.Http
   542                      , host = ""
   543                      , port_ = Nothing
   544                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
   545                      , query = Nothing
   546                      , fragment = Just "Lstepid:1"
   547                      }
   548                      |> Tuple.first
   549                      |> fetchBuild BuildStatusStarted
   550                      |> Tuple.first
   551                      |> Application.handleCallback
   552                          (Callback.PlanAndResourcesFetched 1 <|
   553                              Ok <|
   554                                  ( { id = "stepid"
   555                                    , step =
   556                                          Concourse.BuildStepTask
   557                                              "step"
   558                                    }
   559                                  , { inputs = [], outputs = [] }
   560                                  )
   561                          )
   562                      |> Tuple.first
   563                      |> Application.handleDelivery
   564                          (EventsReceived <|
   565                              Ok <|
   566                                  [ { url = eventsUrl
   567                                    , data =
   568                                          STModels.StartTask
   569                                              { source = "stdout"
   570                                              , id = "stepid"
   571                                              }
   572                                              (Time.millisToPosix 0)
   573                                    }
   574                                  , { url = eventsUrl
   575                                    , data =
   576                                          STModels.Log
   577                                              { source = "stdout"
   578                                              , id = "stepid"
   579                                              }
   580                                              "log message"
   581                                              Nothing
   582                                    }
   583                                  ]
   584                          )
   585                      |> Tuple.first
   586                      |> Application.handleDelivery
   587                          (Subscription.ScrolledToId ( "Lstepid:1", "build-body" ))
   588                      |> Tuple.first
   589                      |> Application.update
   590                          (Msgs.Update <|
   591                              Message.Message.Scrolled
   592                                  { scrollHeight = 20
   593                                  , scrollTop = 10
   594                                  , clientHeight = 10
   595                                  }
   596                          )
   597                      |> Tuple.first
   598                      |> Application.handleDelivery
   599                          (EventsReceived <| Ok [])
   600                      |> Tuple.second
   601                      |> Common.contains (Effects.Scroll ScrollDirection.ToBottom "build-body")
   602          , test "subscribes to scrolled to id completion" <|
   603              \_ ->
   604                  Application.init
   605                      flags
   606                      { protocol = Url.Http
   607                      , host = ""
   608                      , port_ = Nothing
   609                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
   610                      , query = Nothing
   611                      , fragment = Just "Lstepid:1"
   612                      }
   613                      |> Tuple.first
   614                      |> Application.subscriptions
   615                      |> Common.contains Subscription.OnScrolledToId
   616          , describe "page title"
   617              [ test "with a job build" <|
   618                  \_ ->
   619                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
   620                          |> fetchBuild BuildStatusSucceeded
   621                          |> Tuple.first
   622                          |> Application.view
   623                          |> .title
   624                          |> Expect.equal "j #1 - Concourse"
   625              , test "with a one-off-build" <|
   626                  \_ ->
   627                      Common.init "/builds/1"
   628                          |> Application.handleCallback
   629                              (Callback.BuildFetched <|
   630                                  Ok
   631                                      { id = 1
   632                                      , name = "1"
   633                                      , job = Nothing
   634                                      , status = BuildStatusPending
   635                                      , duration =
   636                                          { startedAt = Nothing
   637                                          , finishedAt = Nothing
   638                                          }
   639                                      , reapTime = Nothing
   640                                      }
   641                              )
   642                          |> Tuple.first
   643                          |> Application.view
   644                          |> .title
   645                          |> Expect.equal "#1 - Concourse"
   646              , test "with just the page name" <|
   647                  \_ ->
   648                      Application.init
   649                          flags
   650                          { protocol = Url.Http
   651                          , host = ""
   652                          , port_ = Nothing
   653                          , path = "/teams/t/pipelines/p/jobs/routejob/builds/1"
   654                          , query = Nothing
   655                          , fragment = Just "Lstepid:1"
   656                          }
   657                          |> Tuple.first
   658                          |> Application.view
   659                          |> .title
   660                          |> Expect.equal "routejob #1 - Concourse"
   661              ]
   662          , test "shows tombstone for reaped build with date in current zone" <|
   663              \_ ->
   664                  let
   665                      buildTime =
   666                          Just <|
   667                              Time.millisToPosix
   668                                  (12 * 60 * 60 * 1000)
   669                  in
   670                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
   671                      |> Application.handleCallback
   672                          (Callback.BuildFetched <|
   673                              Ok
   674                                  { id = 1
   675                                  , name = "1"
   676                                  , job = Just Data.shortJobId
   677                                  , status = BuildStatusSucceeded
   678                                  , duration =
   679                                      { startedAt = buildTime
   680                                      , finishedAt = buildTime
   681                                      }
   682                                  , reapTime = buildTime
   683                                  }
   684                          )
   685                      |> Tuple.first
   686                      |> Application.handleCallback
   687                          (Callback.GotCurrentTimeZone <|
   688                              Time.customZone 720 []
   689                          )
   690                      |> Tuple.first
   691                      |> Common.queryView
   692                      |> Query.find [ class "tombstone" ]
   693                      |> Query.has [ text "01/02/70" ]
   694          , test "shows passport officer when build plan request gives 401" <|
   695              \_ ->
   696                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
   697                      |> Application.handleCallback
   698                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusSucceeded))
   699                      |> Tuple.first
   700                      |> Application.handleCallback
   701                          (Callback.PlanAndResourcesFetched 1 <| Data.httpUnauthorized)
   702                      |> Tuple.first
   703                      |> Common.queryView
   704                      |> Query.has [ class "not-authorized" ]
   705          , test "shows 'build cancelled' in red when aborted build's plan request gives 404" <|
   706              \_ ->
   707                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
   708                      |> Application.handleCallback
   709                          (Callback.BuildFetched <|
   710                              Ok
   711                                  { id = 1
   712                                  , name = "1"
   713                                  , job = Just Data.shortJobId
   714                                  , status = BuildStatusAborted
   715                                  , duration =
   716                                      { startedAt = Nothing
   717                                      , finishedAt = Just <| Time.millisToPosix 0
   718                                      }
   719                                  , reapTime = Nothing
   720                                  }
   721                          )
   722                      |> Tuple.first
   723                      |> Application.handleCallback
   724                          (Callback.PlanAndResourcesFetched 1 <| Data.httpNotFound)
   725                      |> Tuple.first
   726                      |> Common.queryView
   727                      |> Query.has
   728                          [ style "background-color" Colors.frame
   729                          , style "padding" "5px 10px"
   730                          , style "color" Colors.errorLog
   731                          , containing [ text "build cancelled" ]
   732                          ]
   733          , test "shows passport officer when build prep request gives 401" <|
   734              \_ ->
   735                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
   736                      |> Application.handleCallback
   737                          (Callback.BuildFetched <|
   738                              Ok
   739                                  { id = 1
   740                                  , name = "1"
   741                                  , job = Just Data.shortJobId
   742                                  , status = BuildStatusPending
   743                                  , duration =
   744                                      { startedAt = Nothing
   745                                      , finishedAt = Nothing
   746                                      }
   747                                  , reapTime = Nothing
   748                                  }
   749                          )
   750                      |> Tuple.first
   751                      |> Application.handleCallback
   752                          (Callback.BuildPrepFetched 1 <| Data.httpUnauthorized)
   753                      |> Tuple.first
   754                      |> Common.queryView
   755                      |> Query.has [ class "not-authorized" ]
   756          , test "focuses build body when build is fetched" <|
   757              \_ ->
   758                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
   759                      |> Application.handleCallback
   760                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusSucceeded))
   761                      |> Tuple.second
   762                      |> Common.contains (Effects.Focus Build.bodyId)
   763          , test "events from a different build are discarded" <|
   764              \_ ->
   765                  Application.init
   766                      flags
   767                      { protocol = Url.Http
   768                      , host = ""
   769                      , port_ = Nothing
   770                      , path = "/builds/1"
   771                      , query = Nothing
   772                      , fragment = Just "Lstepid:1"
   773                      }
   774                      |> Tuple.first
   775                      |> Application.handleCallback
   776                          (Callback.BuildFetched <|
   777                              Ok
   778                                  { id = 1
   779                                  , name = "1"
   780                                  , job = Nothing
   781                                  , status = BuildStatusStarted
   782                                  , duration =
   783                                      { startedAt = Nothing
   784                                      , finishedAt = Nothing
   785                                      }
   786                                  , reapTime = Nothing
   787                                  }
   788                          )
   789                      |> Tuple.first
   790                      |> Application.handleCallback
   791                          (Callback.PlanAndResourcesFetched 1 <|
   792                              Ok <|
   793                                  ( { id = "stepid"
   794                                    , step =
   795                                          Concourse.BuildStepTask
   796                                              "step"
   797                                    }
   798                                  , { inputs = [], outputs = [] }
   799                                  )
   800                          )
   801                      |> Tuple.first
   802                      |> receiveEvent
   803                          { url = "http://localhost:8080/api/v1/builds/1/events"
   804                          , data = STModels.StartTask { id = "stepid", source = "" } (Time.millisToPosix 0)
   805                          }
   806                      |> Tuple.first
   807                      |> receiveEvent
   808                          { url = "http://localhost:8080/api/v1/builds/1/events"
   809                          , data =
   810                              STModels.Log
   811                                  { id = "stepid"
   812                                  , source = "stdout"
   813                                  }
   814                                  "log message"
   815                                  Nothing
   816                          }
   817                      |> Tuple.first
   818                      |> receiveEvent
   819                          { url = "http://localhost:8080/api/v1/builds/2/events"
   820                          , data =
   821                              STModels.Log
   822                                  { id = "stepid"
   823                                  , source = "stdout"
   824                                  }
   825                                  "bad message"
   826                                  Nothing
   827                          }
   828                      |> Tuple.first
   829                      |> Common.queryView
   830                      |> Query.hasNot [ text "bad message" ]
   831          , test "output does not change when the wrong build is fetched" <|
   832              \_ ->
   833                  Common.init "/teams/main/pipelines/pipeline/jobs/job/builds/1"
   834                      |> Application.handleCallback
   835                          (Callback.BuildFetched <|
   836                              Ok
   837                                  { id = 1
   838                                  , name = "1"
   839                                  , job = Nothing
   840                                  , status = BuildStatusStarted
   841                                  , duration =
   842                                      { startedAt =
   843                                          Just <| Time.millisToPosix 0
   844                                      , finishedAt = Nothing
   845                                      }
   846                                  , reapTime = Nothing
   847                                  }
   848                          )
   849                      |> Tuple.first
   850                      |> Application.handleCallback
   851                          (Callback.PlanAndResourcesFetched 1 <|
   852                              Ok <|
   853                                  ( { id = "stepid"
   854                                    , step =
   855                                          Concourse.BuildStepTask
   856                                              "my-step-name"
   857                                    }
   858                                  , { inputs = [], outputs = [] }
   859                                  )
   860                          )
   861                      |> Tuple.first
   862                      |> Application.handleCallback
   863                          (Callback.BuildFetched <|
   864                              Ok
   865                                  { id = 2
   866                                  , name = "2"
   867                                  , job = Nothing
   868                                  , status = BuildStatusStarted
   869                                  , duration =
   870                                      { startedAt =
   871                                          Just <| Time.millisToPosix 0
   872                                      , finishedAt = Nothing
   873                                      }
   874                                  , reapTime = Nothing
   875                                  }
   876                          )
   877                      |> Tuple.first
   878                      |> Common.queryView
   879                      |> Query.has [ text "my-step-name" ]
   880          , test "build name does not change when the wrong build is fetched" <|
   881              \_ ->
   882                  Common.init "/teams/main/pipelines/pipeline/jobs/job/builds/1"
   883                      |> Application.handleCallback
   884                          (Callback.BuildFetched <|
   885                              Ok
   886                                  { id = 1
   887                                  , name = "1"
   888                                  , job = Nothing
   889                                  , status = BuildStatusStarted
   890                                  , duration =
   891                                      { startedAt =
   892                                          Just <| Time.millisToPosix 0
   893                                      , finishedAt = Nothing
   894                                      }
   895                                  , reapTime = Nothing
   896                                  }
   897                          )
   898                      |> Tuple.first
   899                      |> Application.handleCallback
   900                          (Callback.BuildFetched <|
   901                              Ok
   902                                  { id = 2
   903                                  , name = "2"
   904                                  , job = Nothing
   905                                  , status = BuildStatusStarted
   906                                  , duration =
   907                                      { startedAt =
   908                                          Just <| Time.millisToPosix 0
   909                                      , finishedAt = Nothing
   910                                      }
   911                                  , reapTime = Nothing
   912                                  }
   913                          )
   914                      |> Tuple.first
   915                      |> Common.queryView
   916                      |> Query.hasNot [ text "build #2" ]
   917          , test "build prep does not appear when wrong prep is fetched" <|
   918              \_ ->
   919                  Common.init "/teams/main/pipelines/pipeline/jobs/job/builds/1"
   920                      |> Application.handleCallback
   921                          (Callback.BuildFetched <|
   922                              Ok
   923                                  { id = 1
   924                                  , name = "1"
   925                                  , job = Just Data.jobId
   926                                  , status = BuildStatusStarted
   927                                  , duration =
   928                                      { startedAt =
   929                                          Just <| Time.millisToPosix 0
   930                                      , finishedAt = Nothing
   931                                      }
   932                                  , reapTime = Nothing
   933                                  }
   934                          )
   935                      |> Tuple.first
   936                      |> Application.handleCallback
   937                          (Callback.BuildPrepFetched 2 <|
   938                              Ok
   939                                  { pausedPipeline = BuildPrepStatusUnknown
   940                                  , pausedJob = BuildPrepStatusUnknown
   941                                  , maxRunningBuilds = BuildPrepStatusUnknown
   942                                  , inputs = Dict.empty
   943                                  , inputsSatisfied = BuildPrepStatusUnknown
   944                                  , missingInputReasons = Dict.empty
   945                                  }
   946                          )
   947                      |> Tuple.first
   948                      |> Common.queryView
   949                      |> Query.hasNot [ text "preparing" ]
   950          , test "log lines have timestamps in current zone" <|
   951              \_ ->
   952                  Common.init "/builds/1"
   953                      |> Application.handleCallback
   954                          (Callback.BuildFetched <|
   955                              Ok
   956                                  { id = 1
   957                                  , name = "1"
   958                                  , job = Nothing
   959                                  , status = BuildStatusStarted
   960                                  , duration =
   961                                      { startedAt =
   962                                          Just <| Time.millisToPosix 0
   963                                      , finishedAt = Nothing
   964                                      }
   965                                  , reapTime = Nothing
   966                                  }
   967                          )
   968                      |> Tuple.first
   969                      |> Application.handleCallback
   970                          (Callback.PlanAndResourcesFetched 1 <|
   971                              Ok <|
   972                                  ( { id = "stepid"
   973                                    , step =
   974                                          Concourse.BuildStepTask
   975                                              "step"
   976                                    }
   977                                  , { inputs = [], outputs = [] }
   978                                  )
   979                          )
   980                      |> Tuple.first
   981                      |> receiveEvent
   982                          { url = "http://localhost:8080/api/v1/builds/1/events"
   983                          , data =
   984                              STModels.StartTask
   985                                  { id = "stepid"
   986                                  , source = ""
   987                                  }
   988                                  (Time.millisToPosix 0)
   989                          }
   990                      |> Tuple.first
   991                      |> receiveEvent
   992                          { url = "http://localhost:8080/api/v1/builds/1/events"
   993                          , data =
   994                              STModels.Log
   995                                  { id = "stepid"
   996                                  , source = "stdout"
   997                                  }
   998                                  "log message\n"
   999                                  (Just <| Time.millisToPosix 0)
  1000                          }
  1001                      |> Tuple.first
  1002                      |> Application.handleCallback
  1003                          (Callback.GotCurrentTimeZone <|
  1004                              Time.customZone (5 * 60) []
  1005                          )
  1006                      |> Tuple.first
  1007                      |> Application.update
  1008                          (Msgs.Update <|
  1009                              Message.Message.Click <|
  1010                                  Message.Message.StepHeader "stepid"
  1011                          )
  1012                      |> Tuple.first
  1013                      |> Common.queryView
  1014                      |> Query.findAll [ class "timestamped-line" ]
  1015                      |> Query.first
  1016                      |> Query.has [ text "05:00:00" ]
  1017          , test "when build is running it scrolls every build event" <|
  1018              \_ ->
  1019                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1020                      |> Application.handleCallback
  1021                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1022                      |> Tuple.first
  1023                      |> receiveEvent
  1024                          { url = "http://localhost:8080/api/v1/builds/1/events"
  1025                          , data = STModels.StartTask { id = "stepid", source = "" } (Time.millisToPosix 0)
  1026                          }
  1027                      |> Tuple.second
  1028                      |> Common.contains (Effects.Scroll ScrollDirection.ToBottom "build-body")
  1029          , test "when build is not running it does not scroll on build event" <|
  1030              \_ ->
  1031                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1032                      |> Application.handleCallback
  1033                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusSucceeded))
  1034                      |> Tuple.first
  1035                      |> receiveEvent
  1036                          { url = "http://localhost:8080/api/v1/builds/1/events"
  1037                          , data = STModels.StartTask { id = "stepid", source = "" } (Time.millisToPosix 0)
  1038                          }
  1039                      |> Tuple.second
  1040                      |> Expect.equal []
  1041          , test "build body has scroll handler" <|
  1042              \_ ->
  1043                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1044                      |> Application.handleCallback
  1045                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusSucceeded))
  1046                      |> Tuple.first
  1047                      |> Common.queryView
  1048                      |> Query.find [ id "build-body" ]
  1049                      |> Event.simulate
  1050                          (Event.custom "scroll" <|
  1051                              Encode.object
  1052                                  [ ( "target"
  1053                                    , Encode.object
  1054                                          [ ( "clientHeight", Encode.int 0 )
  1055                                          , ( "scrollTop", Encode.int 0 )
  1056                                          , ( "scrollHeight", Encode.int 0 )
  1057                                          ]
  1058                                    )
  1059                                  ]
  1060                          )
  1061                      |> Event.expect
  1062                          (Msgs.Update <|
  1063                              Message.Message.Scrolled
  1064                                  { scrollHeight = 0
  1065                                  , scrollTop = 0
  1066                                  , clientHeight = 0
  1067                                  }
  1068                          )
  1069          , test "when build is running but the user is not scrolled to the bottom it does not scroll on build event" <|
  1070              \_ ->
  1071                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1072                      |> Application.handleCallback
  1073                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1074                      |> Tuple.first
  1075                      |> Application.update
  1076                          (Msgs.Update <|
  1077                              Message.Message.Scrolled
  1078                                  { scrollHeight = 2
  1079                                  , scrollTop = 0
  1080                                  , clientHeight = 1
  1081                                  }
  1082                          )
  1083                      |> Tuple.first
  1084                      |> receiveEvent
  1085                          { url = "http://localhost:8080/api/v1/builds/1/events"
  1086                          , data = STModels.StartTask { id = "stepid", source = "" } (Time.millisToPosix 0)
  1087                          }
  1088                      |> Tuple.second
  1089                      |> Expect.equal []
  1090          , test "when build is running but the user scrolls back to the bottom it scrolls on build event" <|
  1091              \_ ->
  1092                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1093                      |> Application.handleCallback
  1094                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1095                      |> Tuple.first
  1096                      |> Application.update
  1097                          (Msgs.Update <|
  1098                              Message.Message.Scrolled
  1099                                  { scrollHeight = 2
  1100                                  , scrollTop = 0
  1101                                  , clientHeight = 1
  1102                                  }
  1103                          )
  1104                      |> Tuple.first
  1105                      |> Application.update
  1106                          (Msgs.Update <|
  1107                              Message.Message.Scrolled
  1108                                  { scrollHeight = 2
  1109                                  , scrollTop = 1
  1110                                  , clientHeight = 1
  1111                                  }
  1112                          )
  1113                      |> Tuple.first
  1114                      |> receiveEvent
  1115                          { url = "http://localhost:8080/api/v1/builds/1/events"
  1116                          , data = STModels.StartTask { id = "stepid", source = "" } (Time.millisToPosix 0)
  1117                          }
  1118                      |> Tuple.second
  1119                      |> Expect.equal [ Effects.Scroll ScrollDirection.ToBottom "build-body" ]
  1120          , test "pressing 'T' twice triggers two builds" <|
  1121              \_ ->
  1122                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1123                      |> Application.handleCallback
  1124                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1125                      |> Tuple.first
  1126                      |> Application.handleCallback
  1127                          (Callback.BuildJobDetailsFetched <|
  1128                              Ok
  1129                                  { name = ""
  1130                                  , pipelineName = "p"
  1131                                  , teamName = "t"
  1132                                  , nextBuild = Nothing
  1133                                  , finishedBuild = Nothing
  1134                                  , transitionBuild = Nothing
  1135                                  , paused = False
  1136                                  , disableManualTrigger = False
  1137                                  , inputs = []
  1138                                  , outputs = []
  1139                                  , groups = []
  1140                                  }
  1141                          )
  1142                      |> Tuple.first
  1143                      |> Application.update
  1144                          (Msgs.DeliveryReceived <|
  1145                              KeyDown <|
  1146                                  { ctrlKey = False
  1147                                  , shiftKey = True
  1148                                  , metaKey = False
  1149                                  , code = Keyboard.T
  1150                                  }
  1151                          )
  1152                      |> Tuple.first
  1153                      |> Application.update
  1154                          (Msgs.DeliveryReceived <|
  1155                              KeyUp <|
  1156                                  { ctrlKey = False
  1157                                  , shiftKey = False
  1158                                  , metaKey = False
  1159                                  , code = Keyboard.T
  1160                                  }
  1161                          )
  1162                      |> Tuple.first
  1163                      |> Application.update
  1164                          (Msgs.DeliveryReceived <|
  1165                              KeyDown <|
  1166                                  { ctrlKey = False
  1167                                  , shiftKey = True
  1168                                  , metaKey = False
  1169                                  , code = Keyboard.T
  1170                                  }
  1171                          )
  1172                      |> Tuple.second
  1173                      |> Expect.equal [ Effects.DoTriggerBuild Data.shortJobId ]
  1174          , test "pressing 'R' reruns build" <|
  1175              \_ ->
  1176                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1177                      |> Application.handleCallback
  1178                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusSucceeded))
  1179                      |> Tuple.first
  1180                      |> Application.handleCallback
  1181                          (Callback.BuildJobDetailsFetched <|
  1182                              Ok
  1183                                  { name = ""
  1184                                  , pipelineName = "p"
  1185                                  , teamName = "t"
  1186                                  , nextBuild = Nothing
  1187                                  , finishedBuild = Nothing
  1188                                  , transitionBuild = Nothing
  1189                                  , paused = False
  1190                                  , disableManualTrigger = False
  1191                                  , inputs = []
  1192                                  , outputs = []
  1193                                  , groups = []
  1194                                  }
  1195                          )
  1196                      |> Tuple.first
  1197                      |> Application.update
  1198                          (Msgs.DeliveryReceived <|
  1199                              KeyDown <|
  1200                                  { ctrlKey = False
  1201                                  , shiftKey = True
  1202                                  , metaKey = False
  1203                                  , code = Keyboard.R
  1204                                  }
  1205                          )
  1206                      |> Tuple.second
  1207                      |> Expect.equal [ Effects.RerunJobBuild Data.jobBuildId ]
  1208          , test "pressing 'R' does nothing if there is a running build" <|
  1209              \_ ->
  1210                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1211                      |> Application.handleCallback
  1212                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1213                      |> Tuple.first
  1214                      |> Application.handleCallback
  1215                          (Callback.BuildJobDetailsFetched <|
  1216                              Ok
  1217                                  { name = ""
  1218                                  , pipelineName = "p"
  1219                                  , teamName = "t"
  1220                                  , nextBuild = Nothing
  1221                                  , finishedBuild = Nothing
  1222                                  , transitionBuild = Nothing
  1223                                  , paused = False
  1224                                  , disableManualTrigger = False
  1225                                  , inputs = []
  1226                                  , outputs = []
  1227                                  , groups = []
  1228                                  }
  1229                          )
  1230                      |> Tuple.first
  1231                      |> Application.update
  1232                          (Msgs.DeliveryReceived <|
  1233                              KeyDown <|
  1234                                  { ctrlKey = False
  1235                                  , shiftKey = True
  1236                                  , metaKey = False
  1237                                  , code = Keyboard.R
  1238                                  }
  1239                          )
  1240                      |> Tuple.second
  1241                      |> Expect.equal []
  1242          , test "pressing 'gg' scrolls to the top" <|
  1243              \_ ->
  1244                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1245                      |> Application.handleCallback
  1246                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1247                      |> Tuple.first
  1248                      |> Application.update
  1249                          (Msgs.DeliveryReceived <|
  1250                              KeyDown <|
  1251                                  { ctrlKey = False
  1252                                  , shiftKey = False
  1253                                  , metaKey = False
  1254                                  , code = Keyboard.G
  1255                                  }
  1256                          )
  1257                      |> Tuple.first
  1258                      |> Application.update
  1259                          (Msgs.DeliveryReceived <|
  1260                              KeyDown <|
  1261                                  { ctrlKey = False
  1262                                  , shiftKey = False
  1263                                  , metaKey = False
  1264                                  , code = Keyboard.G
  1265                                  }
  1266                          )
  1267                      |> Tuple.second
  1268                      |> Expect.equal [ Effects.Scroll ScrollDirection.ToTop "build-body" ]
  1269          , test "pressing 'G' scrolls to the bottom" <|
  1270              \_ ->
  1271                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1272                      |> Application.handleCallback
  1273                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1274                      |> Tuple.first
  1275                      |> Application.update
  1276                          (Msgs.DeliveryReceived <|
  1277                              KeyDown
  1278                                  { ctrlKey = False
  1279                                  , shiftKey = True
  1280                                  , metaKey = False
  1281                                  , code = Keyboard.G
  1282                                  }
  1283                          )
  1284                      |> Tuple.second
  1285                      |> Expect.equal [ Effects.Scroll ScrollDirection.ToBottom "build-body" ]
  1286          , test "pressing 'g' once does nothing" <|
  1287              \_ ->
  1288                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1289                      |> Application.handleCallback
  1290                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1291                      |> Tuple.first
  1292                      |> Application.update
  1293                          (Msgs.DeliveryReceived <|
  1294                              KeyDown <|
  1295                                  { ctrlKey = False
  1296                                  , shiftKey = False
  1297                                  , metaKey = False
  1298                                  , code = Keyboard.G
  1299                                  }
  1300                          )
  1301                      |> Tuple.second
  1302                      |> Expect.equal []
  1303          , test "pressing '?' shows the keyboard help" <|
  1304              \_ ->
  1305                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1306                      |> Application.handleCallback
  1307                          (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1308                      |> Tuple.first
  1309                      |> Application.update
  1310                          (Msgs.DeliveryReceived <|
  1311                              KeyDown <|
  1312                                  { ctrlKey = False
  1313                                  , shiftKey = True
  1314                                  , metaKey = False
  1315                                  , code = Keyboard.Slash
  1316                                  }
  1317                          )
  1318                      |> Tuple.first
  1319                      |> Common.queryView
  1320                      |> Query.find [ class "keyboard-help" ]
  1321                      |> Query.hasNot [ class "hidden" ]
  1322          , test "says 'loading' on page load" <|
  1323              \_ ->
  1324                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1325                      |> Common.queryView
  1326                      |> Query.has [ text "loading" ]
  1327          , test "fetches build on page load" <|
  1328              \_ ->
  1329                  Application.init
  1330                      { turbulenceImgSrc = ""
  1331                      , notFoundImgSrc = "notfound.svg"
  1332                      , csrfToken = "csrf_token"
  1333                      , authToken = ""
  1334                      , pipelineRunningKeyframes = "pipeline-running"
  1335                      }
  1336                      { protocol = Url.Http
  1337                      , host = ""
  1338                      , port_ = Nothing
  1339                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
  1340                      , query = Nothing
  1341                      , fragment = Nothing
  1342                      }
  1343                      |> Tuple.second
  1344                      |> Common.contains (Effects.FetchJobBuild Data.jobBuildId)
  1345          , test "does not reload build when highlight is modified" <|
  1346              \_ ->
  1347                  let
  1348                      buildParams =
  1349                          { id = Data.jobBuildId
  1350                          , highlight = Routes.HighlightNothing
  1351                          }
  1352                  in
  1353                  Common.init "/"
  1354                      |> Application.handleDelivery
  1355                          (RouteChanged <|
  1356                              Routes.Build
  1357                                  buildParams
  1358                          )
  1359                      |> Tuple.first
  1360                      |> Application.handleDelivery
  1361                          (RouteChanged <|
  1362                              Routes.Build
  1363                                  { buildParams
  1364                                      | highlight = Routes.HighlightLine "step" 1
  1365                                  }
  1366                          )
  1367                      |> Tuple.second
  1368                      |> Common.notContains
  1369                          (Effects.FetchJobBuild <| buildParams.id)
  1370          , test "does not reload one off build page when highlight is modified" <|
  1371              \_ ->
  1372                  let
  1373                      buildParams =
  1374                          { id = 1
  1375                          , highlight = Routes.HighlightNothing
  1376                          }
  1377                  in
  1378                  Common.init "/"
  1379                      |> Application.handleDelivery
  1380                          (RouteChanged <|
  1381                              Routes.OneOffBuild
  1382                                  buildParams
  1383                          )
  1384                      |> Tuple.first
  1385                      |> Application.handleDelivery
  1386                          (RouteChanged <|
  1387                              Routes.OneOffBuild
  1388                                  { buildParams
  1389                                      | highlight = Routes.HighlightLine "step" 1
  1390                                  }
  1391                          )
  1392                      |> Tuple.second
  1393                      |> Common.notContains
  1394                          (Effects.FetchBuild 0 buildParams.id)
  1395          , test "gets current timezone on page load" <|
  1396              \_ ->
  1397                  Application.init
  1398                      { turbulenceImgSrc = ""
  1399                      , notFoundImgSrc = "notfound.svg"
  1400                      , csrfToken = "csrf_token"
  1401                      , authToken = ""
  1402                      , pipelineRunningKeyframes = "pipeline-running"
  1403                      }
  1404                      { protocol = Url.Http
  1405                      , host = ""
  1406                      , port_ = Nothing
  1407                      , path = "/teams/t/pipelines/p/jobs/j/builds/1"
  1408                      , query = Nothing
  1409                      , fragment = Nothing
  1410                      }
  1411                      |> Tuple.second
  1412                      |> Common.contains Effects.GetCurrentTimeZone
  1413          , describe "top bar" <|
  1414              [ test "has a top bar" <|
  1415                  \_ ->
  1416                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1417                          |> Common.queryView
  1418                          |> Query.has [ id "top-bar-app" ]
  1419              , test "has a concourse icon" <|
  1420                  \_ ->
  1421                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1422                          |> Common.queryView
  1423                          |> Query.find [ id "top-bar-app" ]
  1424                          |> Query.has
  1425                              [ style "background-image" <|
  1426                                  Assets.backgroundImage <|
  1427                                      Just Assets.ConcourseLogoWhite
  1428                              ]
  1429              , test "has the breadcrumbs" <|
  1430                  \_ ->
  1431                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1432                          |> Common.queryView
  1433                          |> Query.find [ id "top-bar-app" ]
  1434                          |> Expect.all
  1435                              [ Query.has [ id "breadcrumb-pipeline" ]
  1436                              , Query.has [ text "p" ]
  1437                              , Query.has [ id "breadcrumb-job" ]
  1438                              , Query.has [ text "j" ]
  1439                              ]
  1440              , test "has the breadcrumbs after fetching build" <|
  1441                  \_ ->
  1442                      Common.init "/builds/1"
  1443                          |> fetchBuild BuildStatusSucceeded
  1444                          |> Tuple.first
  1445                          |> Common.queryView
  1446                          |> Query.find [ id "top-bar-app" ]
  1447                          |> Expect.all
  1448                              [ Query.has [ id "breadcrumb-pipeline" ]
  1449                              , Query.has [ text "p" ]
  1450                              , Query.has [ id "breadcrumb-job" ]
  1451                              , Query.has [ text "j" ]
  1452                              ]
  1453              , test "has a user section" <|
  1454                  \_ ->
  1455                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1456                          |> Common.queryView
  1457                          |> Query.find [ id "top-bar-app" ]
  1458                          |> Query.has [ id "login-component" ]
  1459              ]
  1460          , test "page below top bar has padding to accomodate top bar" <|
  1461              \_ ->
  1462                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1463                      |> Common.queryView
  1464                      |> Query.find [ id "page-below-top-bar" ]
  1465                      |> Query.has [ style "padding-top" "54px" ]
  1466          , test "page below top bar fills vertically without scrolling" <|
  1467              \_ ->
  1468                  Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1469                      |> Common.queryView
  1470                      |> Query.find [ id "page-below-top-bar" ]
  1471                      |> Query.has
  1472                          [ style "height" "100%"
  1473                          , style "box-sizing" "border-box"
  1474                          ]
  1475          , describe "after build is fetched" <|
  1476              let
  1477                  givenBuildFetched _ =
  1478                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1" |> fetchBuild BuildStatusSucceeded
  1479              in
  1480              [ test "has a header after the build is fetched" <|
  1481                  givenBuildFetched
  1482                      >> Tuple.first
  1483                      >> Common.queryView
  1484                      >> Query.has [ id "build-header" ]
  1485              , test "build body scrolls independently of page frame" <|
  1486                  givenBuildFetched
  1487                      >> Tuple.first
  1488                      >> Common.queryView
  1489                      >> Query.find [ id "build-body" ]
  1490                      >> Query.has [ style "overflow-y" "auto" ]
  1491              , test "build body has momentum based scroll enabled" <|
  1492                  givenBuildFetched
  1493                      >> Tuple.first
  1494                      >> Common.queryView
  1495                      >> Query.find [ id "build-body" ]
  1496                      >> Query.has [ style "-webkit-overflow-scrolling" "touch" ]
  1497              , test "fetches build history and job details after build is fetched" <|
  1498                  givenBuildFetched
  1499                      >> Tuple.second
  1500                      >> Expect.all
  1501                          [ Common.contains (Effects.FetchBuildHistory Data.shortJobId Nothing)
  1502                          , Common.contains (Effects.FetchBuildJobDetails Data.shortJobId)
  1503                          ]
  1504              , test "header is 60px tall" <|
  1505                  givenBuildFetched
  1506                      >> Tuple.first
  1507                      >> Common.queryView
  1508                      >> Query.find [ id "build-header" ]
  1509                      >> Query.has [ style "height" "60px" ]
  1510              , test "header lays out horizontally" <|
  1511                  givenBuildFetched
  1512                      >> Tuple.first
  1513                      >> Common.queryView
  1514                      >> Query.find [ id "build-header" ]
  1515                      >> Query.has [ style "display" "flex" ]
  1516              , test "when build finishes, shows finished timestamp" <|
  1517                  \_ ->
  1518                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1519                          |> Application.handleCallback (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1520                          |> Tuple.first
  1521                          |> receiveEvent
  1522                              { url = "http://localhost:8080/api/v1/builds/1/events"
  1523                              , data = STModels.BuildStatus BuildStatusSucceeded (Time.millisToPosix 0)
  1524                              }
  1525                          |> Tuple.first
  1526                          |> Application.update
  1527                              (Msgs.DeliveryReceived <|
  1528                                  ClockTicked
  1529                                      OneSecond
  1530                                      (Time.millisToPosix (2 * 1000))
  1531                              )
  1532                          |> Tuple.first
  1533                          |> Common.queryView
  1534                          |> Query.find [ class "build-duration" ]
  1535                          |> Query.find [ tag "tr", containing [ text "finished" ] ]
  1536                          |> Query.has [ text "2s ago" ]
  1537              , test "when build finishes succesfully, header background is green" <|
  1538                  \_ ->
  1539                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1540                          |> Application.handleCallback (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusStarted))
  1541                          |> Tuple.first
  1542                          |> receiveEvent
  1543                              { url = "http://localhost:8080/api/v1/builds/1/events"
  1544                              , data = STModels.BuildStatus BuildStatusSucceeded (Time.millisToPosix 0)
  1545                              }
  1546                          |> Tuple.first
  1547                          |> Application.update
  1548                              (Msgs.DeliveryReceived <|
  1549                                  ClockTicked
  1550                                      OneSecond
  1551                                      (Time.millisToPosix (2 * 1000))
  1552                              )
  1553                          |> Tuple.first
  1554                          |> Common.queryView
  1555                          |> Query.find [ id "build-header" ]
  1556                          |> Query.has [ style "background-color" Colors.success ]
  1557              , test "when less than 24h old, shows relative time since build" <|
  1558                  \_ ->
  1559                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1560                          |> Application.handleCallback (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusSucceeded))
  1561                          |> Tuple.first
  1562                          |> Application.update
  1563                              (Msgs.DeliveryReceived <|
  1564                                  ClockTicked
  1565                                      OneSecond
  1566                                      (Time.millisToPosix (2 * 1000))
  1567                              )
  1568                          |> Tuple.first
  1569                          |> Common.queryView
  1570                          |> Query.find [ id "build-header" ]
  1571                          |> Query.has [ text "2s ago" ]
  1572              , test "when at least 24h old, shows absolute time of build" <|
  1573                  \_ ->
  1574                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1575                          |> Application.handleCallback
  1576                              (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusSucceeded))
  1577                          |> Tuple.first
  1578                          |> Application.update
  1579                              (Msgs.DeliveryReceived <|
  1580                                  ClockTicked
  1581                                      OneSecond
  1582                                      (Time.millisToPosix (24 * 60 * 60 * 1000))
  1583                              )
  1584                          |> Tuple.first
  1585                          |> Common.queryView
  1586                          |> Query.find [ id "build-header" ]
  1587                          |> Query.has [ text "Jan 1 1970 12:00:00 AM" ]
  1588              , test "when at least 24h old, absolute time is in current zone" <|
  1589                  \_ ->
  1590                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1591                          |> Application.handleCallback
  1592                              (Callback.GotCurrentTimeZone <|
  1593                                  Time.customZone (5 * 60) []
  1594                              )
  1595                          |> Tuple.first
  1596                          |> Application.handleCallback
  1597                              (Callback.BuildFetched <| Ok (Data.jobBuild BuildStatusSucceeded))
  1598                          |> Tuple.first
  1599                          |> Application.update
  1600                              (Msgs.DeliveryReceived <|
  1601                                  ClockTicked
  1602                                      OneSecond
  1603                                      (Time.millisToPosix (24 * 60 * 60 * 1000))
  1604                              )
  1605                          |> Tuple.first
  1606                          |> Common.queryView
  1607                          |> Query.find [ id "build-header" ]
  1608                          |> Query.has [ text "Jan 1 1970 05:00:00 AM" ]
  1609              , describe "build banner coloration"
  1610                  [ test "pending build has grey banner" <|
  1611                      \_ ->
  1612                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1613                              |> fetchBuildWithStatus BuildStatusPending
  1614                              |> Common.queryView
  1615                              |> Query.find [ id "build-header" ]
  1616                              |> Query.has [ style "background" "#9b9b9b" ]
  1617                  , test "started build has yellow banner" <|
  1618                      \_ ->
  1619                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1620                              |> fetchBuildWithStatus BuildStatusStarted
  1621                              |> Common.queryView
  1622                              |> Query.find [ id "build-header" ]
  1623                              |> Query.has [ style "background" "#f1c40f" ]
  1624                  , test "succeeded build has green banner" <|
  1625                      \_ ->
  1626                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1627                              |> fetchBuildWithStatus BuildStatusSucceeded
  1628                              |> Common.queryView
  1629                              |> Query.find [ id "build-header" ]
  1630                              |> Query.has [ style "background" "#11c560" ]
  1631                  , test "failed build has red banner" <|
  1632                      \_ ->
  1633                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1634                              |> fetchBuildWithStatus BuildStatusFailed
  1635                              |> Common.queryView
  1636                              |> Query.find [ id "build-header" ]
  1637                              |> Query.has [ style "background" "#ed4b35" ]
  1638                  , test "errored build has amber banner" <|
  1639                      \_ ->
  1640                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1641                              |> fetchBuildWithStatus BuildStatusErrored
  1642                              |> Common.queryView
  1643                              |> Query.find [ id "build-header" ]
  1644                              |> Query.has [ style "background" "#f5a623" ]
  1645                  , test "aborted build has brown banner" <|
  1646                      \_ ->
  1647                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1648                              |> fetchBuildWithStatus BuildStatusAborted
  1649                              |> Common.queryView
  1650                              |> Query.find [ id "build-header" ]
  1651                              |> Query.has [ style "background" "#8b572a" ]
  1652                  ]
  1653              , describe "build history tab coloration"
  1654                  [ test "pending build has grey tab in build history" <|
  1655                      \_ ->
  1656                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1657                              |> fetchBuildWithStatus BuildStatusPending
  1658                              |> Common.queryView
  1659                              |> Query.find [ id "builds" ]
  1660                              |> Query.find [ tag "li" ]
  1661                              |> Query.has [ style "background" "#9b9b9b" ]
  1662                  , test "started build has animated striped yellow tab in build history" <|
  1663                      \_ ->
  1664                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1665                              |> fetchBuildWithStatus BuildStatusStarted
  1666                              |> Common.queryView
  1667                              |> Query.find [ id "builds" ]
  1668                              |> Query.find [ tag "li" ]
  1669                              |> isColorWithStripes { thick = "#f1c40f", thin = "#fad43b" }
  1670                  , test "succeeded build has green tab in build history" <|
  1671                      \_ ->
  1672                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1673                              |> fetchBuildWithStatus BuildStatusSucceeded
  1674                              |> Common.queryView
  1675                              |> Query.find [ id "builds" ]
  1676                              |> Query.find [ tag "li" ]
  1677                              |> Query.has [ style "background" "#11c560" ]
  1678                  , test "failed build has red tab in build history" <|
  1679                      \_ ->
  1680                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1681                              |> fetchBuildWithStatus BuildStatusFailed
  1682                              |> Common.queryView
  1683                              |> Query.find [ id "builds" ]
  1684                              |> Query.find [ tag "li" ]
  1685                              |> Query.has [ style "background" "#ed4b35" ]
  1686                  , test "errored build has amber tab in build history" <|
  1687                      \_ ->
  1688                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1689                              |> fetchBuildWithStatus BuildStatusErrored
  1690                              |> Common.queryView
  1691                              |> Query.find [ id "builds" ]
  1692                              |> Query.find [ tag "li" ]
  1693                              |> Query.has [ style "background" "#f5a623" ]
  1694                  , test "aborted build has brown tab in build history" <|
  1695                      \_ ->
  1696                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  1697                              |> fetchBuildWithStatus BuildStatusAborted
  1698                              |> Common.queryView
  1699                              |> Query.find [ id "builds" ]
  1700                              |> Query.find [ tag "li" ]
  1701                              |> Query.has [ style "background" "#8b572a" ]
  1702                  ]
  1703              , test "header spreads out contents" <|
  1704                  givenBuildFetched
  1705                      >> Tuple.first
  1706                      >> Common.queryView
  1707                      >> Query.find [ id "build-header" ]
  1708                      >> Query.has [ style "justify-content" "space-between" ]
  1709              , describe "after history and details get fetched" <|
  1710                  let
  1711                      givenHistoryAndDetailsFetched =
  1712                          givenBuildFetched
  1713                              >> Tuple.first
  1714                              >> fetchHistory
  1715                              >> Tuple.first
  1716                              >> fetchJobDetails
  1717                  in
  1718                  [ test "trigger build button on right side of header " <|
  1719                      givenHistoryAndDetailsFetched
  1720                          >> Tuple.first
  1721                          >> Common.queryView
  1722                          >> Query.find [ id "build-header" ]
  1723                          >> Query.children []
  1724                          >> Query.index -1
  1725                          >> Query.has
  1726                              [ attribute <|
  1727                                  Attr.attribute "aria-label" "Trigger Build"
  1728                              ]
  1729                  , test """page contents lay out vertically, filling available
  1730                            space without scrolling horizontally""" <|
  1731                      givenHistoryAndDetailsFetched
  1732                          >> Tuple.first
  1733                          >> Common.queryView
  1734                          >> Query.find [ id "page-below-top-bar" ]
  1735                          >> Query.children []
  1736                          >> Query.index 1
  1737                          >> Query.has
  1738                              [ style "flex-grow" "1"
  1739                              , style "display" "flex"
  1740                              , style "flex-direction" "column"
  1741                              , style "overflow" "hidden"
  1742                              ]
  1743                  , test "pressing 'L' updates the URL" <|
  1744                      givenBuildFetched
  1745                          >> Tuple.first
  1746                          >> Application.handleCallback
  1747                              (Callback.BuildHistoryFetched
  1748                                  (Ok
  1749                                      { pagination =
  1750                                          { previousPage = Nothing
  1751                                          , nextPage =
  1752                                              Just
  1753                                                  { direction = To 1
  1754                                                  , limit = 100
  1755                                                  }
  1756                                          }
  1757                                      , content =
  1758                                          [ Data.jobBuild BuildStatusSucceeded
  1759                                          , { id = 2
  1760                                            , name = "2"
  1761                                            , job = Just Data.shortJobId
  1762                                            , status = BuildStatusSucceeded
  1763                                            , duration =
  1764                                                  { startedAt = Just <| Time.millisToPosix 0
  1765                                                  , finishedAt = Just <| Time.millisToPosix 0
  1766                                                  }
  1767                                            , reapTime = Nothing
  1768                                            }
  1769                                          ]
  1770                                      }
  1771                                  )
  1772                              )
  1773                          >> Tuple.first
  1774                          >> Application.handleDelivery
  1775                              (KeyDown
  1776                                  { ctrlKey = False
  1777                                  , shiftKey = False
  1778                                  , metaKey = False
  1779                                  , code = Keyboard.L
  1780                                  }
  1781                              )
  1782                          >> Tuple.second
  1783                          >> Expect.equal
  1784                              [ Effects.NavigateTo
  1785                                  "/teams/t/pipelines/p/jobs/j/builds/2"
  1786                              ]
  1787                  , test "can use keyboard to switch builds after status change event" <|
  1788                      givenBuildFetched
  1789                          >> Tuple.first
  1790                          >> Application.handleCallback
  1791                              (Callback.BuildHistoryFetched
  1792                                  (Ok
  1793                                      { pagination =
  1794                                          { previousPage = Nothing
  1795                                          , nextPage =
  1796                                              Just
  1797                                                  { direction = To 1
  1798                                                  , limit = 100
  1799                                                  }
  1800                                          }
  1801                                      , content =
  1802                                          [ Data.jobBuild BuildStatusSucceeded
  1803                                          , { id = 2
  1804                                            , name = "2"
  1805                                            , job = Just Data.shortJobId
  1806                                            , status = BuildStatusSucceeded
  1807                                            , duration =
  1808                                                  { startedAt = Just <| Time.millisToPosix 0
  1809                                                  , finishedAt = Just <| Time.millisToPosix 0
  1810                                                  }
  1811                                            , reapTime = Nothing
  1812                                            }
  1813                                          ]
  1814                                      }
  1815                                  )
  1816                              )
  1817                          >> Tuple.first
  1818                          >> Application.handleDelivery
  1819                              (Subscription.EventsReceived <|
  1820                                  Ok
  1821                                      [ { data =
  1822                                              STModels.BuildStatus BuildStatusSucceeded <|
  1823                                                  Time.millisToPosix 0
  1824                                        , url = "http://localhost:8080/api/v1/builds/1/events"
  1825                                        }
  1826                                      ]
  1827                              )
  1828                          >> Tuple.first
  1829                          >> Application.handleDelivery
  1830                              (Subscription.KeyDown
  1831                                  { ctrlKey = False
  1832                                  , shiftKey = False
  1833                                  , metaKey = False
  1834                                  , code = Keyboard.L
  1835                                  }
  1836                              )
  1837                          >> Tuple.second
  1838                          >> Common.contains
  1839                              (Effects.NavigateTo "/teams/t/pipelines/p/jobs/j/builds/2")
  1840                  , test "switching tabs updates the build name" <|
  1841                      givenBuildFetched
  1842                          >> Tuple.first
  1843                          >> Application.handleCallback
  1844                              (Callback.BuildHistoryFetched
  1845                                  (Ok
  1846                                      { pagination =
  1847                                          { previousPage = Nothing
  1848                                          , nextPage =
  1849                                              Just
  1850                                                  { direction = To 1
  1851                                                  , limit = 100
  1852                                                  }
  1853                                          }
  1854                                      , content =
  1855                                          [ Data.jobBuild BuildStatusSucceeded
  1856                                          , { id = 2
  1857                                            , name = "2"
  1858                                            , job = Just Data.shortJobId
  1859                                            , status = BuildStatusSucceeded
  1860                                            , duration =
  1861                                                  { startedAt = Just <| Time.millisToPosix 0
  1862                                                  , finishedAt = Just <| Time.millisToPosix 0
  1863                                                  }
  1864                                            , reapTime = Nothing
  1865                                            }
  1866                                          ]
  1867                                      }
  1868                                  )
  1869                              )
  1870                          >> Tuple.first
  1871                          >> Application.handleDelivery
  1872                              (RouteChanged <|
  1873                                  Routes.Build
  1874                                      { id = Data.jobBuildId |> Data.withBuildName "2"
  1875                                      , highlight = Routes.HighlightNothing
  1876                                      }
  1877                              )
  1878                          >> Tuple.first
  1879                          >> Common.queryView
  1880                          >> Query.has [ text " #2" ]
  1881                  , test "pressing Command-L does nothing" <|
  1882                      givenBuildFetched
  1883                          >> Tuple.first
  1884                          >> Application.handleCallback
  1885                              (Callback.BuildHistoryFetched
  1886                                  (Ok
  1887                                      { pagination =
  1888                                          { previousPage = Nothing
  1889                                          , nextPage =
  1890                                              Just
  1891                                                  { direction = To 1
  1892                                                  , limit = 100
  1893                                                  }
  1894                                          }
  1895                                      , content =
  1896                                          [ Data.jobBuild BuildStatusSucceeded
  1897                                          , { id = 2
  1898                                            , name = "2"
  1899                                            , job = Just Data.shortJobId
  1900                                            , status = BuildStatusSucceeded
  1901                                            , duration =
  1902                                                  { startedAt = Just <| Time.millisToPosix 0
  1903                                                  , finishedAt = Just <| Time.millisToPosix 0
  1904                                                  }
  1905                                            , reapTime = Nothing
  1906                                            }
  1907                                          ]
  1908                                      }
  1909                                  )
  1910                              )
  1911                          >> Tuple.first
  1912                          >> Application.handleDelivery
  1913                              (KeyDown
  1914                                  { ctrlKey = False
  1915                                  , shiftKey = False
  1916                                  , metaKey = True
  1917                                  , code = Keyboard.L
  1918                                  }
  1919                              )
  1920                          >> Tuple.second
  1921                          >> Expect.equal []
  1922                  , test "pressing Control-L does nothing" <|
  1923                      givenBuildFetched
  1924                          >> Tuple.first
  1925                          >> Application.handleCallback
  1926                              (Callback.BuildHistoryFetched
  1927                                  (Ok
  1928                                      { pagination =
  1929                                          { previousPage = Nothing
  1930                                          , nextPage =
  1931                                              Just
  1932                                                  { direction = To 1
  1933                                                  , limit = 100
  1934                                                  }
  1935                                          }
  1936                                      , content =
  1937                                          [ Data.jobBuild BuildStatusSucceeded
  1938                                          , { id = 2
  1939                                            , name = "2"
  1940                                            , job = Just Data.shortJobId
  1941                                            , status = BuildStatusSucceeded
  1942                                            , duration =
  1943                                                  { startedAt = Just <| Time.millisToPosix 0
  1944                                                  , finishedAt = Just <| Time.millisToPosix 0
  1945                                                  }
  1946                                            , reapTime = Nothing
  1947                                            }
  1948                                          ]
  1949                                      }
  1950                                  )
  1951                              )
  1952                          >> Tuple.first
  1953                          >> Application.handleDelivery
  1954                              (KeyDown
  1955                                  { ctrlKey = True
  1956                                  , shiftKey = False
  1957                                  , metaKey = False
  1958                                  , code = Keyboard.L
  1959                                  }
  1960                              )
  1961                          >> Tuple.second
  1962                          >> Expect.equal []
  1963                  , describe "scrolling builds"
  1964                      [ test "checks if last build is visible" <|
  1965                          givenBuildFetched
  1966                              >> Tuple.first
  1967                              >> Application.handleCallback
  1968                                  (Callback.BuildHistoryFetched
  1969                                      (Ok
  1970                                          { pagination =
  1971                                              { previousPage = Nothing
  1972                                              , nextPage =
  1973                                                  Just
  1974                                                      { direction = To 1
  1975                                                      , limit = 100
  1976                                                      }
  1977                                              }
  1978                                          , content = [ Data.jobBuild BuildStatusSucceeded ]
  1979                                          }
  1980                                      )
  1981                                  )
  1982                              >> Tuple.first
  1983                              >> Application.update
  1984                                  (Msgs.Update <|
  1985                                      Message.Message.ScrollBuilds
  1986                                          { deltaX = 0, deltaY = 0, deltaMode = DeltaModePixel }
  1987                                  )
  1988                              >> Tuple.second
  1989                              >> Common.contains (Effects.CheckIsVisible "1")
  1990                      , test "deltaX is negated" <|
  1991                          givenBuildFetched
  1992                              >> Tuple.first
  1993                              >> Application.update
  1994                                  (Msgs.Update <|
  1995                                      Message.Message.ScrollBuilds
  1996                                          { deltaX = 5, deltaY = 0, deltaMode = DeltaModePixel }
  1997                                  )
  1998                              >> Tuple.second
  1999                              >> Common.contains (Effects.Scroll (ScrollDirection.Sideways -5) "builds")
  2000                      , test "deltaY is not negated" <|
  2001                          givenBuildFetched
  2002                              >> Tuple.first
  2003                              >> Application.update
  2004                                  (Msgs.Update <|
  2005                                      Message.Message.ScrollBuilds
  2006                                          { deltaX = 0, deltaY = 5, deltaMode = DeltaModePixel }
  2007                                  )
  2008                              >> Tuple.second
  2009                              >> Common.contains (Effects.Scroll (ScrollDirection.Sideways 5) "builds")
  2010                      , test "deltaX is preferred" <|
  2011                          givenBuildFetched
  2012                              >> Tuple.first
  2013                              >> Application.update
  2014                                  (Msgs.Update <|
  2015                                      Message.Message.ScrollBuilds
  2016                                          { deltaX = 5, deltaY = 4, deltaMode = DeltaModePixel }
  2017                                  )
  2018                              >> Tuple.second
  2019                              >> Common.contains (Effects.Scroll (ScrollDirection.Sideways -5) "builds")
  2020                      , test "DeltaModeLine" <|
  2021                          givenBuildFetched
  2022                              >> Tuple.first
  2023                              >> Application.update
  2024                                  (Msgs.Update <|
  2025                                      Message.Message.ScrollBuilds
  2026                                          { deltaX = 5, deltaY = 0, deltaMode = DeltaModeLine }
  2027                                  )
  2028                              >> Tuple.second
  2029                              >> Common.contains (Effects.Scroll (ScrollDirection.Sideways -100) "builds")
  2030                      , test "DeltaModePage" <|
  2031                          givenBuildFetched
  2032                              >> Tuple.first
  2033                              >> Application.update
  2034                                  (Msgs.Update <|
  2035                                      Message.Message.ScrollBuilds
  2036                                          { deltaX = 5, deltaY = 0, deltaMode = DeltaModePage }
  2037                                  )
  2038                              >> Tuple.second
  2039                              >> Common.contains (Effects.Scroll (ScrollDirection.Sideways -4000) "builds")
  2040                      ]
  2041                  , test "subscribes to element visibility" <|
  2042                      givenBuildFetched
  2043                          >> Tuple.first
  2044                          >> Application.subscriptions
  2045                          >> Common.contains Subscription.OnElementVisible
  2046                  , test "scrolling to last build fetches more if possible" <|
  2047                      givenBuildFetched
  2048                          >> Tuple.first
  2049                          >> Application.handleCallback
  2050                              (Callback.BuildHistoryFetched
  2051                                  (Ok
  2052                                      { pagination =
  2053                                          { previousPage = Nothing
  2054                                          , nextPage =
  2055                                              Just
  2056                                                  { direction = To 1
  2057                                                  , limit = 100
  2058                                                  }
  2059                                          }
  2060                                      , content = [ Data.jobBuild BuildStatusSucceeded ]
  2061                                      }
  2062                                  )
  2063                              )
  2064                          >> Tuple.first
  2065                          >> Application.handleDelivery
  2066                              (Subscription.ElementVisible ( "1", True ))
  2067                          >> Tuple.second
  2068                          >> Expect.equal
  2069                              [ Effects.FetchBuildHistory Data.shortJobId
  2070                                  (Just { direction = To 1, limit = 100 })
  2071                              ]
  2072                  , test "scrolling to last build while fetching fetches no more" <|
  2073                      givenBuildFetched
  2074                          >> Tuple.first
  2075                          >> Application.handleCallback
  2076                              (Callback.BuildHistoryFetched
  2077                                  (Ok
  2078                                      { pagination =
  2079                                          { previousPage = Nothing
  2080                                          , nextPage =
  2081                                              Just
  2082                                                  { direction = To 1
  2083                                                  , limit = 100
  2084                                                  }
  2085                                          }
  2086                                      , content = [ Data.jobBuild BuildStatusSucceeded ]
  2087                                      }
  2088                                  )
  2089                              )
  2090                          >> Tuple.first
  2091                          >> Application.handleDelivery
  2092                              (Subscription.ElementVisible ( "1", True ))
  2093                          >> Tuple.first
  2094                          >> Application.handleDelivery
  2095                              (Subscription.ElementVisible ( "1", True ))
  2096                          >> Tuple.second
  2097                          >> Expect.equal []
  2098                  , test "scrolling to absolute last build fetches no more" <|
  2099                      givenHistoryAndDetailsFetched
  2100                          >> Tuple.first
  2101                          >> Application.handleDelivery
  2102                              (Subscription.ElementVisible ( "1", True ))
  2103                          >> Tuple.second
  2104                          >> Expect.equal []
  2105                  , test "if build is present in history, fetches no more" <|
  2106                      givenBuildFetched
  2107                          >> Tuple.first
  2108                          >> Application.handleCallback
  2109                              (Callback.BuildHistoryFetched
  2110                                  (Ok
  2111                                      { pagination =
  2112                                          { previousPage = Nothing
  2113                                          , nextPage =
  2114                                              Just
  2115                                                  { direction = To 1
  2116                                                  , limit = 100
  2117                                                  }
  2118                                          }
  2119                                      , content = [ Data.jobBuild BuildStatusSucceeded ]
  2120                                      }
  2121                                  )
  2122                              )
  2123                          >> Tuple.first
  2124                          >> Application.handleCallback
  2125                              (Callback.BuildHistoryFetched
  2126                                  (Ok
  2127                                      { pagination =
  2128                                          { previousPage = Nothing
  2129                                          , nextPage =
  2130                                              Just
  2131                                                  { direction = To 2
  2132                                                  , limit = 100
  2133                                                  }
  2134                                          }
  2135                                      , content =
  2136                                          [ { id = 2
  2137                                            , name = "2"
  2138                                            , job = Just Data.shortJobId
  2139                                            , status = BuildStatusSucceeded
  2140                                            , duration =
  2141                                                  { startedAt = Nothing
  2142                                                  , finishedAt = Nothing
  2143                                                  }
  2144                                            , reapTime = Nothing
  2145                                            }
  2146                                          ]
  2147                                      }
  2148                                  )
  2149                              )
  2150                          >> Tuple.second
  2151                          >> Common.notContains
  2152                              (Effects.FetchBuildHistory Data.shortJobId
  2153                                  (Just { direction = To 2, limit = 100 })
  2154                              )
  2155                  , test "if build is present in history, checks its visibility" <|
  2156                      givenBuildFetched
  2157                          >> Tuple.first
  2158                          >> Application.handleCallback
  2159                              (Callback.BuildHistoryFetched
  2160                                  (Ok
  2161                                      { pagination =
  2162                                          { previousPage = Nothing
  2163                                          , nextPage =
  2164                                              Just
  2165                                                  { direction = To 1
  2166                                                  , limit = 100
  2167                                                  }
  2168                                          }
  2169                                      , content = [ Data.jobBuild BuildStatusSucceeded ]
  2170                                      }
  2171                                  )
  2172                              )
  2173                          >> Tuple.second
  2174                          >> Common.contains (Effects.CheckIsVisible "1")
  2175                  , test "if build is present and invisible, scrolls to it" <|
  2176                      givenBuildFetched
  2177                          >> Tuple.first
  2178                          >> Application.handleCallback
  2179                              (Callback.BuildHistoryFetched
  2180                                  (Ok
  2181                                      { pagination =
  2182                                          { previousPage = Nothing
  2183                                          , nextPage =
  2184                                              Just
  2185                                                  { direction = To 1
  2186                                                  , limit = 100
  2187                                                  }
  2188                                          }
  2189                                      , content = [ Data.jobBuild BuildStatusSucceeded ]
  2190                                      }
  2191                                  )
  2192                              )
  2193                          >> Tuple.first
  2194                          >> Application.handleDelivery
  2195                              (Subscription.ElementVisible ( "1", False ))
  2196                          >> Tuple.second
  2197                          >> Expect.equal [ Effects.Scroll (ScrollDirection.ToId "1") "builds" ]
  2198                  , test "does not scroll to current build more than once" <|
  2199                      givenBuildFetched
  2200                          >> Tuple.first
  2201                          >> Application.handleCallback
  2202                              (Callback.BuildHistoryFetched
  2203                                  (Ok
  2204                                      { pagination =
  2205                                          { previousPage = Nothing
  2206                                          , nextPage =
  2207                                              Just
  2208                                                  { direction = To 1
  2209                                                  , limit = 100
  2210                                                  }
  2211                                          }
  2212                                      , content = [ Data.jobBuild BuildStatusSucceeded ]
  2213                                      }
  2214                                  )
  2215                              )
  2216                          >> Tuple.first
  2217                          >> Application.handleDelivery
  2218                              (Subscription.ElementVisible ( "1", False ))
  2219                          >> Tuple.first
  2220                          >> Application.handleDelivery
  2221                              (Subscription.ElementVisible ( "1", False ))
  2222                          >> Tuple.second
  2223                          >> Expect.equal []
  2224                  , test "if build is not present in history, fetches more" <|
  2225                      givenBuildFetched
  2226                          >> Tuple.first
  2227                          >> Application.handleCallback
  2228                              (Callback.BuildHistoryFetched
  2229                                  (Ok
  2230                                      { pagination =
  2231                                          { previousPage = Nothing
  2232                                          , nextPage =
  2233                                              Just
  2234                                                  { direction = To 2
  2235                                                  , limit = 100
  2236                                                  }
  2237                                          }
  2238                                      , content =
  2239                                          [ { id = 2
  2240                                            , name = "2"
  2241                                            , job = Just Data.shortJobId
  2242                                            , status = BuildStatusSucceeded
  2243                                            , duration =
  2244                                                  { startedAt = Nothing
  2245                                                  , finishedAt = Nothing
  2246                                                  }
  2247                                            , reapTime = Nothing
  2248                                            }
  2249                                          ]
  2250                                      }
  2251                                  )
  2252                              )
  2253                          >> Tuple.second
  2254                          >> Expect.equal
  2255                              [ Effects.FetchBuildHistory Data.shortJobId
  2256                                  (Just { direction = To 2, limit = 100 })
  2257                              ]
  2258                  , test "trigger build button is styled as a box of the color of the build status" <|
  2259                      givenHistoryAndDetailsFetched
  2260                          >> Tuple.first
  2261                          >> Common.queryView
  2262                          >> Query.find
  2263                              [ attribute <|
  2264                                  Attr.attribute "aria-label" "Trigger Build"
  2265                              ]
  2266                          >> Query.has
  2267                              [ style "padding" "10px"
  2268                              , style "background-color" brightGreen
  2269                              , style "outline" "none"
  2270                              , style "margin" "0"
  2271                              , style "border-width" "0 0 0 1px"
  2272                              , style "border-color" darkGreen
  2273                              , style "border-style" "solid"
  2274                              ]
  2275                  , test "hovered trigger build button is styled as a box of the secondary color of the build status" <|
  2276                      givenHistoryAndDetailsFetched
  2277                          >> Tuple.first
  2278                          >> Application.update
  2279                              (Msgs.Update <|
  2280                                  Message.Message.Hover <|
  2281                                      Just Message.Message.TriggerBuildButton
  2282                              )
  2283                          >> Tuple.first
  2284                          >> Common.queryView
  2285                          >> Query.find
  2286                              [ attribute <|
  2287                                  Attr.attribute "aria-label" "Trigger Build"
  2288                              ]
  2289                          >> Query.has
  2290                              [ style "padding" "10px"
  2291                              , style "background-color" darkGreen
  2292                              , style "outline" "none"
  2293                              , style "margin" "0"
  2294                              , style "border-width" "0 0 0 1px"
  2295                              , style "border-color" darkGreen
  2296                              , style "border-style" "solid"
  2297                              ]
  2298                  , test "trigger build button has pointer cursor" <|
  2299                      givenHistoryAndDetailsFetched
  2300                          >> Tuple.first
  2301                          >> Common.queryView
  2302                          >> Query.find
  2303                              [ attribute <|
  2304                                  Attr.attribute "aria-label" "Trigger Build"
  2305                              ]
  2306                          >> Query.has [ style "cursor" "pointer" ]
  2307                  , test "trigger build button has 'plus' icon" <|
  2308                      givenHistoryAndDetailsFetched
  2309                          >> Tuple.first
  2310                          >> Common.queryView
  2311                          >> Query.find
  2312                              [ attribute <|
  2313                                  Attr.attribute "aria-label" "Trigger Build"
  2314                              ]
  2315                          >> Query.children []
  2316                          >> Query.first
  2317                          >> Query.has
  2318                              (iconSelector
  2319                                  { size = "40px"
  2320                                  , image = Assets.AddCircleIcon |> Assets.CircleOutlineIcon
  2321                                  }
  2322                              )
  2323                  ]
  2324              , describe "when history and details fetched with manual triggering disabled" <|
  2325                  let
  2326                      givenHistoryAndDetailsFetched =
  2327                          givenBuildFetched
  2328                              >> Tuple.first
  2329                              >> fetchHistory
  2330                              >> Tuple.first
  2331                              >> fetchJobDetailsNoTrigger
  2332                  in
  2333                  [ test "when manual triggering is disabled, trigger build button has default cursor" <|
  2334                      givenHistoryAndDetailsFetched
  2335                          >> Tuple.first
  2336                          >> Common.queryView
  2337                          >> Query.find
  2338                              [ attribute <|
  2339                                  Attr.attribute "aria-label" "Trigger Build"
  2340                              ]
  2341                          >> Query.has [ style "cursor" "default" ]
  2342                  , defineHoverBehaviour
  2343                      { name = "disabled trigger build button"
  2344                      , setup =
  2345                          givenHistoryAndDetailsFetched () |> Tuple.first
  2346                      , query =
  2347                          Common.queryView
  2348                              >> Query.find
  2349                                  [ attribute <|
  2350                                      Attr.attribute "aria-label" "Trigger Build"
  2351                                  ]
  2352                      , unhoveredSelector =
  2353                          { description = "grey plus icon"
  2354                          , selector =
  2355                              iconSelector
  2356                                  { size = "40px"
  2357                                  , image = Assets.AddCircleIcon |> Assets.CircleOutlineIcon
  2358                                  }
  2359                          }
  2360                      , hoveredSelector =
  2361                          { description = "grey plus icon with tooltip"
  2362                          , selector =
  2363                              [ style "position" "relative"
  2364                              , containing
  2365                                  [ containing
  2366                                      [ text "manual triggering disabled in job config" ]
  2367                                  ]
  2368                              , containing <|
  2369                                  iconSelector
  2370                                      { size = "40px"
  2371                                      , image = Assets.AddCircleIcon |> Assets.CircleOutlineIcon
  2372                                      }
  2373                              ]
  2374                          }
  2375                      , hoverable = Message.Message.TriggerBuildButton
  2376                      }
  2377                  ]
  2378              ]
  2379          , describe "given build started and history and details fetched" <|
  2380              let
  2381                  givenBuildStarted _ =
  2382                      Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  2383                          |> fetchBuildWithStatus BuildStatusStarted
  2384                          |> fetchHistory
  2385                          |> Tuple.first
  2386                          |> fetchJobDetails
  2387              in
  2388              [ test "build action section lays out horizontally" <|
  2389                  givenBuildStarted
  2390                      >> Tuple.first
  2391                      >> Common.queryView
  2392                      >> Query.find [ id "build-header" ]
  2393                      >> Query.children []
  2394                      >> Query.index -1
  2395                      >> Query.has [ style "display" "flex" ]
  2396              , test "abort build button is to the left of the trigger button" <|
  2397                  givenBuildStarted
  2398                      >> Tuple.first
  2399                      >> Common.queryView
  2400                      >> Query.find [ id "build-header" ]
  2401                      >> Query.children []
  2402                      >> Query.index -1
  2403                      >> Query.children []
  2404                      >> Query.first
  2405                      >> Query.has
  2406                          [ attribute <|
  2407                              Attr.attribute "aria-label" "Abort Build"
  2408                          ]
  2409              , test "abort build button is styled as a bright red box" <|
  2410                  givenBuildStarted
  2411                      >> Tuple.first
  2412                      >> Common.queryView
  2413                      >> Query.find
  2414                          [ attribute <|
  2415                              Attr.attribute "aria-label" "Abort Build"
  2416                          ]
  2417                      >> Query.has
  2418                          [ style "padding" "10px"
  2419                          , style "background-color" brightRed
  2420                          , style "outline" "none"
  2421                          , style "margin" "0"
  2422                          , style "border-width" "0 0 0 1px"
  2423                          , style "border-color" darkRed
  2424                          , style "border-style" "solid"
  2425                          ]
  2426              , test "hovered abort build button is styled as a dark red box" <|
  2427                  givenBuildStarted
  2428                      >> Tuple.first
  2429                      >> Application.update
  2430                          (Msgs.Update <|
  2431                              Message.Message.Hover <|
  2432                                  Just Message.Message.AbortBuildButton
  2433                          )
  2434                      >> Tuple.first
  2435                      >> Common.queryView
  2436                      >> Query.find
  2437                          [ attribute <|
  2438                              Attr.attribute "aria-label" "Abort Build"
  2439                          ]
  2440                      >> Query.has
  2441                          [ style "padding" "10px"
  2442                          , style "background-color" darkRed
  2443                          , style "outline" "none"
  2444                          , style "margin" "0"
  2445                          , style "border-width" "0 0 0 1px"
  2446                          , style "border-color" darkRed
  2447                          , style "border-style" "solid"
  2448                          ]
  2449              , test "abort build button has pointer cursor" <|
  2450                  givenBuildStarted
  2451                      >> Tuple.first
  2452                      >> Common.queryView
  2453                      >> Query.find
  2454                          [ attribute <|
  2455                              Attr.attribute "aria-label" "Abort Build"
  2456                          ]
  2457                      >> Query.has [ style "cursor" "pointer" ]
  2458              , test "abort build button has 'X' icon" <|
  2459                  givenBuildStarted
  2460                      >> Tuple.first
  2461                      >> Common.queryView
  2462                      >> Query.find
  2463                          [ attribute <|
  2464                              Attr.attribute "aria-label" "Abort Build"
  2465                          ]
  2466                      >> Query.children []
  2467                      >> Query.first
  2468                      >> Query.has
  2469                          (iconSelector
  2470                              { size = "40px"
  2471                              , image = Assets.AbortCircleIcon |> Assets.CircleOutlineIcon
  2472                              }
  2473                          )
  2474              , describe "build prep section"
  2475                  [ test "when pipeline is not paused, shows a check" <|
  2476                      let
  2477                          prep =
  2478                              { pausedPipeline = BuildPrepStatusNotBlocking
  2479                              , pausedJob = BuildPrepStatusNotBlocking
  2480                              , maxRunningBuilds = BuildPrepStatusNotBlocking
  2481                              , inputs = Dict.empty
  2482                              , inputsSatisfied = BuildPrepStatusNotBlocking
  2483                              , missingInputReasons = Dict.empty
  2484                              }
  2485  
  2486                          icon =
  2487                              Assets.backgroundImage <| Just Assets.NotBlockingCheckIcon
  2488                      in
  2489                      givenBuildStarted
  2490                          >> Tuple.first
  2491                          >> Application.handleCallback
  2492                              (Callback.BuildPrepFetched 1 <| Ok prep)
  2493                          >> Tuple.first
  2494                          >> Common.queryView
  2495                          >> Query.find [ class "prep-status-list" ]
  2496                          >> Expect.all
  2497                              [ Query.children []
  2498                                  >> Query.each
  2499                                      (Query.children []
  2500                                          >> Query.first
  2501                                          >> Query.has
  2502                                              [ style "display" "flex"
  2503                                              , style "align-items" "center"
  2504                                              ]
  2505                                      )
  2506                              , Query.has
  2507                                  [ style "background-image" icon
  2508                                  , style "background-position" "50% 50%"
  2509                                  , style "background-repeat" "no-repeat"
  2510                                  , style "background-size" "contain"
  2511                                  , style "width" "12px"
  2512                                  , style "height" "12px"
  2513                                  , style "margin-right" "8px"
  2514                                  , attribute <| Attr.title "not blocking"
  2515                                  ]
  2516                              ]
  2517                  , test "when pipeline is paused, shows a spinner" <|
  2518                      let
  2519                          prep =
  2520                              { pausedPipeline = BuildPrepStatusBlocking
  2521                              , pausedJob = BuildPrepStatusNotBlocking
  2522                              , maxRunningBuilds = BuildPrepStatusNotBlocking
  2523                              , inputs = Dict.empty
  2524                              , inputsSatisfied = BuildPrepStatusNotBlocking
  2525                              , missingInputReasons = Dict.empty
  2526                              }
  2527                      in
  2528                      givenBuildStarted
  2529                          >> Tuple.first
  2530                          >> Application.handleCallback
  2531                              (Callback.BuildPrepFetched 1 <| Ok prep)
  2532                          >> Tuple.first
  2533                          >> Common.queryView
  2534                          >> Query.find [ class "prep-status-list" ]
  2535                          >> Expect.all
  2536                              [ Query.children []
  2537                                  >> Query.each
  2538                                      (Query.children []
  2539                                          >> Query.first
  2540                                          >> Query.has
  2541                                              [ style "display" "flex"
  2542                                              , style "align-items" "center"
  2543                                              ]
  2544                                      )
  2545                              , Query.has
  2546                                  [ style "animation"
  2547                                      "container-rotate 1568ms linear infinite"
  2548                                  , style "height" "12px"
  2549                                  , style "width" "12px"
  2550                                  , style "margin" "0 8px 0 0"
  2551                                  ]
  2552                              , Query.has [ attribute <| Attr.title "blocking" ]
  2553                              ]
  2554                  , test "when paused state is unknown, shows a spinner" <|
  2555                      let
  2556                          prep =
  2557                              { pausedPipeline = BuildPrepStatusUnknown
  2558                              , pausedJob = BuildPrepStatusNotBlocking
  2559                              , maxRunningBuilds = BuildPrepStatusNotBlocking
  2560                              , inputs = Dict.empty
  2561                              , inputsSatisfied = BuildPrepStatusNotBlocking
  2562                              , missingInputReasons = Dict.empty
  2563                              }
  2564                      in
  2565                      givenBuildStarted
  2566                          >> Tuple.first
  2567                          >> Application.handleCallback
  2568                              (Callback.BuildPrepFetched 1 <| Ok prep)
  2569                          >> Tuple.first
  2570                          >> Common.queryView
  2571                          >> Query.find [ class "prep-status-list" ]
  2572                          >> Expect.all
  2573                              [ Query.children []
  2574                                  >> Query.each
  2575                                      (Query.children []
  2576                                          >> Query.first
  2577                                          >> Query.has
  2578                                              [ style "display" "flex"
  2579                                              , style "align-items" "center"
  2580                                              ]
  2581                                      )
  2582                              , Query.has
  2583                                  [ style "animation"
  2584                                      "container-rotate 1568ms linear infinite"
  2585                                  , style "height" "12px"
  2586                                  , style "width" "12px"
  2587                                  , style "margin" "0 8px 0 0"
  2588                                  ]
  2589                              , Query.has [ attribute <| Attr.title "thinking..." ]
  2590                              ]
  2591                  ]
  2592              , describe "build events subscription" <|
  2593                  let
  2594                      preBuildPlanReceived _ =
  2595                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  2596                              |> fetchBuild BuildStatusStarted
  2597                              |> Tuple.first
  2598                              |> fetchHistory
  2599                              |> Tuple.first
  2600                              |> fetchJobDetails
  2601                              |> Tuple.first
  2602                  in
  2603                  [ test "after build plan is received, opens event stream" <|
  2604                      preBuildPlanReceived
  2605                          >> Application.handleCallback
  2606                              (Callback.PlanAndResourcesFetched 1 <|
  2607                                  Ok <|
  2608                                      ( { id = "plan"
  2609                                        , step =
  2610                                              Concourse.BuildStepGet
  2611                                                  "step"
  2612                                                  Nothing
  2613                                        }
  2614                                      , { inputs = [], outputs = [] }
  2615                                      )
  2616                              )
  2617                          >> Expect.all
  2618                              [ Tuple.second
  2619                                  >> Common.contains
  2620                                      (Effects.OpenBuildEventStream
  2621                                          { url = "/api/v1/builds/1/events"
  2622                                          , eventTypes = [ "end", "event" ]
  2623                                          }
  2624                                      )
  2625                              , Tuple.first
  2626                                  >> Application.subscriptions
  2627                                  >> Common.contains
  2628                                      (Subscription.FromEventSource
  2629                                          ( "/api/v1/builds/1/events"
  2630                                          , [ "end", "event" ]
  2631                                          )
  2632                                      )
  2633                              ]
  2634                  , test "if build plan request fails, no event stream" <|
  2635                      preBuildPlanReceived
  2636                          >> Application.handleCallback
  2637                              (Callback.PlanAndResourcesFetched 1 <| Data.httpUnauthorized)
  2638                          >> Expect.all
  2639                              [ Tuple.second >> Expect.equal []
  2640                              , Tuple.first
  2641                                  >> Application.subscriptions
  2642                                  >> Common.notContains
  2643                                      (Subscription.FromEventSource
  2644                                          ( "/api/v1/builds/1/events"
  2645                                          , [ "end", "event" ]
  2646                                          )
  2647                                      )
  2648                              ]
  2649                  ]
  2650              , describe "sync sticky build log headers" <|
  2651                  let
  2652                      setup _ =
  2653                          Common.init "/teams/t/pipelines/p/jobs/j/builds/1"
  2654                              |> fetchBuild BuildStatusStarted
  2655                              |> Tuple.first
  2656                              |> fetchHistory
  2657                              |> Tuple.first
  2658                              |> fetchJobDetails
  2659                              |> Tuple.first
  2660                  in
  2661                  [ test "on plan received" <|
  2662                      setup
  2663                          >> Application.handleCallback
  2664                              (Callback.PlanAndResourcesFetched 1 <|
  2665                                  Ok <|
  2666                                      ( { id = "plan"
  2667                                        , step =
  2668                                              Concourse.BuildStepGet
  2669                                                  "step"
  2670                                                  Nothing
  2671                                        }
  2672                                      , { inputs = [], outputs = [] }
  2673                                      )
  2674                              )
  2675                          >> Tuple.second
  2676                          >> Common.contains Effects.SyncStickyBuildLogHeaders
  2677                  , test "on header clicked" <|
  2678                      setup
  2679                          >> Application.update
  2680                              (Msgs.Update <|
  2681                                  Message.Message.Click <|
  2682                                      Message.Message.StepHeader "plan"
  2683                              )
  2684                          >> Tuple.second
  2685                          >> Common.contains Effects.SyncStickyBuildLogHeaders
  2686                  , test "on sub header clicked" <|
  2687                      setup
  2688                          >> Application.update
  2689                              (Msgs.Update <|
  2690                                  Message.Message.Click <|
  2691                                      Message.Message.StepSubHeader "plan" 0
  2692                              )
  2693                          >> Tuple.second
  2694                          >> Common.contains Effects.SyncStickyBuildLogHeaders
  2695                  , test "on window resized" <|
  2696                      setup
  2697                          >> Application.handleDelivery (WindowResized 1 2)
  2698                          >> Tuple.second
  2699                          >> Common.contains Effects.SyncStickyBuildLogHeaders
  2700                  ]
  2701              , describe "step header" <|
  2702                  let
  2703                      fetchPlanWithGetStep : () -> Application.Model
  2704                      fetchPlanWithGetStep =
  2705                          givenBuildStarted
  2706                              >> Tuple.first
  2707                              >> Application.handleCallback
  2708                                  (Callback.PlanAndResourcesFetched 1 <|
  2709                                      Ok <|
  2710                                          ( { id = "plan"
  2711                                            , step =
  2712                                                  Concourse.BuildStepGet
  2713                                                      "step"
  2714                                                      Nothing
  2715                                            }
  2716                                          , { inputs = [], outputs = [] }
  2717                                          )
  2718                                  )
  2719                              >> Tuple.first
  2720  
  2721                      fetchPlanWithArtifactInputStep : () -> Application.Model
  2722                      fetchPlanWithArtifactInputStep =
  2723                          givenBuildStarted
  2724                              >> Tuple.first
  2725                              >> Application.handleCallback
  2726                                  (Callback.PlanAndResourcesFetched 1 <|
  2727                                      Ok <|
  2728                                          ( { id = "plan"
  2729                                            , step =
  2730                                                  Concourse.BuildStepArtifactInput
  2731                                                      "step"
  2732                                            }
  2733                                          , { inputs = [], outputs = [] }
  2734                                          )
  2735                                  )
  2736                              >> Tuple.first
  2737  
  2738                      fetchPlanWithEnsureArtifactOutputStep : () -> Application.Model
  2739                      fetchPlanWithEnsureArtifactOutputStep =
  2740                          givenBuildStarted
  2741                              >> Tuple.first
  2742                              >> Application.handleCallback
  2743                                  (Callback.PlanAndResourcesFetched 1 <|
  2744                                      Ok <|
  2745                                          ( { id = "plan"
  2746                                            , step =
  2747                                                  Concourse.BuildStepEnsure
  2748                                                      { hook =
  2749                                                          { id = "plan1"
  2750                                                          , step =
  2751                                                              Concourse.BuildStepArtifactOutput
  2752                                                                  "step"
  2753                                                          }
  2754                                                      , step =
  2755                                                          { id = "plan2"
  2756                                                          , step =
  2757                                                              Concourse.BuildStepGet
  2758                                                                  "step"
  2759                                                                  Nothing
  2760                                                          }
  2761                                                      }
  2762                                            }
  2763                                          , { inputs = [], outputs = [] }
  2764                                          )
  2765                                  )
  2766                              >> Tuple.first
  2767  
  2768                      fetchPlanWithTaskStep : () -> Application.Model
  2769                      fetchPlanWithTaskStep =
  2770                          givenBuildStarted
  2771                              >> Tuple.first
  2772                              >> Application.handleCallback
  2773                                  (Callback.PlanAndResourcesFetched 1 <|
  2774                                      Ok <|
  2775                                          ( { id = "plan"
  2776                                            , step =
  2777                                                  Concourse.BuildStepTask
  2778                                                      "step"
  2779                                            }
  2780                                          , { inputs = [], outputs = [] }
  2781                                          )
  2782                                  )
  2783                              >> Tuple.first
  2784  
  2785                      fetchPlanWithCheckStep : () -> Application.Model
  2786                      fetchPlanWithCheckStep =
  2787                          givenBuildStarted
  2788                              >> Tuple.first
  2789                              >> Application.handleCallback
  2790                                  (Callback.PlanAndResourcesFetched 307 <|
  2791                                      Ok <|
  2792                                          ( { id = "plan"
  2793                                            , step =
  2794                                                  Concourse.BuildStepCheck
  2795                                                      "step"
  2796                                            }
  2797                                          , { inputs = [], outputs = [] }
  2798                                          )
  2799                                  )
  2800                              >> Tuple.first
  2801  
  2802                      fetchPlanWithSetPipelineStep : () -> Application.Model
  2803                      fetchPlanWithSetPipelineStep =
  2804                          givenBuildStarted
  2805                              >> Tuple.first
  2806                              >> Application.handleCallback
  2807                                  (Callback.PlanAndResourcesFetched 1 <|
  2808                                      Ok <|
  2809                                          ( { id = "plan"
  2810                                            , step =
  2811                                                  Concourse.BuildStepSetPipeline
  2812                                                      "step"
  2813                                            }
  2814                                          , { inputs = [], outputs = [] }
  2815                                          )
  2816                                  )
  2817                              >> Tuple.first
  2818  
  2819                      fetchPlanWithLoadVarStep : () -> Application.Model
  2820                      fetchPlanWithLoadVarStep =
  2821                          givenBuildStarted
  2822                              >> Tuple.first
  2823                              >> Application.handleCallback
  2824                                  (Callback.PlanAndResourcesFetched 307 <|
  2825                                      Ok <|
  2826                                          ( { id = "plan"
  2827                                            , step =
  2828                                                  Concourse.BuildStepLoadVar
  2829                                                      "step"
  2830                                            }
  2831                                          , { inputs = [], outputs = [] }
  2832                                          )
  2833                                  )
  2834                              >> Tuple.first
  2835  
  2836                      fetchPlanWithPutStep : () -> Application.Model
  2837                      fetchPlanWithPutStep =
  2838                          givenBuildStarted
  2839                              >> Tuple.first
  2840                              >> Application.handleCallback
  2841                                  (Callback.PlanAndResourcesFetched 1 <|
  2842                                      Ok <|
  2843                                          ( { id = "plan"
  2844                                            , step =
  2845                                                  Concourse.BuildStepPut
  2846                                                      "step"
  2847                                            }
  2848                                          , { inputs = [], outputs = [] }
  2849                                          )
  2850                                  )
  2851                              >> Tuple.first
  2852  
  2853                      fetchPlanWithGetStepWithFirstOccurrence :
  2854                          ()
  2855                          -> Application.Model
  2856                      fetchPlanWithGetStepWithFirstOccurrence =
  2857                          let
  2858                              version =
  2859                                  Dict.fromList
  2860                                      [ ( "ref", "abc123" ) ]
  2861  
  2862                              step =
  2863                                  Concourse.BuildStepDo <|
  2864                                      Array.fromList
  2865                                          [ { id = "foo"
  2866                                            , step =
  2867                                                  Concourse.BuildStepGet "step"
  2868                                                      (Just version)
  2869                                            }
  2870                                          , { id = "bar"
  2871                                            , step =
  2872                                                  Concourse.BuildStepGet "step2"
  2873                                                      (Just version)
  2874                                            }
  2875                                          , { id = "baz"
  2876                                            , step =
  2877                                                  Concourse.BuildStepGet "step3"
  2878                                                      (Just version)
  2879                                            }
  2880                                          ]
  2881                          in
  2882                          givenBuildStarted
  2883                              >> Tuple.first
  2884                              >> Application.handleCallback
  2885                                  (Callback.PlanAndResourcesFetched 1 <|
  2886                                      Ok <|
  2887                                          ( { id = "plan", step = step }
  2888                                          , { inputs =
  2889                                                  [ { name = "step"
  2890                                                    , version = version
  2891                                                    , firstOccurrence = True
  2892                                                    }
  2893                                                  , { name = "step2"
  2894                                                    , version = version
  2895                                                    , firstOccurrence = True
  2896                                                    }
  2897                                                  , { name = "step3"
  2898                                                    , version = version
  2899                                                    , firstOccurrence = False
  2900                                                    }
  2901                                                  ]
  2902                                            , outputs = []
  2903                                            }
  2904                                          )
  2905                                  )
  2906                              >> Tuple.first
  2907                  in
  2908                  [ test "step is collapsed by default" <|
  2909                      fetchPlanWithGetStep
  2910                          >> Application.handleDelivery
  2911                              (EventsReceived <|
  2912                                  Ok <|
  2913                                      [ { url =
  2914                                              eventsUrl
  2915                                        , data =
  2916                                              STModels.InitializeGet
  2917                                                  { source = ""
  2918                                                  , id = "plan"
  2919                                                  }
  2920                                                  (Time.millisToPosix 0)
  2921                                        }
  2922                                      ]
  2923                              )
  2924                          >> Tuple.first
  2925                          >> Common.queryView
  2926                          >> Query.hasNot [ class "step-body" ]
  2927                  , test "step expands on click" <|
  2928                      fetchPlanWithGetStep
  2929                          >> Application.handleDelivery
  2930                              (EventsReceived <|
  2931                                  Ok <|
  2932                                      [ { url =
  2933                                              eventsUrl
  2934                                        , data =
  2935                                              STModels.InitializeGet
  2936                                                  { source = ""
  2937                                                  , id = "plan"
  2938                                                  }
  2939                                                  (Time.millisToPosix 0)
  2940                                        }
  2941                                      ]
  2942                              )
  2943                          >> Tuple.first
  2944                          >> Application.update
  2945                              (Msgs.Update <|
  2946                                  Message.Message.Click <|
  2947                                      Message.Message.StepHeader "plan"
  2948                              )
  2949                          >> Tuple.first
  2950                          >> Common.queryView
  2951                          >> Query.has [ class "step-body" ]
  2952                  , test "expanded step collapses on click" <|
  2953                      fetchPlanWithGetStep
  2954                          >> Application.handleDelivery
  2955                              (EventsReceived <|
  2956                                  Ok <|
  2957                                      [ { url =
  2958                                              eventsUrl
  2959                                        , data =
  2960                                              STModels.InitializeGet
  2961                                                  { source = ""
  2962                                                  , id = "plan"
  2963                                                  }
  2964                                                  (Time.millisToPosix 0)
  2965                                        }
  2966                                      ]
  2967                              )
  2968                          >> Tuple.first
  2969                          >> Application.update
  2970                              (Msgs.Update <|
  2971                                  Message.Message.Click <|
  2972                                      Message.Message.StepHeader "plan"
  2973                              )
  2974                          >> Tuple.first
  2975                          >> Application.update
  2976                              (Msgs.Update <|
  2977                                  Message.Message.Click <|
  2978                                      Message.Message.StepHeader "plan"
  2979                              )
  2980                          >> Tuple.first
  2981                          >> Common.queryView
  2982                          >> Query.hasNot [ class "step-body" ]
  2983                  , test "build step header lays out horizontally" <|
  2984                      fetchPlanWithGetStep
  2985                          >> Common.queryView
  2986                          >> Query.find [ class "header" ]
  2987                          >> Query.has [ style "display" "flex" ]
  2988                  , test "has two children spread apart" <|
  2989                      fetchPlanWithGetStep
  2990                          >> Common.queryView
  2991                          >> Query.find [ class "header" ]
  2992                          >> Expect.all
  2993                              [ Query.has
  2994                                  [ style "justify-content" "space-between" ]
  2995                              , Query.children [] >> Query.count (Expect.equal 2)
  2996                              ]
  2997                  , test "both children lay out horizontally" <|
  2998                      fetchPlanWithGetStep
  2999                          >> Common.queryView
  3000                          >> Query.find [ class "header" ]
  3001                          >> Query.children []
  3002                          >> Query.each
  3003                              (Query.has [ style "display" "flex" ])
  3004                  , test "resource get step shows get label" <|
  3005                      fetchPlanWithGetStep
  3006                          >> Common.queryView
  3007                          >> Query.has getStepLabel
  3008                  , test "artifact input step shows get label" <|
  3009                      fetchPlanWithArtifactInputStep
  3010                          >> Common.queryView
  3011                          >> Query.has getStepLabel
  3012                  , test "task step shows task label" <|
  3013                      fetchPlanWithTaskStep
  3014                          >> Common.queryView
  3015                          >> Query.has taskStepLabel
  3016                  , test "check step shows check label" <|
  3017                      fetchPlanWithCheckStep
  3018                          >> Common.queryView
  3019                          >> Query.has checkStepLabel
  3020                  , test "set_pipeline step shows set_pipeline label" <|
  3021                      fetchPlanWithSetPipelineStep
  3022                          >> Common.queryView
  3023                          >> Query.has setPipelineStepLabel
  3024                  , test "load_var step shows load_var label" <|
  3025                      fetchPlanWithLoadVarStep
  3026                          >> Common.queryView
  3027                          >> Query.has loadVarStepLabel
  3028                  , test "artifact output step shows put label" <|
  3029                      fetchPlanWithEnsureArtifactOutputStep
  3030                          >> Common.queryView
  3031                          >> Query.has putStepLabel
  3032                  , test "put step shows upward arrow" <|
  3033                      fetchPlanWithPutStep
  3034                          >> Common.queryView
  3035                          >> Query.has putStepLabel
  3036                  , test "get step on first occurrence shows yellow downward arrow" <|
  3037                      fetchPlanWithGetStepWithFirstOccurrence
  3038                          >> Common.queryView
  3039                          >> Query.has firstOccurrenceGetStepLabel
  3040                  , test "hovering over a normal get step label does nothing" <|
  3041                      fetchPlanWithGetStep
  3042                          >> Common.queryView
  3043                          >> Query.find getStepLabel
  3044                          >> Event.simulate Event.mouseEnter
  3045                          >> Event.toResult
  3046                          >> Expect.err
  3047                  , test "hovering over a normal set_pipeline step label does nothing" <|
  3048                      fetchPlanWithSetPipelineStep
  3049                          >> Common.queryView
  3050                          >> Query.find setPipelineStepLabel
  3051                          >> Event.simulate Event.mouseEnter
  3052                          >> Event.toResult
  3053                          >> Expect.err
  3054                  , describe "first-occurrence get step label hover behaviour"
  3055                      [ test "first-occurrence get step label has no tooltip" <|
  3056                          fetchPlanWithGetStepWithFirstOccurrence
  3057                              >> Common.queryView
  3058                              >> Query.findAll [ text "new version" ]
  3059                              >> Query.count (Expect.equal 0)
  3060                      , test "hovering over yellow label triggers Hover message" <|
  3061                          fetchPlanWithGetStepWithFirstOccurrence
  3062                              >> Common.queryView
  3063                              >> Query.findAll firstOccurrenceGetStepLabel
  3064                              >> Query.first
  3065                              >> Event.simulate Event.mouseEnter
  3066                              >> Event.expect
  3067                                  (Msgs.Update <|
  3068                                      Message.Message.Hover <|
  3069                                          Just firstOccurrenceLabelID
  3070                                  )
  3071                      , test "no tooltip before 1 second has passed" <|
  3072                          fetchPlanWithGetStepWithFirstOccurrence
  3073                              >> hoverFirstOccurrenceLabel
  3074                              >> Common.queryView
  3075                              >> Query.findAll [ text "new version" ]
  3076                              >> Query.count (Expect.equal 0)
  3077                      , test "1 second after hovering, tooltip appears" <|
  3078                          fetchPlanWithGetStepWithFirstOccurrence
  3079                              >> Application.handleDelivery
  3080                                  (ClockTicked OneSecond <|
  3081                                      Time.millisToPosix 0
  3082                                  )
  3083                              >> Tuple.first
  3084                              >> hoverFirstOccurrenceLabel
  3085                              >> Application.handleDelivery
  3086                                  (ClockTicked OneSecond <|
  3087                                      Time.millisToPosix 1
  3088                                  )
  3089                              >> Tuple.second
  3090                              >> Common.contains
  3091                                  (Effects.GetViewportOf firstOccurrenceLabelID)
  3092                      , test "mousing off yellow label triggers Hover message" <|
  3093                          fetchPlanWithGetStepWithFirstOccurrence
  3094                              >> hoverFirstOccurrenceLabel
  3095                              >> Common.queryView
  3096                              >> Query.findAll firstOccurrenceGetStepLabel
  3097                              >> Query.first
  3098                              >> Event.simulate Event.mouseLeave
  3099                              >> Event.expect
  3100                                  (Msgs.Update <| Message.Message.Hover Nothing)
  3101                      , test "unhovering after tooltip appears dismisses" <|
  3102                          fetchPlanWithGetStepWithFirstOccurrence
  3103                              >> Application.handleDelivery
  3104                                  (ClockTicked OneSecond <|
  3105                                      Time.millisToPosix 0
  3106                                  )
  3107                              >> Tuple.first
  3108                              >> hoverFirstOccurrenceLabel
  3109                              >> Application.handleDelivery
  3110                                  (ClockTicked OneSecond <|
  3111                                      Time.millisToPosix 1
  3112                                  )
  3113                              >> Tuple.first
  3114                              >> Application.update
  3115                                  (Msgs.Update <|
  3116                                      Message.Message.Hover Nothing
  3117                                  )
  3118                              >> Tuple.first
  3119                              >> Common.queryView
  3120                              >> Query.findAll [ text "new version" ]
  3121                              >> Query.count (Expect.equal 0)
  3122                      ]
  3123                  , test "hovering one resource of several produces only a single tooltip" <|
  3124                      fetchPlanWithGetStepWithFirstOccurrence
  3125                          >> Application.handleDelivery
  3126                              (ClockTicked OneSecond <|
  3127                                  Time.millisToPosix 0
  3128                              )
  3129                          >> Tuple.first
  3130                          >> hoverFirstOccurrenceLabel
  3131                          >> Application.handleDelivery
  3132                              (ClockTicked OneSecond <|
  3133                                  Time.millisToPosix 1
  3134                              )
  3135                          >> Tuple.first
  3136                          >> Application.handleCallback
  3137                              (Callback.GotViewport firstOccurrenceLabelID <|
  3138                                  Ok
  3139                                      { scene =
  3140                                          { width = 1
  3141                                          , height = 0
  3142                                          }
  3143                                      , viewport =
  3144                                          { width = 1
  3145                                          , height = 0
  3146                                          , x = 0
  3147                                          , y = 0
  3148                                          }
  3149                                      }
  3150                              )
  3151                          >> Tuple.first
  3152                          >> Application.handleCallback
  3153                              (Callback.GotElement <|
  3154                                  Ok
  3155                                      { scene =
  3156                                          { width = 0
  3157                                          , height = 0
  3158                                          }
  3159                                      , viewport =
  3160                                          { width = 0
  3161                                          , height = 0
  3162                                          , x = 0
  3163                                          , y = 0
  3164                                          }
  3165                                      , element =
  3166                                          { x = 0
  3167                                          , y = 0
  3168                                          , width = 1
  3169                                          , height = 1
  3170                                          }
  3171                                      }
  3172                              )
  3173                          >> Tuple.first
  3174                          >> Common.queryView
  3175                          >> Query.findAll [ text "new version" ]
  3176                          >> Query.count (Expect.equal 1)
  3177                  , test "successful step has a checkmark at the far right" <|
  3178                      fetchPlanWithGetStep
  3179                          >> Application.handleDelivery
  3180                              (EventsReceived <|
  3181                                  Ok <|
  3182                                      [ { url =
  3183                                              eventsUrl
  3184                                        , data =
  3185                                              STModels.FinishGet
  3186                                                  { source = "stdout"
  3187                                                  , id = "plan"
  3188                                                  }
  3189                                                  0
  3190                                                  Dict.empty
  3191                                                  []
  3192                                                  Nothing
  3193                                        }
  3194                                      ]
  3195                              )
  3196                          >> Tuple.first
  3197                          >> Common.queryView
  3198                          >> Query.find [ class "header" ]
  3199                          >> Query.children []
  3200                          >> Query.index -1
  3201                          >> Query.has
  3202                              (iconSelector
  3203                                  { size = "28px"
  3204                                  , image = Assets.SuccessCheckIcon
  3205                                  }
  3206                                  ++ [ style "background-size" "14px 14px" ]
  3207                              )
  3208                  , test "get step lists resource version on the right" <|
  3209                      fetchPlanWithGetStep
  3210                          >> Application.handleDelivery
  3211                              (EventsReceived <|
  3212                                  Ok <|
  3213                                      [ { url = eventsUrl
  3214                                        , data =
  3215                                              STModels.FinishGet
  3216                                                  { source = "stdout", id = "plan" }
  3217                                                  0
  3218                                                  (Dict.fromList [ ( "version", "v3.1.4" ) ])
  3219                                                  []
  3220                                                  Nothing
  3221                                        }
  3222                                      ]
  3223                              )
  3224                          >> Tuple.first
  3225                          >> Common.queryView
  3226                          >> Query.find [ class "header" ]
  3227                          >> Query.children []
  3228                          >> Query.index -1
  3229                          >> Query.has [ text "v3.1.4" ]
  3230                  , test "one tick after hovering step state, GetElement fires" <|
  3231                      fetchPlanWithGetStep
  3232                          >> Application.handleDelivery
  3233                              (EventsReceived <|
  3234                                  Ok <|
  3235                                      [ { url = eventsUrl
  3236                                        , data =
  3237                                              STModels.InitializeTask
  3238                                                  { source = "stdout", id = "plan" }
  3239                                                  (Time.millisToPosix 0)
  3240                                        }
  3241                                      , { url = eventsUrl
  3242                                        , data =
  3243                                              STModels.StartTask
  3244                                                  { source = "stdout", id = "plan" }
  3245                                                  (Time.millisToPosix 10000)
  3246                                        }
  3247                                      , { url = eventsUrl
  3248                                        , data =
  3249                                              STModels.FinishTask
  3250                                                  { source = "stdout", id = "plan" }
  3251                                                  0
  3252                                                  (Time.millisToPosix 30000)
  3253                                        }
  3254                                      ]
  3255                              )
  3256                          >> Tuple.first
  3257                          >> Application.update
  3258                              (Msgs.Update <|
  3259                                  Message.Message.Hover <|
  3260                                      Just <|
  3261                                          Message.Message.StepState
  3262                                              "plan"
  3263                              )
  3264                          >> Tuple.first
  3265                          >> Application.handleDelivery
  3266                              (ClockTicked OneSecond <|
  3267                                  Time.millisToPosix 1
  3268                              )
  3269                          >> Tuple.second
  3270                          >> Common.contains
  3271                              (Effects.GetViewportOf <| Message.Message.StepState "plan")
  3272                  , test "finished task lists initialization duration in tooltip" <|
  3273                      fetchPlanWithTaskStep
  3274                          >> Application.handleDelivery
  3275                              (EventsReceived <|
  3276                                  Ok <|
  3277                                      [ { url = eventsUrl
  3278                                        , data =
  3279                                              STModels.InitializeTask
  3280                                                  { source = "stdout", id = "plan" }
  3281                                                  (Time.millisToPosix 0)
  3282                                        }
  3283                                      , { url = eventsUrl
  3284                                        , data =
  3285                                              STModels.StartTask
  3286                                                  { source = "stdout", id = "plan" }
  3287                                                  (Time.millisToPosix 10000)
  3288                                        }
  3289                                      , { url = eventsUrl
  3290                                        , data =
  3291                                              STModels.FinishTask
  3292                                                  { source = "stdout", id = "plan" }
  3293                                                  0
  3294                                                  (Time.millisToPosix 30000)
  3295                                        }
  3296                                      ]
  3297                              )
  3298                          >> Tuple.first
  3299                          >> hoverOver (Message.Message.StepState "plan")
  3300                          >> Tuple.first
  3301                          >> Common.queryView
  3302                          >> Query.find [ id "tooltips" ]
  3303                          >> Query.children []
  3304                          >> Query.index -1
  3305                          >> Query.findAll [ tag "tr" ]
  3306                          >> Query.index 0
  3307                          >> Query.has [ text "initialization", text "10s" ]
  3308                  , test "finished task lists step duration in tooltip" <|
  3309                      fetchPlanWithTaskStep
  3310                          >> Application.handleDelivery
  3311                              (EventsReceived <|
  3312                                  Ok <|
  3313                                      [ { url = eventsUrl
  3314                                        , data =
  3315                                              STModels.InitializeTask
  3316                                                  { source = "stdout", id = "plan" }
  3317                                                  (Time.millisToPosix 0)
  3318                                        }
  3319                                      , { url = eventsUrl
  3320                                        , data =
  3321                                              STModels.StartTask
  3322                                                  { source = "stdout", id = "plan" }
  3323                                                  (Time.millisToPosix 10000)
  3324                                        }
  3325                                      , { url = eventsUrl
  3326                                        , data =
  3327                                              STModels.FinishTask
  3328                                                  { source = "stdout", id = "plan" }
  3329                                                  0
  3330                                                  (Time.millisToPosix 30000)
  3331                                        }
  3332                                      ]
  3333                              )
  3334                          >> Tuple.first
  3335                          >> hoverOver (Message.Message.StepState "plan")
  3336                          >> Tuple.first
  3337                          >> Common.queryView
  3338                          >> Query.find [ id "tooltips" ]
  3339                          >> Query.children []
  3340                          >> Query.index -1
  3341                          >> Query.findAll [ tag "tr" ]
  3342                          >> Query.index 1
  3343                          >> Query.has [ text "step", text "20s" ]
  3344                  , test "running step has loading spinner at the right" <|
  3345                      fetchPlanWithTaskStep
  3346                          >> Application.handleDelivery
  3347                              (EventsReceived <|
  3348                                  Ok <|
  3349                                      [ { url = eventsUrl
  3350                                        , data =
  3351                                              STModels.StartTask
  3352                                                  { source = "stdout"
  3353                                                  , id = "plan"
  3354                                                  }
  3355                                                  (Time.millisToPosix 0)
  3356                                        }
  3357                                      ]
  3358                              )
  3359                          >> Tuple.first
  3360                          >> Common.queryView
  3361                          >> Query.find [ class "header" ]
  3362                          >> Query.children []
  3363                          >> Query.index -1
  3364                          >> Query.has
  3365                              [ style "animation"
  3366                                  "container-rotate 1568ms linear infinite"
  3367                              ]
  3368                  , test "running step shows running in tooltip" <|
  3369                      fetchPlanWithTaskStep
  3370                          >> Application.handleDelivery
  3371                              (EventsReceived <|
  3372                                  Ok <|
  3373                                      [ { url = eventsUrl
  3374                                        , data =
  3375                                              STModels.StartTask
  3376                                                  { source = "stdout"
  3377                                                  , id = "plan"
  3378                                                  }
  3379                                                  (Time.millisToPosix 0)
  3380                                        }
  3381                                      ]
  3382                              )
  3383                          >> Tuple.first
  3384                          >> hoverOver (Message.Message.StepState "plan")
  3385                          >> Tuple.first
  3386                          >> Common.queryView
  3387                          >> Query.find [ id "tooltips" ]
  3388                          >> Query.has [ text "running" ]
  3389                  , test "pending step has dashed circle at the right" <|
  3390                      fetchPlanWithTaskStep
  3391                          >> Common.queryView
  3392                          >> Query.find [ class "header" ]
  3393                          >> Query.children []
  3394                          >> Query.index -1
  3395                          >> Query.has
  3396                              (iconSelector
  3397                                  { size = "28px"
  3398                                  , image = Assets.PendingIcon
  3399                                  }
  3400                                  ++ [ style "background-size" "14px 14px" ]
  3401                              )
  3402                  , test "pending step shows pending in tooltip" <|
  3403                      fetchPlanWithTaskStep
  3404                          >> hoverOver (Message.Message.StepState "plan")
  3405                          >> Tuple.first
  3406                          >> Common.queryView
  3407                          >> Query.find [ id "tooltips" ]
  3408                          >> Query.has [ text "pending" ]
  3409                  , test "interrupted step has no-entry circle at the right" <|
  3410                      fetchPlanWithTaskStep
  3411                          >> Application.handleDelivery
  3412                              (EventsReceived <|
  3413                                  Ok <|
  3414                                      [ { url = eventsUrl
  3415                                        , data =
  3416                                              STModels.InitializeTask
  3417                                                  { source = "stdout"
  3418                                                  , id = "plan"
  3419                                                  }
  3420                                                  (Time.millisToPosix 0)
  3421                                        }
  3422                                      , { url = eventsUrl
  3423                                        , data =
  3424                                              STModels.BuildStatus
  3425                                                  BuildStatusAborted
  3426                                                  (Time.millisToPosix 0)
  3427                                        }
  3428                                      ]
  3429                              )
  3430                          >> Tuple.first
  3431                          >> Common.queryView
  3432                          >> Query.find [ class "header" ]
  3433                          >> Query.children []
  3434                          >> Query.index -1
  3435                          >> Query.has
  3436                              (iconSelector
  3437                                  { size = "28px"
  3438                                  , image = Assets.InterruptedIcon
  3439                                  }
  3440                                  ++ [ style "background-size" "14px 14px" ]
  3441                              )
  3442                  , test "interrupted step shows interrupted in tooltip" <|
  3443                      fetchPlanWithTaskStep
  3444                          >> Application.handleDelivery
  3445                              (EventsReceived <|
  3446                                  Ok <|
  3447                                      [ { url = eventsUrl
  3448                                        , data =
  3449                                              STModels.InitializeTask
  3450                                                  { source = "stdout"
  3451                                                  , id = "plan"
  3452                                                  }
  3453                                                  (Time.millisToPosix 0)
  3454                                        }
  3455                                      , { url = eventsUrl
  3456                                        , data =
  3457                                              STModels.BuildStatus
  3458                                                  BuildStatusAborted
  3459                                                  (Time.millisToPosix 0)
  3460                                        }
  3461                                      ]
  3462                              )
  3463                          >> Tuple.first
  3464                          >> hoverOver (Message.Message.StepState "plan")
  3465                          >> Tuple.first
  3466                          >> Common.queryView
  3467                          >> Query.find [ id "tooltips" ]
  3468                          >> Query.has [ text "interrupted" ]
  3469                  , test "cancelled step has dashed circle with dot at the right" <|
  3470                      fetchPlanWithTaskStep
  3471                          >> Application.handleDelivery
  3472                              (EventsReceived <|
  3473                                  Ok <|
  3474                                      [ { url = eventsUrl
  3475                                        , data =
  3476                                              STModels.BuildStatus
  3477                                                  BuildStatusAborted
  3478                                                  (Time.millisToPosix 0)
  3479                                        }
  3480                                      ]
  3481                              )
  3482                          >> Tuple.first
  3483                          >> Common.queryView
  3484                          >> Query.find [ class "header" ]
  3485                          >> Query.children []
  3486                          >> Query.index -1
  3487                          >> Query.has
  3488                              (iconSelector
  3489                                  { size = "28px"
  3490                                  , image = Assets.CancelledIcon
  3491                                  }
  3492                                  ++ [ style "background-size" "14px 14px" ]
  3493                              )
  3494                  , test "cancelled step shows cancelled in tooltip" <|
  3495                      fetchPlanWithTaskStep
  3496                          >> Application.handleDelivery
  3497                              (EventsReceived <|
  3498                                  Ok <|
  3499                                      [ { url = eventsUrl
  3500                                        , data =
  3501                                              STModels.BuildStatus
  3502                                                  BuildStatusAborted
  3503                                                  (Time.millisToPosix 0)
  3504                                        }
  3505                                      ]
  3506                              )
  3507                          >> Tuple.first
  3508                          >> hoverOver (Message.Message.StepState "plan")
  3509                          >> Tuple.first
  3510                          >> Common.queryView
  3511                          >> Query.find [ id "tooltips" ]
  3512                          >> Query.has [ text "cancelled" ]
  3513                  , test "failing step has an X at the far right" <|
  3514                      fetchPlanWithGetStep
  3515                          >> Application.handleDelivery
  3516                              (EventsReceived <|
  3517                                  Ok <|
  3518                                      [ { url = eventsUrl
  3519                                        , data =
  3520                                              STModels.FinishGet
  3521                                                  { source = "stdout", id = "plan" }
  3522                                                  1
  3523                                                  Dict.empty
  3524                                                  []
  3525                                                  Nothing
  3526                                        }
  3527                                      ]
  3528                              )
  3529                          >> Tuple.first
  3530                          >> Common.queryView
  3531                          >> Query.find [ class "header" ]
  3532                          >> Query.children []
  3533                          >> Query.index -1
  3534                          >> Query.has
  3535                              (iconSelector
  3536                                  { size = "28px"
  3537                                  , image = Assets.FailureTimesIcon
  3538                                  }
  3539                                  ++ [ style "background-size" "14px 14px" ]
  3540                              )
  3541                  , test "erroring step has orange exclamation triangle at right" <|
  3542                      fetchPlanWithGetStep
  3543                          >> Application.handleDelivery
  3544                              (EventsReceived <|
  3545                                  Ok <|
  3546                                      [ { url = eventsUrl
  3547                                        , data =
  3548                                              STModels.Error
  3549                                                  { source = "stderr", id = "plan" }
  3550                                                  "error message"
  3551                                                  (Time.millisToPosix 0)
  3552                                        }
  3553                                      ]
  3554                              )
  3555                          >> Tuple.first
  3556                          >> Common.queryView
  3557                          >> Query.find [ class "header" ]
  3558                          >> Query.children []
  3559                          >> Query.index -1
  3560                          >> Query.has
  3561                              (iconSelector
  3562                                  { size = "28px"
  3563                                  , image = Assets.ExclamationTriangleIcon
  3564                                  }
  3565                                  ++ [ style "background-size" "14px 14px" ]
  3566                              )
  3567                  , test "successful step has no border" <|
  3568                      fetchPlanWithGetStep
  3569                          >> Application.handleDelivery
  3570                              (EventsReceived <|
  3571                                  Ok <|
  3572                                      [ { url =
  3573                                              eventsUrl
  3574                                        , data =
  3575                                              STModels.FinishGet
  3576                                                  { source = "stdout"
  3577                                                  , id = "plan"
  3578                                                  }
  3579                                                  0
  3580                                                  Dict.empty
  3581                                                  []
  3582                                                  Nothing
  3583                                        }
  3584                                      ]
  3585                              )
  3586                          >> Tuple.first
  3587                          >> Common.queryView
  3588                          >> Query.find [ class "header" ]
  3589                          >> Query.has [ style "border-color" "transparent" ]
  3590                  , test "failing step has a red border" <|
  3591                      fetchPlanWithGetStep
  3592                          >> Application.handleDelivery
  3593                              (EventsReceived <|
  3594                                  Ok <|
  3595                                      [ { url = eventsUrl
  3596                                        , data =
  3597                                              STModels.FinishGet
  3598                                                  { source = "stdout", id = "plan" }
  3599                                                  1
  3600                                                  Dict.empty
  3601                                                  []
  3602                                                  Nothing
  3603                                        }
  3604                                      ]
  3605                              )
  3606                          >> Tuple.first
  3607                          >> Common.queryView
  3608                          >> Query.find [ class "header" ]
  3609                          >> Query.has
  3610                              [ style "border-color" <| Colors.failure ]
  3611                  , test "started step has a yellow border" <|
  3612                      fetchPlanWithTaskStep
  3613                          >> Application.handleDelivery
  3614                              (EventsReceived <|
  3615                                  Ok <|
  3616                                      [ { url = eventsUrl
  3617                                        , data =
  3618                                              STModels.StartTask
  3619                                                  { source = "stdout"
  3620                                                  , id = "plan"
  3621                                                  }
  3622                                                  (Time.millisToPosix 0)
  3623                                        }
  3624                                      ]
  3625                              )
  3626                          >> Tuple.first
  3627                          >> Common.queryView
  3628                          >> Query.find [ class "header" ]
  3629                          >> Query.has
  3630                              [ style "border-color" <| Colors.started ]
  3631                  , test "set_pipeline step that changed something has a yellow text" <|
  3632                      fetchPlanWithSetPipelineStep
  3633                          >> Application.handleDelivery
  3634                              (EventsReceived <|
  3635                                  Ok <|
  3636                                      [ { url = eventsUrl
  3637                                        , data =
  3638                                              STModels.SetPipelineChanged
  3639                                                  { source = "stdout", id = "plan" }
  3640                                                  True
  3641                                        }
  3642                                      ]
  3643                              )
  3644                          >> Tuple.first
  3645                          >> Common.queryView
  3646                          >> Query.has changedSetPipelineStepLabel
  3647                  , test "set_pipeline step that changed something tooltip appears after 1 second" <|
  3648                      fetchPlanWithSetPipelineStep
  3649                          >> Application.handleDelivery
  3650                              (EventsReceived <|
  3651                                  Ok <|
  3652                                      [ { url = eventsUrl
  3653                                        , data =
  3654                                              STModels.SetPipelineChanged
  3655                                                  { source = "stdout", id = "plan" }
  3656                                                  True
  3657                                        }
  3658                                      ]
  3659                              )
  3660                          >> Tuple.first
  3661                          >> Application.handleDelivery
  3662                              (ClockTicked OneSecond <|
  3663                                  Time.millisToPosix 0
  3664                              )
  3665                          >> Tuple.first
  3666                          >> hoverSetPipelineChangedLabel
  3667                          >> Application.handleDelivery
  3668                              (ClockTicked OneSecond <|
  3669                                  Time.millisToPosix 1
  3670                              )
  3671                          >> Tuple.second
  3672                          >> Common.contains
  3673                              (Effects.GetViewportOf setPipelineChangedLabelID)
  3674                  , test "network error on first event shows passport officer" <|
  3675                      let
  3676                          imgUrl =
  3677                              Assets.toString Assets.PassportOfficerIcon
  3678                      in
  3679                      fetchPlanWithGetStep
  3680                          >> Application.handleDelivery
  3681                              (EventsReceived <|
  3682                                  Ok
  3683                                      [ { data = STModels.NetworkError
  3684                                        , url = eventsUrl
  3685                                        }
  3686                                      ]
  3687                              )
  3688                          >> Tuple.first
  3689                          >> Common.queryView
  3690                          >> Query.find [ class "not-authorized" ]
  3691                          >> Query.find [ tag "img" ]
  3692                          >> Query.has [ attribute <| Attr.src imgUrl ]
  3693                  , test """network error after first event fails silently
  3694                            (EventSource browser API will retry connection)""" <|
  3695                      fetchPlanWithGetStep
  3696                          >> Application.handleDelivery
  3697                              (EventsReceived <|
  3698                                  Ok
  3699                                      [ { url = eventsUrl
  3700                                        , data = STModels.Opened
  3701                                        }
  3702                                      ]
  3703                              )
  3704                          >> Tuple.first
  3705                          >> Application.handleDelivery
  3706                              (EventsReceived <|
  3707                                  Ok
  3708                                      [ { data = STModels.NetworkError
  3709                                        , url = eventsUrl
  3710                                        }
  3711                                      ]
  3712                              )
  3713                          >> Tuple.first
  3714                          >> Common.queryView
  3715                          >> Query.findAll [ class "not-authorized" ]
  3716                          >> Query.count (Expect.equal 0)
  3717                  ]
  3718              , describe "get step with metadata" <|
  3719                  let
  3720                      httpURLText =
  3721                          "http://some-url"
  3722  
  3723                      httpsURLText =
  3724                          "https://some-url"
  3725  
  3726                      plainText =
  3727                          "plain-text"
  3728  
  3729                      invalidURLText =
  3730                          "https:// is secure!"
  3731  
  3732                      metadataView =
  3733                          Application.init
  3734                              flags
  3735                              { protocol = Url.Http
  3736                              , host = ""
  3737                              , port_ = Nothing
  3738                              , path = "/teams/t/pipelines/p/jobs/j/builds/1"
  3739                              , query = Nothing
  3740                              , fragment = Just "Lstepid:1"
  3741                              }
  3742                              |> Tuple.first
  3743                              |> Application.handleCallback
  3744                                  (Callback.BuildFetched <|
  3745                                      Ok
  3746                                          { id = 1
  3747                                          , name = "1"
  3748                                          , job = Just Data.shortJobId
  3749                                          , status = BuildStatusStarted
  3750                                          , duration =
  3751                                              { startedAt = Nothing
  3752                                              , finishedAt = Nothing
  3753                                              }
  3754                                          , reapTime = Nothing
  3755                                          }
  3756                                  )
  3757                              |> Tuple.first
  3758                              |> Application.handleCallback
  3759                                  (Callback.PlanAndResourcesFetched 1 <|
  3760                                      Ok <|
  3761                                          ( { id = "stepid"
  3762                                            , step =
  3763                                                  Concourse.BuildStepGet
  3764                                                      "step"
  3765                                                      (Just <| Dict.fromList [ ( "version", "1" ) ])
  3766                                            }
  3767                                          , { inputs = [], outputs = [] }
  3768                                          )
  3769                                  )
  3770                              |> Tuple.first
  3771                              |> Application.update
  3772                                  (Msgs.DeliveryReceived <|
  3773                                      EventsReceived <|
  3774                                          Ok <|
  3775                                              [ { url = eventsUrl
  3776                                                , data =
  3777                                                      STModels.FinishGet
  3778                                                          { source = "stdout"
  3779                                                          , id = "stepid"
  3780                                                          }
  3781                                                          1
  3782                                                          (Dict.fromList [ ( "version", "1" ) ])
  3783                                                          [ { name = "http-url"
  3784                                                            , value = httpURLText
  3785                                                            }
  3786                                                          , { name = "https-url"
  3787                                                            , value = httpsURLText
  3788                                                            }
  3789                                                          , { name = "plain-text"
  3790                                                            , value = plainText
  3791                                                            }
  3792                                                          ]
  3793                                                          Nothing
  3794                                                }
  3795                                              ]
  3796                                  )
  3797                              |> Tuple.first
  3798                              |> Common.queryView
  3799                  in
  3800                  [ test "should show hyperlink if metadata starts with 'http://'" <|
  3801                      \_ ->
  3802                          metadataView
  3803                              |> Query.find
  3804                                  [ containing [ text httpURLText ]
  3805                                  ]
  3806                              |> Query.has
  3807                                  [ tag "a"
  3808                                  , style "text-decoration-line" "underline"
  3809                                  , attribute <| Attr.target "_blank"
  3810                                  , attribute <| Attr.href httpURLText
  3811                                  ]
  3812                  , test "should show hyperlink if metadata starts with 'https://'" <|
  3813                      \_ ->
  3814                          metadataView
  3815                              |> Query.find
  3816                                  [ containing [ text httpsURLText ]
  3817                                  ]
  3818                              |> Query.has
  3819                                  [ tag "a"
  3820                                  , style "text-decoration-line" "underline"
  3821                                  , attribute <| Attr.target "_blank"
  3822                                  , attribute <| Attr.href httpsURLText
  3823                                  ]
  3824                  , test "should not show hyperlink if metadata is plain text" <|
  3825                      \_ ->
  3826                          metadataView
  3827                              |> Query.find
  3828                                  [ containing [ text plainText ]
  3829                                  ]
  3830                              |> Query.hasNot
  3831                                  [ tag "a"
  3832                                  , style "text-decoration-line" "underline"
  3833                                  , attribute <| Attr.target "_blank"
  3834                                  , attribute <| Attr.href plainText
  3835                                  ]
  3836                  , test "should not show hyperlink if metadata is malformed URL" <|
  3837                      \_ ->
  3838                          metadataView
  3839                              |> Query.find
  3840                                  [ containing [ text invalidURLText ]
  3841                                  ]
  3842                              |> Query.hasNot
  3843                                  [ tag "a"
  3844                                  , style "text-decoration-line" "underline"
  3845                                  , attribute <| Attr.target "_blank"
  3846                                  , attribute <| Attr.href invalidURLText
  3847                                  ]
  3848                  ]
  3849              ]
  3850          ]
  3851  
  3852  
  3853  getStepLabel =
  3854      [ style "color" Colors.pending
  3855      , style "line-height" "28px"
  3856      , style "padding-left" "6px"
  3857      , containing [ text "get:" ]
  3858      ]
  3859  
  3860  
  3861  firstOccurrenceGetStepLabel =
  3862      [ style "color" Colors.started
  3863      , style "line-height" "28px"
  3864      , style "padding-left" "6px"
  3865      , containing [ text "get:" ]
  3866      ]
  3867  
  3868  
  3869  putStepLabel =
  3870      [ style "color" Colors.pending
  3871      , style "line-height" "28px"
  3872      , style "padding-left" "6px"
  3873      , containing [ text "put:" ]
  3874      ]
  3875  
  3876  
  3877  taskStepLabel =
  3878      [ style "color" Colors.pending
  3879      , style "line-height" "28px"
  3880      , style "padding-left" "6px"
  3881      , containing [ text "task:" ]
  3882      ]
  3883  
  3884  
  3885  setPipelineStepLabel =
  3886      [ style "color" Colors.pending
  3887      , style "line-height" "28px"
  3888      , style "padding-left" "6px"
  3889      , containing [ text "set_pipeline:" ]
  3890      ]
  3891  
  3892  
  3893  changedSetPipelineStepLabel =
  3894      [ style "color" Colors.started
  3895      , style "line-height" "28px"
  3896      , style "padding-left" "6px"
  3897      , containing [ text "set_pipeline:" ]
  3898      ]
  3899  
  3900  
  3901  checkStepLabel =
  3902      [ style "color" Colors.pending
  3903      , style "line-height" "28px"
  3904      , style "padding-left" "6px"
  3905      , containing [ text "check:" ]
  3906      ]
  3907  
  3908  
  3909  loadVarStepLabel =
  3910      [ style "color" Colors.pending
  3911      , style "line-height" "28px"
  3912      , style "padding-left" "6px"
  3913      , containing [ text "load_var:" ]
  3914      ]
  3915  
  3916  
  3917  firstOccurrenceLabelID =
  3918      Message.Message.ChangedStepLabel
  3919          "foo"
  3920          "new version"
  3921  
  3922  
  3923  hoverFirstOccurrenceLabel =
  3924      Application.update
  3925          (Msgs.Update <| Message.Message.Hover <| Just firstOccurrenceLabelID)
  3926          >> Tuple.first
  3927  
  3928  
  3929  setPipelineChangedLabelID =
  3930      Message.Message.ChangedStepLabel
  3931          "foo"
  3932          "pipeline config changed"
  3933  
  3934  
  3935  hoverSetPipelineChangedLabel =
  3936      Application.update
  3937          (Msgs.Update <| Message.Message.Hover <| Just setPipelineChangedLabelID)
  3938          >> Tuple.first
  3939  
  3940  
  3941  tooltipGreyHex : String
  3942  tooltipGreyHex =
  3943      "#9b9b9b"
  3944  
  3945  
  3946  darkRed : String
  3947  darkRed =
  3948      "#bd3826"
  3949  
  3950  
  3951  brightRed : String
  3952  brightRed =
  3953      "#ed4b35"
  3954  
  3955  
  3956  darkGreen : String
  3957  darkGreen =
  3958      "#419867"
  3959  
  3960  
  3961  brightGreen : String
  3962  brightGreen =
  3963      "#11c560"
  3964  
  3965  
  3966  darkGrey : String
  3967  darkGrey =
  3968      "#3d3c3c"
  3969  
  3970  
  3971  receiveEvent :
  3972      STModels.BuildEventEnvelope
  3973      -> Application.Model
  3974      -> ( Application.Model, List Effects.Effect )
  3975  receiveEvent envelope =
  3976      Application.update (Msgs.DeliveryReceived <| EventsReceived <| Ok [ envelope ])
  3977  
  3978  
  3979  hoverOver domID =
  3980      Application.update
  3981          (Msgs.Update (Message.Message.Hover (Just domID)))
  3982          >> Tuple.first
  3983          >> Application.handleDelivery
  3984              (ClockTicked OneSecond <|
  3985                  Time.millisToPosix 1
  3986              )
  3987          >> Tuple.first
  3988          >> Application.handleCallback
  3989              (Callback.GotViewport domID <|
  3990                  Ok
  3991                      { scene =
  3992                          { width = 1
  3993                          , height = 0
  3994                          }
  3995                      , viewport =
  3996                          { width = 1
  3997                          , height = 0
  3998                          , x = 0
  3999                          , y = 0
  4000                          }
  4001                      }
  4002              )
  4003          >> Tuple.first
  4004          >> Application.handleCallback
  4005              (Callback.GotElement <|
  4006                  Ok
  4007                      { scene =
  4008                          { width = 0
  4009                          , height = 0
  4010                          }
  4011                      , viewport =
  4012                          { width = 0
  4013                          , height = 0
  4014                          , x = 0
  4015                          , y = 0
  4016                          }
  4017                      , element =
  4018                          { x = 0
  4019                          , y = 0
  4020                          , width = 1
  4021                          , height = 1
  4022                          }
  4023                      }
  4024              )