Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEI-5533: Re-enable select keyboard tests for Dropdown and Clickable #2420

Open
wants to merge 9 commits into
base: feature/dropdown-combobox
Choose a base branch
from

Conversation

marcysutton
Copy link
Member

@marcysutton marcysutton commented Jan 7, 2025

In working on WB-1799 for SingleSelect, I found a bunch of disabled tests that I started fixing to ensure keyboard interactions work. Fixing these tests required changes to Clickable, which is used in WB Dropdowns.

Issue: https://khanacademy.atlassian.net/browse/FEI-5533

PR highlights:

  1. Re-enables some keyboard tests that were disabled with userEvent@14
  2. Exposes a centralized keys object in wonder-blocks-core for use in wonder-blocks-clickable, wonder-blocks-dropdown, and any other modules that need it.
    1. Note: userEvent passes the literal key code string back, i.e. Space or space. I lower-cased the key names to make sure they match in the code. We could use linting to enforce this instead... I'm open to suggestions.
  3. Keeps two tests for SingleSelect disabled:
    1. "It should find and select an item using the keyboard": fixing this one broke other tests (the dropdown isn't open before typing so refs aren't populated, but explicitly opening it made filtering tests fail).
    2. "It should change the number of options after using the search filter" (Live Region test): this one fails for me when I enable it. I'll plan to revisit it as part of the Announcer implementation.

Test Plan

Run the tests using yarn test.

There is one pre-existing lint failure for me locally in expect-render-error.d.ts, but it seems unrelated to these changes.

userEvent@14 changed how keyboard events are handled, so they were failing to match things like `" "` or `32` for space key codes. `keyboard('{space}')` passes back a case-sensitive event name that must be matched specifically, like "Space" or "space". To make this work in ClickableBehavior, I centralized the keys into wonder-blocks-core so it could be reused in Dropdowns and elsewhere.

I also included a story with one of the unit test fixtures so I could compare headless testing to the browser.
Copy link

changeset-bot bot commented Jan 7, 2025

🦋 Changeset detected

Latest commit: 2ada9bd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 27 packages
Name Type
@khanacademy/wonder-blocks-clickable Major
@khanacademy/wonder-blocks-dropdown Major
@khanacademy/wonder-blocks-core Major
@khanacademy/wonder-blocks-accordion Patch
@khanacademy/wonder-blocks-button Patch
@khanacademy/wonder-blocks-cell Patch
@khanacademy/wonder-blocks-form Patch
@khanacademy/wonder-blocks-icon-button Patch
@khanacademy/wonder-blocks-link Patch
@khanacademy/wonder-blocks-pill Patch
@khanacademy/wonder-blocks-birthday-picker Patch
@khanacademy/wonder-blocks-banner Patch
@khanacademy/wonder-blocks-breadcrumbs Patch
@khanacademy/wonder-blocks-data Patch
@khanacademy/wonder-blocks-grid Patch
@khanacademy/wonder-blocks-icon Patch
@khanacademy/wonder-blocks-labeled-field Patch
@khanacademy/wonder-blocks-layout Patch
@khanacademy/wonder-blocks-modal Patch
@khanacademy/wonder-blocks-popover Patch
@khanacademy/wonder-blocks-progress-spinner Patch
@khanacademy/wonder-blocks-search-field Patch
@khanacademy/wonder-blocks-switch Patch
@khanacademy/wonder-blocks-testing Patch
@khanacademy/wonder-blocks-toolbar Patch
@khanacademy/wonder-blocks-tooltip Patch
@khanacademy/wonder-blocks-typography Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@khan-actions-bot khan-actions-bot requested a review from a team January 7, 2025 23:07
@khan-actions-bot
Copy link
Contributor

khan-actions-bot commented Jan 7, 2025

Gerald

