## The basics
- [x] I [validated my changes](https://developers.google.com/blockly/guides/contribute/core#making_and_verifying_a_change)
## The details
### Resolves
Fixes#9155
### Proposed Changes
In cases when an ID is missing for an element passed to `FocusableTreeTraverser.findFocusableNodeFor()`, always return `null`.
Additionally, the new short-circuit logic exposed that `Toolbox` actually wasn't being set up correctly (that is, its root element was not being configured with a valid ID). This has been fixed.
### Reason for Changes
These are cases when a valid node should never be matched (and it's technically possible to incorrectly match if an `IFocusableNode` is set up incorrectly and is providing a focusable element with an unset ID). This avoids the extra computation time of potentially calling deep into `WorkspaceSvg` and exploring all possible nodes for an ID that should never match.
Note that there is a weird quirk with `null` IDs actually being the string `"null"`. This is a side effect of how `setAttribute` and attributes in general work with HTML elements. There's nothing really that can be done here, so it's now considered invalid to also have an ID of string `"null"` just to ensure the `null` case is properly short-circuited.
Finally, the issue with toolbox being configured incorrectly was discovered with the introducing of a new hard failure in `FocusManager.registerTree()` when a tree with an invalid root element is registered. From testing there are no other such trees that need to be updated.
A new warning was also added if `focusNode()` is used on a node with an element that has an invalid ID. This isn't a hard failure to follow the convention of other invalid `focusNode()` situations. It's much more fragile for `focusNode()` to throw than `registerTree()` since the former generally happens much earlier in a page lifecycle, and is less prone to dynamic behaviors.
### Test Coverage
New tests were added to validate the various empty ID cases for `FocusableTreeTraverser.findFocusableNodeFor()`, and to validate the new error check for `FocusManager.registerTree()`.
### Documentation
No new documentation should be needed.
### Additional Information
Nothing to add.
* refactor(build): Rename "package" gulp task (but not npm script) to "pack"
This is to avoid an issue due to "package" being a reserved word
in JavaScript, and therefore not a valid export identifier.
* refactor(build): Convert gulpfile.js from CJS to ESM.
* refactor(build): Convert scripts/gulpfiles/*.js from CJS to ESM
* fix(build): Fix eslint warning for @license tag in gulpfile.mjs
* chore(build): Remove unused imports
* fix(build): Fix incorrect import of gulp-gzip
* fix(build): Fix incorrect sourcemaps import reference
The order of the modifiers is not significant to Blockly but it's conventional
to say e.g. Cmd+Shift+Z. Following that order here means that UI like the
keyboard navigation shortcut dialog gets the correct order without having to
sort.
* refactor(interfaces): Use typeof ... === 'function' to test for methods
Testing for
'name' in object
or
obj.name !== undefined
only checks for the existence of the property (and in the latter
case that the property is not set to undefined). That's fine if
the interface specifies a property of indeterminate type, but in
the usual case that the interface member is a method we can do
one better and check to make sure the property's value is
callable.
* refactor(interfaces): Always check obj is not null/undefined
Since most type predicates take an argument of type any but then
check for the existence of certain properties, explicitly check
that the argument is not null or undefined (or check implicitly
by calling another type predicate that does so first, which
necessitates adding a few casts because tsc infers the type of
the argument too narrowly).
* fix(interfaces): Add missing check to hasBubble type predicate
This appears to have inadvertently been omitted in PR #9004.
* fix(interfaces): Fix misplaced typeof
* fix: Fix typos in JSDocs
* fix(tests): Make Mocks conform to corresponding interfaces
Introduce a new MockFocusable, and add methods to MockIcon,
MockBubbleIcon and MockComment, so that they fulfil the
IFocusableNode, IIcon, IHasBubble and ICommentIcon interfaces
respectively.
* chore(tests): Add assertions verifying mocks conform to predicates
Add (test) runtime assertions that:
- isFocusableNode(MockFocusable) returns true
- isIcon(MockIcon) returns true
- hasBubble(MockBubbleIcon) returns true
- isCommentIcon(MockCommentIcon) returns true
(The latter is currently failing because Blockly is undefined when
isCommentIcon calls the MockCommentIcon's getType method.)
* fix(tests): Don't rely on Blockly being set in Mock methods
For some reason the global Blockly binding is not visible at the
time when isCommentIcon calls MockCommentIcon's getType method,
and presumably this problem would apply to getBubbleSize too,
so directly import the required items.
* refactor(tests): Make MockCommentIcon a MockBubbleIcon
This slightly simplifies it and makes it less likely to accidentally
stop conforming to IHasBubble.
* fix(interfaces): Fix incorrect check in isSelectable
Fix an error which caused ISelectable instances to fail
isSelectable() checks, one of the results of which is that
Blockly.common.getSelected() would generally return null.
Whoops!
## The basics
- [x] I [validated my changes](https://developers.google.com/blockly/guides/contribute/core#making_and_verifying_a_change)
## The details
### Resolves
N/A (no tracking issue)
### Proposed Changes
Introduces a GitHub actions CI workflow to run the webdriver IO tests from https://github.com/google/blockly-keyboard-experimentation as part of core Blockly's CI.
### Reason for Changes
Since development on the plugin is going to continue for many months yet, this ensures that behavioral changes in core Blockly don't inadvertently break the plugin.
Note that this shouldn't be made a blocking workflow since there may be cases where it's necessary to break the plugin before a change to the plugin itself can be introduced to then fix it (as this has happened many times in the past). However, the CI check is forced signal to both author and reviewer as to whether their change affects the plugin without having to manually check the test suite.
### Test Coverage
N/A -- Verifying that the CI workflow runs is sufficient.
### Documentation
No documentation changes are needed here.
### Additional Information
Nothing.