web: fix flash of unstructured content, add tests for it (#11013)
* web: fix Flash of Unstructured Content while SearchSelect is loading from the backend Provide an alternative, readonly, disabled, unindexed input object with the text "Loading...", to be replaced with the _real_ input element after the content is loaded. This provides the correct appearance and spacing so the content doesn't jiggle about between the start of loading and the SearchSelect element being finalized. It was visually distracting and unappealing. * web: comment on state management in API layer, move file to point to correct component under test. * web: test for flash of unstructured content - Add a unit test to ensure the "Loading..." element is displayed correctly before data arrives - Demo how to mock a `fetchObjects()` call in testing. Very cool. - Make distinguishing rule sets for code, tests, and scripts in nightmare mode - In SearchSelect, Move the `styles()` declaration to the top of the class for consistency. - To test for the FLOUC issue in SearchSelect. This is both an exercise in mocking @beryju's `fetchObjects()` protocol, and shows how we can unit test generic components that render API objects.
This commit is contained in:
@ -0,0 +1,104 @@
|
||||
import { $, browser } from "@wdio/globals";
|
||||
import { slug } from "github-slugger";
|
||||
import { Key } from "webdriverio";
|
||||
|
||||
import { html, render } from "lit";
|
||||
|
||||
import "../ak-search-select-view.js";
|
||||
import { sampleData } from "../stories/sampleData.js";
|
||||
import { AkSearchSelectViewDriver } from "./ak-search-select-view.comp.js";
|
||||
|
||||
const longGoodForYouPairs = {
|
||||
grouped: false,
|
||||
options: sampleData.map(({ produce }) => [slug(produce), produce]),
|
||||
};
|
||||
|
||||
describe("Search select: Test Input Field", () => {
|
||||
let select: AkSearchSelectViewDriver;
|
||||
|
||||
beforeEach(async () => {
|
||||
await render(
|
||||
html`<ak-search-select-view .options=${longGoodForYouPairs}> </ak-search-select-view>`,
|
||||
document.body,
|
||||
);
|
||||
// @ts-ignore
|
||||
select = await AkSearchSelectViewDriver.build(await $("ak-search-select-view"));
|
||||
});
|
||||
|
||||
it("should open the menu when the input is clicked", async () => {
|
||||
expect(await select.open).toBe(false);
|
||||
expect(await select.menuIsVisible()).toBe(false);
|
||||
await select.clickInput();
|
||||
expect(await select.open).toBe(true);
|
||||
// expect(await select.menuIsVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it("should not open the menu when the input is focused", async () => {
|
||||
expect(await select.open).toBe(false);
|
||||
await select.focusOnInput();
|
||||
expect(await select.open).toBe(false);
|
||||
expect(await select.menuIsVisible()).toBe(false);
|
||||
});
|
||||
|
||||
it("should close the menu when the input is clicked a second time", async () => {
|
||||
expect(await select.open).toBe(false);
|
||||
expect(await select.menuIsVisible()).toBe(false);
|
||||
await select.clickInput();
|
||||
expect(await select.menuIsVisible()).toBe(true);
|
||||
expect(await select.open).toBe(true);
|
||||
await select.clickInput();
|
||||
expect(await select.open).toBe(false);
|
||||
expect(await select.open).toBe(false);
|
||||
});
|
||||
|
||||
it("should open the menu from a focused but closed input when a search is begun", async () => {
|
||||
expect(await select.open).toBe(false);
|
||||
await select.focusOnInput();
|
||||
expect(await select.open).toBe(false);
|
||||
expect(await select.menuIsVisible()).toBe(false);
|
||||
await browser.keys("A");
|
||||
expect(await select.open).toBe(true);
|
||||
expect(await select.menuIsVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it("should update the list as the user types", async () => {
|
||||
await select.focusOnInput();
|
||||
await browser.keys("Ap");
|
||||
expect(await select.menuIsVisible()).toBe(true);
|
||||
const elements = Array.from(await select.listElements());
|
||||
expect(elements.length).toBe(2);
|
||||
});
|
||||
|
||||
it("set the value when a match is close", async () => {
|
||||
await select.focusOnInput();
|
||||
await browser.keys("Ap");
|
||||
expect(await select.menuIsVisible()).toBe(true);
|
||||
const elements = Array.from(await select.listElements());
|
||||
expect(elements.length).toBe(2);
|
||||
await browser.keys(Key.Tab);
|
||||
expect(await (await select.input()).getValue()).toBe("Apples");
|
||||
});
|
||||
|
||||
it("should close the menu when the user clicks away", async () => {
|
||||
document.body.insertAdjacentHTML(
|
||||
"afterbegin",
|
||||
'<input id="a-separate-component" type="text" />',
|
||||
);
|
||||
const input = await browser.$("#a-separate-component");
|
||||
|
||||
await select.clickInput();
|
||||
expect(await select.open).toBe(true);
|
||||
await input.click();
|
||||
expect(await select.open).toBe(false);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await document.body.querySelector("#a-separate-component")?.remove();
|
||||
await document.body.querySelector("ak-search-select-view")?.remove();
|
||||
// @ts-expect-error expression of type '"_$litPart$"' is added by Lit
|
||||
if (document.body["_$litPart$"]) {
|
||||
// @ts-expect-error expression of type '"_$litPart$"' is added by Lit
|
||||
delete document.body["_$litPart$"];
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user