Required Reviewers
  • @Khan/wonder-blocks for changes to .changeset/mean-cherries-press.md, __docs__/wonder-blocks-dropdown/single-select.accessibility.stories.tsx, packages/wonder-blocks-core/src/index.ts, packages/wonder-blocks-clickable/src/components/clickable-behavior.ts, packages/wonder-blocks-core/src/util/keys.ts, packages/wonder-blocks-dropdown/src/components/dropdown-core.tsx, packages/wonder-blocks-dropdown/src/components/option-item.tsx, packages/wonder-blocks-dropdown/src/components/select-opener.tsx, packages/wonder-blocks-dropdown/src/util/constants.ts, packages/wonder-blocks-clickable/src/components/__tests__/clickable-behavior.test.tsx, packages/wonder-blocks-dropdown/src/components/__tests__/action-menu.test.tsx, packages/wonder-blocks-dropdown/src/components/__tests__/combobox.test.tsx, packages/wonder-blocks-dropdown/src/components/__tests__/dropdown-core.test.tsx, packages/wonder-blocks-dropdown/src/components/__tests__/multi-select.test.tsx, packages/wonder-blocks-dropdown/src/components/__tests__/select-opener.test.tsx, packages/wonder-blocks-dropdown/src/components/__tests__/single-select.test.tsx

Don't want to be involved in this pull request? Comment #removeme and we won't notify you of further changes.

Copy link
Contributor

github-actions bot commented Jan 7, 2025

npm Snapshot: Published

🎉 Good news!! We've packaged up the latest commit from this PR (84fd008) and published all packages with changesets to npm.

You can install the packages in webapp by running:

./services/static/dev/tools/deploy_wonder_blocks.js --tag="PR2420"

Packages can also be installed manually by running:

yarn add @khanacademy/wonder-blocks-<package-name>@PR2420

Copy link
Contributor

github-actions bot commented Jan 7, 2025

A new build was pushed to Chromatic! 🚀

https://5e1bf4b385e3fb0020b7073c-agpotuhfru.chromatic.com/

Chromatic results:

Metric Total
Captured snapshots 383
Tests with visual changes 0
Total stories 529
Inherited (not captured) snapshots [TurboSnap] 0
Tests on the build 383

Copy link
Contributor

github-actions bot commented Jan 7, 2025

Size Change: +5 B (+0.01%)

Total Size: 98.3 kB

Filename Size Change
packages/wonder-blocks-clickable/dist/es/index.js 3.04 kB -21 B (-0.69%)
packages/wonder-blocks-core/dist/es/index.js 2.97 kB +66 B (+2.27%)
packages/wonder-blocks-dropdown/dist/es/index.js 19.1 kB -40 B (-0.21%)
ℹ️ View Unchanged
Filename Size
packages/wonder-blocks-accordion/dist/es/index.js 3.77 kB
packages/wonder-blocks-banner/dist/es/index.js 1.53 kB
packages/wonder-blocks-birthday-picker/dist/es/index.js 1.77 kB
packages/wonder-blocks-breadcrumbs/dist/es/index.js 887 B
packages/wonder-blocks-button/dist/es/index.js 4.12 kB
packages/wonder-blocks-cell/dist/es/index.js 2.01 kB
packages/wonder-blocks-data/dist/es/index.js 6.24 kB
packages/wonder-blocks-form/dist/es/index.js 6.2 kB
packages/wonder-blocks-grid/dist/es/index.js 1.36 kB
packages/wonder-blocks-icon-button/dist/es/index.js 2.95 kB
packages/wonder-blocks-icon/dist/es/index.js 871 B
packages/wonder-blocks-labeled-field/dist/es/index.js 1.94 kB
packages/wonder-blocks-layout/dist/es/index.js 1.82 kB
packages/wonder-blocks-link/dist/es/index.js 2.28 kB
packages/wonder-blocks-modal/dist/es/index.js 5.42 kB
packages/wonder-blocks-pill/dist/es/index.js 1.65 kB
packages/wonder-blocks-popover/dist/es/index.js 4.85 kB
packages/wonder-blocks-progress-spinner/dist/es/index.js 1.52 kB
packages/wonder-blocks-search-field/dist/es/index.js 1.36 kB
packages/wonder-blocks-switch/dist/es/index.js 1.92 kB
packages/wonder-blocks-testing-core/dist/es/index.js 3.74 kB
packages/wonder-blocks-testing/dist/es/index.js 1.07 kB
packages/wonder-blocks-theming/dist/es/index.js 693 B
packages/wonder-blocks-timing/dist/es/index.js 1.8 kB
packages/wonder-blocks-tokens/dist/es/index.js 2.36 kB
packages/wonder-blocks-toolbar/dist/es/index.js 905 B
packages/wonder-blocks-tooltip/dist/es/index.js 6.99 kB
packages/wonder-blocks-typography/dist/es/index.js 1.23 kB

