add tab tests

This commit is contained in:
charbelrami 2022-10-04 15:08:57 -03:00
parent 50931dd848
commit a42ef41e8d
4 changed files with 280 additions and 36 deletions

View File

@ -246,10 +246,11 @@ viewTabPanel tab selected =
++ (if selected then ++ (if selected then
[ -- Used as selector for test queries [ -- Used as selector for test queries
Attributes.attribute "data-selected" "true" Attributes.attribute "data-selected" "true"
, Attributes.style "display" "block"
] ]
else else
[ Attributes.css [ Css.display Css.none ] [ Attributes.style "display" "none"
] ]
) )
) )

View File

@ -118,6 +118,24 @@ pressShiftLeft { targetDetails } =
pressKey { targetDetails = targetDetails, keyCode = 37, shiftKey = True } pressKey { targetDetails = targetDetails, keyCode = 37, shiftKey = True }
releaseRightArrow :
{ targetDetails : List ( String, Encode.Value ) }
-> List Selector
-> ProgramTest model msg effect
-> ProgramTest model msg effect
releaseRightArrow { targetDetails } =
releaseKey { targetDetails = targetDetails, keyCode = 39, shiftKey = False }
releaseLeftArrow :
{ targetDetails : List ( String, Encode.Value ) }
-> List Selector
-> ProgramTest model msg effect
-> ProgramTest model msg effect
releaseLeftArrow { targetDetails } =
releaseKey { targetDetails = targetDetails, keyCode = 37, shiftKey = False }
releaseShiftRight : releaseShiftRight :
{ targetDetails : List ( String, Encode.Value ) } { targetDetails : List ( String, Encode.Value ) }
-> List Selector -> List Selector

View File

