In [some cases][1], text editing utilities re-focus the `<input />` element during a blur event. This causes an unusual sequence of `focusin` and `focusout` events, leading to the engine sending unintended events.
Consider the following HTML code:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="container">
<input type="" value="1" id="input1">
<input type="" value="2" id="input2">
<input type="" value="3" id="input3">
</div>
<script>
container.addEventListener('focusin', (ev) => {
console.log('focusin: focus was gained by', ev.target);
});
container.addEventListener('focusout', (ev) => {
console.log('focusout: focus is leaving', ev.target, 'and it will go to', ev.relatedTarget);
});
</script>
</body>
</html>
```
Clicking input1, then input2, then input3 produces the following console logs:
```
// Input1 is clicked
focusin: focus was gained by <input type value=â"1" id=â"input1">â
// Input2 is clicked
focusout: focus is leaving <input type value=â"1" id=â"input1">â and it will go to <input type value=â"2" id=â"input2">â
focusin: focus was gained by <input type value=â"2" id=â"input2">â
// Input3 is clicked
focusout: focus is leaving <input type value=â"2" id=â"input2">â and it will go to <input type value=â"3" id=â"input3">â
focusin: focus was gained by <input type value=â"3" id=â"input3">â
```
Now, let's add a blur handler that changes focus:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="container">
<input type="" value="1" id="input1">
<input type="" value="2" id="input2">
<input type="" value="3" id="input3">
</div>
<script>
container.addEventListener('focusin', (ev) => {
console.log('focusin: focus was gained by', ev.target);
});
container.addEventListener('focusout', (ev) => {
console.log('focusout: focus is leaving', ev.target, 'and it will go to', ev.relatedTarget);
});
input2.addEventListener('blur', (ev) => {
input2.focus();
});
</script>
</body>
</html>
```
The log sequence changes and gives the wrong impression that no dom element has focus:
```
// Input1 is clicked
focusin: focus was gained by <input type value=â"1" id=â"input1">â
// Input2 is clicked
focusout: focus is leaving <input type value=â"1" id=â"input1">â and it will go to <input type value=â"2" id=â"input2">â
focusin: focus was gained by <input type value=â"2" id=â"input2">â
// Input3 is clicked, but the handler kicks in and instead of the following line being a focusout, it results in a focusin call first.
focusin: focus was gained by <input type value=â"2" id=â"input2">â
focusout: focus is leaving <input type value=â"2" id=â"input2">â and it will go to null
```
In addition to that, during `focusout` processing, `activeElement` typically points to `<body />`. However, if an element is focused during a `blur` event, `activeElement` points to that focused element. Although, undocumented it can be verified with:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="container">
<input type="" value="1" id="input1">
<input type="" value="2" id="input2">
<input type="" value="3" id="input3">
</div>
<script>
container.addEventListener('focusin', (ev) => {
console.log('focusin: was gained by', ev.target);
});
container.addEventListener('focusout', (ev) => {
console.log('document.hasFocus()', document.hasFocus());
console.log('document.activeElement', document.activeElement);
console.log('focusout: focus is leaving', ev.target, 'and it will go to', ev.relatedTarget);
});
input2.addEventListener('blur', (ev) => {
input2.focus();
});
</script>
</body>
</html>
```
We leverage these behaviors to ignore `focusout` events when the document has focus but `activeElement` is not `<body />`.
https://github.com/flutter/flutter/issues/153022
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
...............................................................................
Flutter Web Engine Test Suites
The flutter engine unit tests can be run with a number of different
configuration options that affect both compile time and run time. The
permutations of these options are specified in the felt_config.yaml file that
is colocated with this README. Here is an overview of the way the test suite
configurations are structured:
compile-configs
Specifies how the tests should be compiled. Each compile config specifies the following:
name- The name of the compile configuration.compiler- What compiler is used to compile the tests. Currently we supportdart2jsanddart2wasmas values.renderer- Which renderer to use when compiling the tests. Currently we supporthtml,canvaskit, andskwasm.
test-sets
A group of files that contain unit tests. Each test set specifies the following:
name- The name of the test set.directory- The name of the directory underflutter/lib/web_ui/testthat contains all the test files.
test-bundles
Specifies a group of tests and a compile configuration of those tests. The output
of the test bundles appears in flutter/lib/web_ui/build/test_bundles/<name>
where <name> is replaced by the name of the bundle. Each test bundle may be used
by multiple test suites. Each test bundle specifies the following:
name- The name of the test bundle.test-set- The name of the test set that contains the tests to be compiled.compile-config- The name of the compile configuration to use.
run-configs
Specifies the test environment that should be provided to a unit test. Each run config specifies the following:
name- Name of the run configuration.browser- The browser with which to run the tests. Valid values for this arechrome,firefox,safarioredge.canvaskit-variant- An optionally supplied argument that forces the tests to use a particular variant of CanvasKit, eitherfullorchromium. If none is specified, the engine will select the variant based on its normal selection logic.
test-suites
This is a fully specified run of a group of unit tests. They specify the following:
name- Name of the test suite.test-bundle- Which compiled test bundle to use when running the suite.run-config- Which run configuration to use when runnin the tests.artifact-deps- Which gn/ninja build artifacts are needed to run the suite. Valid values arecanvaskit,canvaskit_chromiumorskwasm.