compressed-size-action

Copy link
Contributor

@kevinb-khan kevinb-khan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for figuring out why our keyboard tests were broken. I left a few suggestions in the comments (nothing blocking).

Comment on lines 564 to 565
(triggerOnEnter && keyCode === keys.enter.toLowerCase()) ||
(triggerOnSpace && keyCode === keys.space.toLowerCase())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're normalizing the key name that we're getting from the event to be lowercase, why not have the constants in keys be lowercase to begin with?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. It would have to be normalized somewhere in the event of mixed casing. The tests already had lowercase key names in them, but our constants are in capital case...so it makes sense why they would fail to match. I could change the constants to all be lowercase, but that will require a lottttt of testing for every key event (Enter, Escape, ArrowDown, ArrowUp, etc.). I'm actually thinking I could just update these tests to use capital case and go with that. It might limit the scope of this a bit better!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: I did make some updates including re-enabling more tests! But I limited it to wonder-blocks-dropdown and wonder-blocks-clickable. There are still more in other packages that could be updated later!

packages/wonder-blocks-dropdown/src/util/constants.ts Outdated Show resolved Hide resolved
Copy link
Member

@beaesguerra beaesguerra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for diving into this, Marcy! Enabling the tests again can help build our confidence to new changes in our components, especially with these more complicated components 😄 I've left some comments and questions!

