From 193dbfc339e090c5a32550052943028bd77fa606 Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 7 Feb 2023 16:24:06 -0700 Subject: [PATCH] Et2Select: Fix some search weirdness - Search didn't start until 1 character more than expected - Search didn't happen on enter because the et2-searchbox inside stopped the key event from bubbling --- api/js/etemplate/Et2Select/SearchMixin.ts | 10 +- .../Et2Select/test/SearchActions.test.ts | 93 +++++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/api/js/etemplate/Et2Select/SearchMixin.ts b/api/js/etemplate/Et2Select/SearchMixin.ts index afc60a37ce..1b0f3e3cc8 100644 --- a/api/js/etemplate/Et2Select/SearchMixin.ts +++ b/api/js/etemplate/Et2Select/SearchMixin.ts @@ -434,12 +434,12 @@ export const Et2WithSearchMixin = >(superclass } // I can't figure out how to get this full width via CSS return html` - + > ${edit} `; } @@ -882,6 +882,7 @@ export const Et2WithSearchMixin = >(superclass { return this.handleKeyDown(event); } + event.stopPropagation(); // Don't allow event to bubble or it will interact with select event.stopImmediatePropagation(); @@ -913,7 +914,8 @@ export const Et2WithSearchMixin = >(superclass } // Start the search automatically if they have enough letters - if(this._searchInputNode.value.length >= Et2WidgetWithSearch.MIN_CHARS) + // -1 because we're in keyDown handler, and value is from _before_ this key was pressed + if(this._searchInputNode.value.length >= Et2WidgetWithSearch.MIN_CHARS - 1) { this._searchTimeout = window.setTimeout(() => {this.startSearch()}, Et2WidgetWithSearch.SEARCH_TIMEOUT); } diff --git a/api/js/etemplate/Et2Select/test/SearchActions.test.ts b/api/js/etemplate/Et2Select/test/SearchActions.test.ts index 652dede4c7..2b2f4d683f 100644 --- a/api/js/etemplate/Et2Select/test/SearchActions.test.ts +++ b/api/js/etemplate/Et2Select/test/SearchActions.test.ts @@ -7,6 +7,9 @@ import {assert, elementUpdated, fixture, html} from '@open-wc/testing'; import * as sinon from 'sinon'; import {Et2Box} from "../../Layout/Et2Box/Et2Box"; import {Et2Select} from "../Et2Select"; +import {Et2Textbox} from "../../Et2Textbox/Et2Textbox"; + +let keep_import : Et2Textbox = new Et2Textbox(); // Stub global egw for cssImage to find // @ts-ignore @@ -20,6 +23,7 @@ window.egw = { let parser = new window.DOMParser(); let container : Et2Box; + const options = [ {value: "1", label: "Option 1"}, {value: "2", label: "Option 2"} @@ -75,4 +79,93 @@ describe("Search actions", () => // For some reason in the test change gets called twice, even though in normal operation it gets called once. sinon.assert.called(change); }); +}) + +describe("Trigger search", () => +{ + + let element : Et2Select; + let clock; + + // Setup run before each test + beforeEach(async() => + { + // Mess with time + clock = sinon.useFakeTimers() + + // Create an element to test with, and wait until it's ready + // @ts-ignore + element = await fixture(html` + + One + Two + Three + Four + Five + Six + Seven + + `); + // Stub egw() + sinon.stub(element, "egw").returns(window.egw); + + await element.updateComplete; + await element._searchInputNode.updateComplete; + }); + + afterEach(() => + { + clock.restore(); + }) + + it("Searches after 2 characters", () => + { + + // Set up spy + let searchSpy = sinon.spy(element, "startSearch"); + + // Send two keypresses, but we need to explicitly set the value + element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "o"})); + element._searchInputNode.value = "o"; + assert(searchSpy.notCalled); + element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "n"})); + element._searchInputNode.value = "on"; + assert(searchSpy.notCalled); + + // Skip the timeout + clock.runAll(); + + assert(searchSpy.calledOnce, "startSearch() was not called"); + + }); + + it("Searches on enter", () => + { + // Set up spy + let searchSpy = sinon.spy(element, "startSearch"); + + // Send two keypresses, but we need to explicitly set the value + element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "o"})); + element._searchInputNode.value = "t"; + assert(searchSpy.notCalled); + element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "Enter"})); + + // Search starts immediately + assert(searchSpy.calledOnce, "startSearch() was not called"); + }); + + it("Aborts search when escape pressed", () => + { + // Set up spy + let abortSpy = sinon.spy(element, "_handleSearchAbort"); + let searchSpy = sinon.spy(element, "startSearch"); + + // Send two keypresses, but we need to explicitly set the value + element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "t"})); + element._searchInputNode.value = "t"; + element._searchInputNode.dispatchEvent(new KeyboardEvent("keydown", {"key": "Escape"})); + + assert(searchSpy.notCalled, "startSearch() was called"); + assert(abortSpy.calledOnce, "_handleSearchAbort() was not called"); + }) }); \ No newline at end of file