@ -28,7 +28,7 @@ keyboardTests =
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> done |> done
, test "has only one element included in the tab sequence" <| , test "has only one element included in the tab sequence" <|
\() -> \() ->
@ -40,55 +40,55 @@ keyboardTests =
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> rightArrow |> rightArrow
|> ensureFocusOn "indirect" |> ensureTabbable "indirect"
|> ensureOnlyOneInTabSequence (String.words "Pothos indirect light") |> ensureOnlyOneInTabSequence (String.words "Pothos indirect light")
|> rightArrow |> rightArrow
|> ensureFocusOn "light" |> ensureTabbable "light"
-- once we're on the final element, pressing right arrow again should -- once we're on the final element, pressing right arrow again should
-- _not_ wrap the focus. We should stay right where we are! -- _not_ wrap the focus. We should stay right where we are!
|> rightArrow |> rightArrow
|> ensureFocusOn "light" |> ensureTabbable "light"
|> done |> done
, test "moves focus left on left arrow key" <| , test "moves focus left on left arrow key" <|
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> rightArrow |> rightArrow
|> ensureFocusOn "indirect" |> ensureTabbable "indirect"
|> leftArrow |> leftArrow
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> ensureOnlyOneInTabSequence (String.words "Pothos indirect light") |> ensureOnlyOneInTabSequence (String.words "Pothos indirect light")
-- once we're on the first element, pressing left arrow again should -- once we're on the first element, pressing left arrow again should
-- _not_ wrap the focus. We should stay right where we are! -- _not_ wrap the focus. We should stay right where we are!
|> leftArrow |> leftArrow
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> done |> done
, test "moves focus right on shift + right arrow" <| , test "moves focus right on shift + right arrow" <|
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> shiftRight |> shiftRight
|> ensureFocusOn "indirect" |> ensureTabbable "indirect"
|> shiftRight |> shiftRight
|> ensureFocusOn "light" |> ensureTabbable "light"
|> shiftRight |> shiftRight
|> ensureFocusOn "light" |> ensureTabbable "light"
|> done |> done
, test "moves focus left on shift + left arrow" <| , test "moves focus left on shift + left arrow" <|
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> rightArrow |> rightArrow
|> ensureFocusOn "indirect" |> ensureTabbable "indirect"
|> shiftLeft |> shiftLeft
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> shiftLeft |> shiftLeft
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> done |> done
, test "expands selection one element to the right on shift + right arrow and highlight selected elements" <| , test "expands selection one element to the right on shift + right arrow and highlight selected elements" <|
\() -> \() ->
@ -124,13 +124,13 @@ keyboardTests =
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> shiftRight |> shiftRight
|> releaseShiftRight |> releaseShiftRight
|> ensureMarked [ "Pothos", " ", "indirect" ] |> ensureMarked [ "Pothos", " ", "indirect" ]
|> ensureFocusOn "indirect" |> ensureTabbable "indirect"
|> rightArrow |> rightArrow
|> ensureFocusOn "light" |> ensureTabbable "light"
|> shiftLeft |> shiftLeft
|> releaseShiftLeft |> releaseShiftLeft
|> ensureMarked [ "Pothos", " ", "indirect", " ", "light" ] |> ensureMarked [ "Pothos", " ", "indirect", " ", "light" ]
@ -139,7 +139,7 @@ keyboardTests =
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> mouseDown "Pothos" |> mouseDown "Pothos"
|> mouseUp "Pothos" |> mouseUp "Pothos"
|> ensureMarked [ "Pothos" ] |> ensureMarked [ "Pothos" ]
@ -148,7 +148,7 @@ keyboardTests =
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> mouseDown "Pothos" |> mouseDown "Pothos"
|> mouseOver "indirect" |> mouseOver "indirect"
|> mouseUp "Pothos" |> mouseUp "Pothos"
@ -158,7 +158,7 @@ keyboardTests =
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> space |> space
|> ensureMarked [ "Pothos" ] |> ensureMarked [ "Pothos" ]
|> done |> done
@ -166,10 +166,10 @@ keyboardTests =
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> space |> space
|> ensureMarked [ "Pothos" ] |> ensureMarked [ "Pothos" ]
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> mouseDown "Pothos" |> mouseDown "Pothos"
|> mouseUp "Pothos" |> mouseUp "Pothos"
|> expectViewHasNot |> expectViewHasNot
@ -178,7 +178,7 @@ keyboardTests =
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> shiftRight |> shiftRight
|> releaseShiftRight |> releaseShiftRight
|> ensureMarked [ "Pothos", " ", "indirect" ] |> ensureMarked [ "Pothos", " ", "indirect" ]
@ -190,19 +190,19 @@ keyboardTests =
\() -> \() ->
Highlightable.initFragments Nothing "Pothos indirect light" Highlightable.initFragments Nothing "Pothos indirect light"
|> program marker |> program marker
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> space |> space
|> ensureMarked [ "Pothos" ] |> ensureMarked [ "Pothos" ]
|> ensureFocusOn "Pothos" |> ensureTabbable "Pothos"
|> space |> space
|> expectViewHasNot |> expectViewHasNot
[ Selector.tag "mark" ] [ Selector.tag "mark" ]
] ]
ensureFocusOn : String -> TestContext marker -> TestContext marker ensureTabbable : String -> TestContext marker -> TestContext marker
ensureFocusOn word textContext = ensureTabbable word testContext =
textContext testContext
|> ensureView |> ensureView
(Query.find [ Selector.attribute (Key.tabbable True) ] (Query.find [ Selector.attribute (Key.tabbable True) ]
>> Query.has [ Selector.text word ] >> Query.has [ Selector.text word ]
@ -210,8 +210,8 @@ ensureFocusOn word textContext =
ensureOnlyOneInTabSequence : List String -> TestContext marker -> TestContext marker ensureOnlyOneInTabSequence : List String -> TestContext marker -> TestContext marker
ensureOnlyOneInTabSequence words textContext = ensureOnlyOneInTabSequence words testContext =
textContext testContext
|> ensureView |> ensureView
(Query.findAll [ Selector.attribute (Key.tabbable True) ] (Query.findAll [ Selector.attribute (Key.tabbable True) ]
>> Query.count (Expect.equal 1) >> Query.count (Expect.equal 1)
@ -223,8 +223,8 @@ ensureOnlyOneInTabSequence words textContext =
ensureMarked : List String -> TestContext marker -> TestContext marker ensureMarked : List String -> TestContext marker -> TestContext marker
ensureMarked words textContext = ensureMarked words testContext =
textContext testContext
|> ensureView |> ensureView
(Query.find [ Selector.tag "mark" ] (Query.find [ Selector.tag "mark" ]
>> Query.children [ Selector.tag "span" ] >> Query.children [ Selector.tag "span" ]
@ -232,6 +232,10 @@ ensureMarked words textContext =
) )
-- TODO: ensure other elements are not marked
space : TestContext marker -> TestContext marker space : TestContext marker -> TestContext marker
space = space =
KeyboardHelpers.pressSpaceKey { targetDetails = [] } KeyboardHelpers.pressSpaceKey { targetDetails = [] }

221
tests/Spec/Nri/Ui/Tabs.elm Normal file
View File

@ -0,0 +1,221 @@
module Spec.Nri.Ui.Tabs exposing (spec)
import Accessibility.Key as Key
import Accessibility.Role as Role
import Browser.Dom as Dom
import Expect
import Html.Styled as Html exposing (..)
import Nri.Ui.Tabs.V7 as Tabs
import ProgramTest exposing (..)
import Spec.KeyboardHelpers as KeyboardHelpers
import Task
import Test exposing (..)
import Test.Html.Query as Query
import Test.Html.Selector as Selector
spec : Test
spec =
describe "Nri.Ui.Tabs.V7"
[ describe "panel rendering" panelRenderingTests
, describe "keyboard behavior" keyboardTests
]
panelRenderingTests : List Test
panelRenderingTests =
[ test "displays the associated panel when a tab is activated" <|
\() ->
program
|> ensureTabbable "Tab 0"
|> ensurePanelDisplayed "Panel 0"
|> done
, test "has only one panel displayed" <|
\() ->
program
|> ensureOnlyOnePanelDisplayed [ "Panel 0", "Panel 1", "Panel 2" ]
|> done
]
keyboardTests : List Test
keyboardTests =
[ test "has a focusable tab" <|
\() ->
program
|> ensureTabbable "Tab 0"
|> done
, test "all panels are focusable" <|
\() ->
program
|> ensurePanelsFocusable [ "Panel 0", "Panel 1", "Panel 2" ]
|> done
, test "has only one tab included in the tab sequence" <|
\() ->
program
|> ensureOnlyOneTabInSequence [ "Tab 0", "Tab 1", "Tab 2" ]
|> done
, test "moves focus right on right arrow key" <|
\() ->
program
|> ensureTabbable "Tab 0"
|> releaseRightArrow
|> ensureTabbable "Tab 1"
|> ensureOnlyOneTabInSequence [ "Tab 0", "Tab 1", "Tab 2" ]
|> releaseRightArrow
|> ensureTabbable "Tab 2"
|> done
, test "moves focus left on left arrow key" <|
\() ->
program
|> ensureTabbable "Tab 0"
|> releaseRightArrow
|> ensureTabbable "Tab 1"
|> releaseLeftArrow
|> ensureTabbable "Tab 0"
|> ensureOnlyOneTabInSequence [ "Tab 0", "Tab 1", "Tab 2" ]
|> done
, test "when the focus is on the first element, move focus to the last element on left arrow key" <|
\() ->
program
|> ensureTabbable "Tab 0"
|> releaseLeftArrow
|> ensureTabbable "Tab 2"
|> ensureOnlyOneTabInSequence [ "Tab 0", "Tab 1", "Tab 2" ]
|> done
, test "when the focus is on the last element, move focus to the first element on right arrow key" <|
\() ->
program
|> ensureTabbable "Tab 0"
|> releaseLeftArrow
|> ensureTabbable "Tab 2"
|> releaseRightArrow
|> ensureTabbable "Tab 0"
|> ensureOnlyOneTabInSequence [ "Tab 0", "Tab 1", "Tab 2" ]
|> done
]
type alias TestContext =
ProgramTest State Msg ()
ensureTabbable : String -> TestContext -> TestContext
ensureTabbable word testContext =
testContext
|> ensureView
(Query.find [ Selector.attribute Role.tab, Selector.attribute (Key.tabbable True) ]
>> Query.has [ Selector.text word ]
)
ensurePanelsFocusable : List String -> TestContext -> TestContext
ensurePanelsFocusable words testContext =
testContext
|> ensureView
(Query.findAll [ Selector.attribute Role.tabPanel, Selector.attribute (Key.tabbable True) ]
>> Expect.all (List.indexedMap (\i w -> Query.index i >> Query.has [ Selector.text w ]) words)
)
ensurePanelDisplayed : String -> TestContext -> TestContext
ensurePanelDisplayed word testContext =
testContext
|> ensureView
(Query.find [ Selector.attribute Role.tabPanel, Selector.style "display" "block" ]
>> Query.has [ Selector.text word ]
)
ensureOnlyOnePanelDisplayed : List String -> TestContext -> TestContext
ensureOnlyOnePanelDisplayed panels testContext =
testContext
|> ensureView
(Query.findAll [ Selector.attribute Role.tabPanel, Selector.style "display" "block" ]
>> Query.count (Expect.equal 1)
)
|> ensureView
(Query.findAll [ Selector.attribute Role.tabPanel, Selector.style "display" "none" ]
>> Query.count (Expect.equal (List.length panels - 1))
)
ensureOnlyOneTabInSequence : List String -> TestContext -> TestContext
ensureOnlyOneTabInSequence tabs testContext =
testContext
|> ensureView
(Query.findAll [ Selector.attribute Role.tab, Selector.attribute (Key.tabbable True) ]
>> Query.count (Expect.equal 1)
)
|> ensureView
(Query.findAll [ Selector.attribute Role.tab, Selector.attribute (Key.tabbable False) ]
>> Query.count (Expect.equal (List.length tabs - 1))
)
releaseRightArrow : TestContext -> TestContext
releaseRightArrow =
KeyboardHelpers.releaseRightArrow { targetDetails = [] }
[ Selector.attribute Role.tab, Selector.attribute (Key.tabbable True) ]
releaseLeftArrow : TestContext -> TestContext
releaseLeftArrow =
KeyboardHelpers.releaseLeftArrow { targetDetails = [] }
[ Selector.attribute Role.tab, Selector.attribute (Key.tabbable True) ]
type alias State =
{ selected : Int
}
init : State
init =
{ selected = 0
}
type Msg
= FocusAndSelectTab { select : Int, focus : Maybe String }
| Focused (Result Dom.Error ())
update : Msg -> State -> State
update msg model =
case msg of
FocusAndSelectTab { select, focus } ->
Tuple.first
( { model | selected = select }
, focus
|> Maybe.map (Dom.focus >> Task.attempt Focused)
|> Maybe.withDefault Cmd.none
)
Focused error ->
Tuple.first ( model, Cmd.none )
view model =
Tabs.view
{ title = Nothing
, alignment = Tabs.Left
, customSpacing = Nothing
, focusAndSelect = FocusAndSelectTab
, selected = model.selected
, tabs =
[ Tabs.build { id = 0, idString = "tab-0" } [ Tabs.tabString "Tab 0", Tabs.panelHtml (text "Panel 0") ]
, Tabs.build { id = 1, idString = "tab-1" } [ Tabs.tabString "Tab 1", Tabs.panelHtml (text "Panel 1") ]
, Tabs.build { id = 2, idString = "tab-2" } [ Tabs.tabString "Tab 2", Tabs.panelHtml (text "Panel 2") ]
]
}
program : TestContext
program =
ProgramTest.createSandbox
{ init = init
, update = update
, view = view >> Html.toUnstyled
}
|> ProgramTest.start ()