.changeset/mean-cherries-press.md Outdated Show resolved Hide resolved
@@ -8,7 +8,7 @@ import {ComboboxLabels} from "./types";
export const keys = {
escape: "Escape",
tab: "Tab",
space: " ",
space: "Space",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was running into similar-ish issues recently with key events and tests in PR: #2376 (comment) !

I ended up updating checks in DropdownCore for event.keyCode/event.which to event.key as well, since event.which or event.keyCode are deprecated. Testing keyboard interactions in tests weren't triggering the correct logic since we were using deprecated fields and user-event removed support for keyCode. I'm not sure if this is the same issue with all the other tests that were disabled though!

I also updated these constants based on the keyboard event key linked in the jsdocs: https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values. The expected key for space is documented to be " " so this may cause issues!

Copy link
Member Author

@marcysutton marcysutton Jan 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was weird that " " wasn't matching for a space any longer. I only changed it because userEvent passed back the key name, in mixed casing! I considered doing an OR statement so that either one would match. One of them would have to be named something else, though...probably the literal space " " since the rest are represented by key names (Escape, Space, etc.)?

Copy link
Member Author

@marcysutton marcysutton Jan 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the event object under test when passing userEvent.keyboard('{space}') as was written in these tests, with some irrelevant parts stripped out for brevity:

SyntheticBaseEvent {
      _reactName: 'onKeyDown',
      type: 'keydown',
      target: <ref *1> HTMLButtonElement {
        '__reactFiber$dkck3rhjopo': FiberNode {
          tag: 5,
          key: null,
          elementType: 'button',
          type: 'button',
        },
        '__reactProps$dkck3rhjopo': {
          'aria-label': undefined,
          'aria-selected': 'false',
          'aria-checked': undefined,
          role: 'option',
          'aria-current': undefined,
          children: [Object],
          'data-testid': undefined,
          onClick: [Function: handleClick],
          onMouseEnter: [Function: handleMouseEnter],
          onMouseLeave: [Function: handleMouseLeave],
          onMouseDown: [Function: handleMouseDown],
          onMouseUp: [Function: handleMouseUp],
          onTouchStart: [Function: handleTouchStart],
          onTouchEnd: [Function: handleTouchEnd],
          onTouchCancel: [Function: handleTouchCancel],
          onKeyDown: [Function: handleKeyDown],
          onKeyUp: [Function: handleKeyUp],
          onFocus: [Function: handleFocus],
          onBlur: [Function: handleBlur],
          tabIndex: undefined,
          rel: undefined,
          type: 'button',
          'aria-disabled': false,
          className: '',
          style: [Object]
        },
      currentTarget: <ref *1> HTMLButtonElement {
        '__reactFiber$dkck3rhjopo': FiberNode {
          tag: 5,
          key: null,
          elementType: 'button',
          type: 'button',
        },
      eventPhase: 3,
      bubbles: true,
      cancelable: true,
      timeStamp: 1736555344807,
      defaultPrevented: false,
      isTrusted: false,
      view: null,
      detail: 0,
      key: 'space',  // <----- this one!
      code: 'Unknown',
      location: 0,
      ctrlKey: false,
      shiftKey: false,
      altKey: false,
      metaKey: false,
      repeat: false,
      locale: undefined,
      getModifierState: [Function: modifierStateGetter],
      charCode: 0,
      keyCode: 0,
      which: 0,
      isDefaultPrevented: [Function: functionThatReturnsFalse],
      isPropagationStopped: [Function: functionThatReturnsFalse]
    }

I suppose the test would have to pass a literal space character to match on that? I was trying to get the existing tests to pass, and they had lowercase key names in them ('{space}')!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm I wonder if we need to update how we simulate the space press key event in our tests: testing-library/user-event#972 (comment) ({space} or {Space} isn't shown as an example)

Looking up {space} in the React Testing Library docs shows documentation for user events v13: https://testing-library.com/docs/user-event/v13/#special-characters so it could be related to why the tests broke after upgrading to v14!

By updating the tests, it will be more similar to what happens in the browser! Testing things out in Storybook, I found that the space key functionality in the Clickable example is not showing the pressed styles as expected since the browser sets the key to instead of Space:

Screen.Recording.2025-01-13.at.3.27.35.PM.mov

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch, Bea! This prompted me to check the tests again and we can fire the literal string space instead! I made some updates to use " " instead of "{Space}" and ClickableBehavior should work again.

1. Use core keys over wonder-blocks-dropdown constants
2. Use keyName over keyCode for key names
3. Use one assertion per test
4. Use CapitalCase event names to simplify code
Comment on lines 2 to 4
"@khanacademy/wonder-blocks-clickable": minor
"@khanacademy/wonder-blocks-dropdown": minor
"@khanacademy/wonder-blocks-core": minor
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to our thread about versioning in the other PR, would this also be a breaking change if consumer projects were relying on the event.which/event.keyCode functionality?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great question. I think yes, and this could be released along with the other breaking changes. So it's good timing!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, now I'm rethinking major on this and wondering if minor is more appropriate. The move to event.key is internal, and not part of the public API. Curious to hear your thoughts @beaesguerra!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like I marked the similar event.key change for the SelectOpener as a patch change 😅 I think it is fine that we don't mark it as major since it is internal. It would be good to double check these areas in current usage though just to be sure there wasn't functionality relying on that!

And since this would be released with the other combobox changes, it'll be part of the new major version as you mentioned!

@marcysutton
Copy link
Member Author

I did a bit of an audit as part of creating subtasks and found a few more tests that could be enabled! There are 5 outstanding tests in WB Dropdown that I've indicated in the subtask issue: https://khanacademy.atlassian.net/browse/FEI-6114

@marcysutton marcysutton changed the base branch from main to feature/dropdown-combobox January 16, 2025 23:35
Copy link
Member

@beaesguerra beaesguerra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good, thanks for fixing this issue and re-enabling a bunch of tests! 🎉

Will leave it up to you on the versioning since this will be combined with the other combobox changes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants