From 1bae7c6ce5f04df9b2565f76e91eef3a7e2998f0 Mon Sep 17 00:00:00 2001 From: alexisvisco Date: Sun, 3 May 2020 16:28:16 +0200 Subject: [PATCH 1/4] suggest(fix): add resetOnSelect when its an item create --- packages/select/src/components/query-list/queryList.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/select/src/components/query-list/queryList.tsx b/packages/select/src/components/query-list/queryList.tsx index 8ca6f29fe6..730cef9a2b 100644 --- a/packages/select/src/components/query-list/queryList.tsx +++ b/packages/select/src/components/query-list/queryList.tsx @@ -407,7 +407,9 @@ export class QueryList extends AbstractComponent2, IQueryL const item = Utils.safeInvoke(this.props.createNewItemFromQuery, query); if (item != null) { Utils.safeInvoke(this.props.onItemSelect, item, evt); - this.setQuery("", true); + if (this.props.resetOnSelect) { + this.setQuery("", true); + } } }; From 047e180f4b48deefad2610762a74e43fdce2939b Mon Sep 17 00:00:00 2001 From: alexisvisco Date: Mon, 11 May 2020 09:58:07 +0200 Subject: [PATCH 2/4] queryList: add maybeResetQuery function --- .../src/components/query-list/queryList.tsx | 14 +- packages/select/test/queryListTests.tsx | 508 ++++++++++-------- 2 files changed, 283 insertions(+), 239 deletions(-) diff --git a/packages/select/src/components/query-list/queryList.tsx b/packages/select/src/components/query-list/queryList.tsx index 730cef9a2b..4a459c014f 100644 --- a/packages/select/src/components/query-list/queryList.tsx +++ b/packages/select/src/components/query-list/queryList.tsx @@ -407,18 +407,14 @@ export class QueryList extends AbstractComponent2, IQueryL const item = Utils.safeInvoke(this.props.createNewItemFromQuery, query); if (item != null) { Utils.safeInvoke(this.props.onItemSelect, item, evt); - if (this.props.resetOnSelect) { - this.setQuery("", true); - } + this.maybeResetQuery() } }; private handleItemSelect = (item: T, event?: React.SyntheticEvent) => { this.setActiveItem(item); Utils.safeInvoke(this.props.onItemSelect, item, event); - if (this.props.resetOnSelect) { - this.setQuery("", true); - } + this.maybeResetQuery() }; private handlePaste = (queries: string[]) => { @@ -537,6 +533,12 @@ export class QueryList extends AbstractComponent2, IQueryL executeItemsEqual(this.props.itemsEqual, item, this.state.createNewItem), ); } + + private maybeResetQuery() { + if (this.props.resetOnSelect) { + this.setQuery("", true); + } + } } function pxToNumber(value: string | null) { diff --git a/packages/select/test/queryListTests.tsx b/packages/select/test/queryListTests.tsx index 4ae71425c9..63335b5e35 100644 --- a/packages/select/test/queryListTests.tsx +++ b/packages/select/test/queryListTests.tsx @@ -13,339 +13,381 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { assert } from "chai"; -import { mount, ReactWrapper, shallow } from "enzyme"; -import * as React from "react"; -import * as sinon from "sinon"; - +import { assert } from 'chai' +import { mount, ReactWrapper, shallow } from 'enzyme' +import * as React from 'react' +import * as sinon from 'sinon' // this is an awkward import across the monorepo, but we'd rather not introduce a cyclical dependency or create another package -import { IQueryListProps } from "@blueprintjs/select"; -import { IFilm, renderFilm, TOP_100_FILMS } from "../../docs-app/src/examples/select-examples/films"; +import { IQueryListProps } from '@blueprintjs/select' +import { IFilm, renderFilm, TOP_100_FILMS } from '../../docs-app/src/examples/select-examples/films' import { IQueryListRendererProps, IQueryListState, ItemListPredicate, ItemListRenderer, ItemPredicate, - QueryList, -} from "../src/index"; + QueryList +} from '../src/index' type FilmQueryListWrapper = ReactWrapper, IQueryListState>; -describe("", () => { - const FilmQueryList = QueryList.ofType(); +describe('', () => { + const FilmQueryList = QueryList.ofType() const testProps = { itemRenderer: sinon.spy(renderFilm), items: TOP_100_FILMS.slice(0, 20), onActiveItemChange: sinon.spy(), onItemSelect: sinon.spy(), - renderer: sinon.spy((props: IQueryListRendererProps) =>
{props.itemList}
), - }; + renderer: sinon.spy((props: IQueryListRendererProps) =>
{ props.itemList }
) + } beforeEach(() => { - testProps.itemRenderer.resetHistory(); - testProps.onActiveItemChange.resetHistory(); - testProps.onItemSelect.resetHistory(); - testProps.renderer.resetHistory(); - }); - - describe("items", () => { - it("handles controlled changes to the whole items list", () => { - const wrapper = shallow(); - const newItems = TOP_100_FILMS.slice(0, 1); - wrapper.setProps({ items: newItems }); - assert.deepEqual(wrapper.state("filteredItems"), newItems); - }); - }); - - describe("itemListRenderer", () => { + testProps.itemRenderer.resetHistory() + testProps.onActiveItemChange.resetHistory() + testProps.onItemSelect.resetHistory() + testProps.renderer.resetHistory() + }) + + describe('items', () => { + it('handles controlled changes to the whole items list', () => { + const wrapper = shallow() + const newItems = TOP_100_FILMS.slice(0, 1) + wrapper.setProps({ items: newItems }) + assert.deepEqual(wrapper.state('filteredItems'), newItems) + }) + }) + + describe('itemListRenderer', () => { const itemListRenderer: ItemListRenderer = props => ( -
    {props.items.map(props.renderItem)}
- ); - - it("renderItem calls itemRenderer", () => { - const wrapper = shallow(); - assert.lengthOf(wrapper.find("ul.foo"), 1, "should find element"); - assert.equal(testProps.itemRenderer.callCount, 20); - }); - }); - - describe("filtering", () => { - it("itemPredicate filters each item by query", () => { - const predicate = sinon.spy((query: string, film: IFilm) => film.year === +query); - shallow(); - - assert.equal(predicate.callCount, testProps.items.length, "called once per item"); - const { filteredItems } = testProps.renderer.args[0][0] as IQueryListRendererProps; - assert.lengthOf(filteredItems, 3, "returns only films from 1994"); - }); - - it("itemListPredicate filters entire list by query", () => { - const predicate = sinon.spy((query: string, films: IFilm[]) => films.filter(f => f.year === +query)); - shallow(); - - assert.equal(predicate.callCount, 1, "called once for entire list"); - const { filteredItems } = testProps.renderer.args[0][0] as IQueryListRendererProps; - assert.lengthOf(filteredItems, 3, "returns only films from 1994"); - }); - - it("prefers itemListPredicate if both are defined", () => { - const predicate = sinon.spy(() => true); - const listPredicate: ItemListPredicate = (_q, items) => items; - const listPredicateSpy = sinon.spy(listPredicate); +
    { props.items.map(props.renderItem) }
+ ) + + it('renderItem calls itemRenderer', () => { + const wrapper = shallow() + assert.lengthOf(wrapper.find('ul.foo'), 1, 'should find element') + assert.equal(testProps.itemRenderer.callCount, 20) + }) + }) + + describe('filtering', () => { + it('itemPredicate filters each item by query', () => { + const predicate = sinon.spy((query: string, film: IFilm) => film.year === +query) + shallow() + + assert.equal(predicate.callCount, testProps.items.length, 'called once per item') + const { filteredItems } = testProps.renderer.args[0][0] as IQueryListRendererProps + assert.lengthOf(filteredItems, 3, 'returns only films from 1994') + }) + + it('itemListPredicate filters entire list by query', () => { + const predicate = sinon.spy((query: string, films: IFilm[]) => films.filter(f => f.year === +query)) + shallow() + + assert.equal(predicate.callCount, 1, 'called once for entire list') + const { filteredItems } = testProps.renderer.args[0][0] as IQueryListRendererProps + assert.lengthOf(filteredItems, 3, 'returns only films from 1994') + }) + + it('prefers itemListPredicate if both are defined', () => { + const predicate = sinon.spy(() => true) + const listPredicate: ItemListPredicate = (_q, items) => items + const listPredicateSpy = sinon.spy(listPredicate) shallow( , - ); - assert.isTrue(listPredicateSpy.called, "listPredicate should be invoked"); - assert.isFalse(predicate.called, "item predicate should not be invoked"); - }); - - it("omitting both predicate props is supported", () => { - shallow(); - const { filteredItems } = testProps.renderer.args[0][0] as IQueryListRendererProps; - assert.lengthOf(filteredItems, testProps.items.length, "returns all films"); - }); - - it("ensure onActiveItemChange is not called with undefined and empty list", () => { - const myItem = { title: "Toy Story 3", year: 2010, rank: 1 }; - const filmQueryList = mount(); - filmQueryList.setState({ query: "query" }); - filmQueryList.setState({ activeItem: undefined }); - assert.equal(testProps.onActiveItemChange.callCount, 0); - }); - - it("ensure onActiveItemChange is not called updating props and query doesn't change", () => { - const myItem = { title: "Toy Story 3", year: 2010, rank: 1 }; + /> + ) + assert.isTrue(listPredicateSpy.called, 'listPredicate should be invoked') + assert.isFalse(predicate.called, 'item predicate should not be invoked') + }) + + it('omitting both predicate props is supported', () => { + shallow() + const { filteredItems } = testProps.renderer.args[0][0] as IQueryListRendererProps + assert.lengthOf(filteredItems, testProps.items.length, 'returns all films') + }) + + it('ensure onActiveItemChange is not called with undefined and empty list', () => { + const myItem = { title: 'Toy Story 3', year: 2010, rank: 1 } + const filmQueryList = mount() + filmQueryList.setState({ query: 'query' }) + filmQueryList.setState({ activeItem: undefined }) + assert.equal(testProps.onActiveItemChange.callCount, 0) + }) + + it('ensure onActiveItemChange is not called updating props and query doesn\'t change', () => { + const myItem = { title: 'Toy Story 3', year: 2010, rank: 1 } const props: IQueryListProps = { ...testProps, activeItem: myItem, - items: [myItem], - query: "", - }; - const filmQueryList: FilmQueryListWrapper = mount(); - filmQueryList.setProps(props); - assert.equal(testProps.onActiveItemChange.callCount, 0); - }); - - it("ensure activeItem changes on query change", () => { + items: [ myItem ], + query: '' + } + const filmQueryList: FilmQueryListWrapper = mount() + filmQueryList.setProps(props) + assert.equal(testProps.onActiveItemChange.callCount, 0) + }) + + it('ensure activeItem changes on query change', () => { const props: IQueryListProps = { ...testProps, - items: [TOP_100_FILMS[0]], - query: "abc", - }; - const filmQueryList: FilmQueryListWrapper = mount(); - assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[0]); + items: [ TOP_100_FILMS[0] ], + query: 'abc' + } + const filmQueryList: FilmQueryListWrapper = mount() + assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[0]) filmQueryList.setProps({ - items: [TOP_100_FILMS[1]], - query: "123", - }); - assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[1]); - }); + items: [ TOP_100_FILMS[1] ], + query: '123' + }) + assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[1]) + }) - it("ensure activeItem changes on when no longer in new items", () => { + it('ensure activeItem changes on when no longer in new items', () => { const props: IQueryListProps = { ...testProps, - items: [TOP_100_FILMS[0]], - query: "abc", - }; - const filmQueryList: FilmQueryListWrapper = mount(); - assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[0]); + items: [ TOP_100_FILMS[0] ], + query: 'abc' + } + const filmQueryList: FilmQueryListWrapper = mount() + assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[0]) filmQueryList.setProps({ - items: [TOP_100_FILMS[1]], - }); - assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[1]); - }); - }); - - describe("activeItem state initialization", () => { - it("initializes to first filtered item when uncontrolled", () => { + items: [ TOP_100_FILMS[1] ] + }) + assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[1]) + }) + }) + + describe('activeItem state initialization', () => { + it('initializes to first filtered item when uncontrolled', () => { const props: IQueryListProps = { ...testProps, // Filter down to only item at index 11, so item at index 11 should be // chosen as default activeItem itemPredicate: (_query, item) => item === TOP_100_FILMS[11], - query: "123", - }; - const filmQueryList: FilmQueryListWrapper = mount(); - assert(filmQueryList.state().activeItem === TOP_100_FILMS[11]); - }); + query: '123' + } + const filmQueryList: FilmQueryListWrapper = mount() + assert(filmQueryList.state().activeItem === TOP_100_FILMS[11]) + }) - it("initializes to controlled activeItem prop (non-null)", () => { + it('initializes to controlled activeItem prop (non-null)', () => { const props: IQueryListProps = { ...testProps, // List is not filtered, and item at index 11 is explicitly chosen as activeItem - activeItem: TOP_100_FILMS[11], - }; - const filmQueryList: FilmQueryListWrapper = mount(); - assert(filmQueryList.state().activeItem === TOP_100_FILMS[11]); - }); + activeItem: TOP_100_FILMS[11] + } + const filmQueryList: FilmQueryListWrapper = mount() + assert(filmQueryList.state().activeItem === TOP_100_FILMS[11]) + }) - it("initializes to controlled activeItem prop (null)", () => { + it('initializes to controlled activeItem prop (null)', () => { const props: IQueryListProps = { ...testProps, - activeItem: null, - }; - const filmQueryList: FilmQueryListWrapper = mount(); - assert(filmQueryList.state().activeItem === null); - }); - }); + activeItem: null + } + const filmQueryList: FilmQueryListWrapper = mount() + assert(filmQueryList.state().activeItem === null) + }) + }) - describe("scrolling", () => { - it("brings active item into view"); - }); + describe('scrolling', () => { + it('brings active item into view') + }) - describe("pasting", () => { - const onItemsPaste = sinon.spy(); + describe('pasting', () => { + const onItemsPaste = sinon.spy() const itemPredicate: ItemPredicate = (query: string, film: IFilm, _i?: number, exactMatch?: boolean) => { - return exactMatch === true ? query.toLowerCase() === film.title.toLowerCase() : true; - }; + return exactMatch === true ? query.toLowerCase() === film.title.toLowerCase() : true + } function mountForPasteTest(overrideProps: Partial> = {}) { // Placeholder. This will be overwritten by the mounted component. - let handlePaste: (queries: string[]) => void; + let handlePaste: (queries: string[]) => void const props: IQueryListProps = { ...testProps, itemPredicate, onItemsPaste, renderer: sinon.spy((listItemsProps: IQueryListRendererProps) => { - handlePaste = listItemsProps.handlePaste; - return testProps.renderer(listItemsProps); + handlePaste = listItemsProps.handlePaste + return testProps.renderer(listItemsProps) }), - ...overrideProps, - }; + ...overrideProps + } - const filmQueryList: FilmQueryListWrapper = mount(); + const filmQueryList: FilmQueryListWrapper = mount() // `handlePaste` will have been set by now, because `props.renderer` // will have been called. - return { filmQueryList, handlePaste: handlePaste! }; + return { filmQueryList, handlePaste: handlePaste! } } afterEach(() => { - onItemsPaste.resetHistory(); - }); + onItemsPaste.resetHistory() + }) - it("converts 1 pasted value into an item", () => { - const { filmQueryList, handlePaste } = mountForPasteTest(); + it('converts 1 pasted value into an item', () => { + const { filmQueryList, handlePaste } = mountForPasteTest() - const pastedValue = TOP_100_FILMS[0].title; - handlePaste([pastedValue]); + const pastedValue = TOP_100_FILMS[0].title + handlePaste([ pastedValue ]) - assert.isTrue(onItemsPaste.calledOnce); - assert.deepEqual(onItemsPaste.args[0][0], [TOP_100_FILMS[0]]); - assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[0]); - assert.deepEqual(filmQueryList.state().query, ""); - }); + assert.isTrue(onItemsPaste.calledOnce) + assert.deepEqual(onItemsPaste.args[0][0], [ TOP_100_FILMS[0] ]) + assert.deepEqual(filmQueryList.state().activeItem, TOP_100_FILMS[0]) + assert.deepEqual(filmQueryList.state().query, '') + }) - it("convert multiple pasted values into items", () => { - const { filmQueryList, handlePaste } = mountForPasteTest(); + it('convert multiple pasted values into items', () => { + const { filmQueryList, handlePaste } = mountForPasteTest() // Paste items in unsorted order for fun. - const item1 = TOP_100_FILMS[6]; - const item2 = TOP_100_FILMS[0]; - const item3 = TOP_100_FILMS[3]; + const item1 = TOP_100_FILMS[6] + const item2 = TOP_100_FILMS[0] + const item3 = TOP_100_FILMS[3] - const pastedValue1 = item1.title; - const pastedValue2 = item2.title; - const pastedValue3 = item3.title; + const pastedValue1 = item1.title + const pastedValue2 = item2.title + const pastedValue3 = item3.title - handlePaste([pastedValue1, pastedValue2, pastedValue3]); + handlePaste([ pastedValue1, pastedValue2, pastedValue3 ]) - assert.isTrue(onItemsPaste.calledOnce); + assert.isTrue(onItemsPaste.calledOnce) // Emits all three items. - assert.deepEqual(onItemsPaste.args[0][0], [item1, item2, item3]); + assert.deepEqual(onItemsPaste.args[0][0], [ item1, item2, item3 ]) // Highlight the last item pasted. - assert.deepEqual(filmQueryList.state().activeItem, item3); - assert.deepEqual(filmQueryList.state().query, ""); - }); + assert.deepEqual(filmQueryList.state().activeItem, item3) + assert.deepEqual(filmQueryList.state().query, '') + }) - it("concatenates unrecognized values into the ghost input by default", () => { - const { filmQueryList, handlePaste } = mountForPasteTest(); + it('concatenates unrecognized values into the ghost input by default', () => { + const { filmQueryList, handlePaste } = mountForPasteTest() - const item2 = TOP_100_FILMS[6]; - const item4 = TOP_100_FILMS[3]; + const item2 = TOP_100_FILMS[6] + const item4 = TOP_100_FILMS[3] - const pastedValue1 = "unrecognized1"; - const pastedValue2 = item2.title; - const pastedValue3 = "unrecognized2"; - const pastedValue4 = item4.title; + const pastedValue1 = 'unrecognized1' + const pastedValue2 = item2.title + const pastedValue3 = 'unrecognized2' + const pastedValue4 = item4.title - handlePaste([pastedValue1, pastedValue2, pastedValue3, pastedValue4]); + handlePaste([ pastedValue1, pastedValue2, pastedValue3, pastedValue4 ]) - assert.isTrue(onItemsPaste.calledOnce); + assert.isTrue(onItemsPaste.calledOnce) // Emits just the 2 valid items. - assert.deepEqual(onItemsPaste.args[0][0], [item2, item4]); + assert.deepEqual(onItemsPaste.args[0][0], [ item2, item4 ]) // Highlight the last item pasted. - assert.deepEqual(filmQueryList.state().activeItem, item4); - assert.deepEqual(filmQueryList.state().query, "unrecognized1, unrecognized2"); - }); + assert.deepEqual(filmQueryList.state().activeItem, item4) + assert.deepEqual(filmQueryList.state().query, 'unrecognized1, unrecognized2') + }) - it("creates new items out of unrecognized values if 'Create item' option is enabled", () => { - const createdRank = 0; - const createdYear = 2019; + it('creates new items out of unrecognized values if \'Create item\' option is enabled', () => { + const createdRank = 0 + const createdYear = 2019 const { filmQueryList, handlePaste } = mountForPasteTest({ // Must pass these two props to enable the "Create item" option. createNewItemFromQuery: query => ({ rank: createdRank, title: query, - year: createdYear, + year: createdYear }), - createNewItemRenderer: () =>
Create item
, - }); + createNewItemRenderer: () =>
Create item
+ }) - const item1 = TOP_100_FILMS[6]; - const item2 = TOP_100_FILMS[3]; + const item1 = TOP_100_FILMS[6] + const item2 = TOP_100_FILMS[3] - const pastedValue1 = item1.title; - const pastedValue2 = item2.title; + const pastedValue1 = item1.title + const pastedValue2 = item2.title // Paste this item last. - const pastedValue3 = "unrecognized"; + const pastedValue3 = 'unrecognized' - handlePaste([pastedValue1, pastedValue2, pastedValue3]); - const createdItem = { title: "unrecognized", rank: createdRank, year: createdYear }; + handlePaste([ pastedValue1, pastedValue2, pastedValue3 ]) + const createdItem = { title: 'unrecognized', rank: createdRank, year: createdYear } - assert.isTrue(onItemsPaste.calledOnce); + assert.isTrue(onItemsPaste.calledOnce) // Emits 2 existing items and 1 newly created item. - assert.deepEqual(onItemsPaste.args[0][0], [item1, item2, createdItem]); + assert.deepEqual(onItemsPaste.args[0][0], [ item1, item2, createdItem ]) // Highlight the last *already existing* item pasted. - assert.deepEqual(filmQueryList.state().activeItem, item2); - assert.deepEqual(filmQueryList.state().query, ""); - }); - }); - - describe("query", () => { - it("trims leading and trailing whitespace when creating new items", () => { - let triggerInputQueryChange: ((e: any) => void) | undefined; - const createNewItemFromQuerySpy = sinon.spy(); - const createNewItemRendererSpy = sinon.spy(); + assert.deepEqual(filmQueryList.state().activeItem, item2) + assert.deepEqual(filmQueryList.state().query, '') + }) + }) + + describe('query', () => { + it('trims leading and trailing whitespace when creating new items', () => { + let triggerInputQueryChange: ((e: any) => void) | undefined + const createNewItemFromQuerySpy = sinon.spy() + const createNewItemRendererSpy = sinon.spy() // we must supply our own renderer so that we can hook into IQueryListRendererProps#handleQueryChange const renderer = sinon.spy((props: IQueryListRendererProps) => { - triggerInputQueryChange = props.handleQueryChange; - return
{props.itemList}
; - }); + triggerInputQueryChange = props.handleQueryChange + return
{ props.itemList }
+ }) shallow( , + { ...testProps } + renderer={ renderer } + createNewItemFromQuery={ createNewItemFromQuerySpy } + createNewItemRenderer={ createNewItemRendererSpy } + /> + ) + + const untrimmedQuery = ' foo ' + const trimmedQuery = untrimmedQuery.trim() + + assert.isDefined(triggerInputQueryChange, 'query list should render with input change callbacks') + triggerInputQueryChange!({ target: { value: untrimmedQuery } }) + assert.isTrue(createNewItemFromQuerySpy.calledWith(trimmedQuery)) + assert.isTrue(createNewItemRendererSpy.calledWith(trimmedQuery)) + }) + + it('resets the query after creating new item if resetOnSelect=true', () => { + const onQueryChangeSpy = runResetOnSelectTest(true) + assert.isTrue(onQueryChangeSpy.calledWith('')) + }) + + it('does not reset the query after creating new item if resetOnSelect=false', () => { + const onQueryChangeSpy = runResetOnSelectTest(false) + assert.isTrue(onQueryChangeSpy.notCalled) + }) + + function runResetOnSelectTest(resetOnSelect: boolean): sinon.SinonSpy { + let triggerItemCreate: ((e: any) => void) | undefined + const onQueryChangeSpy = sinon.spy() + // supply a custom renderer so we can hook into handleClick and invoke it ourselves later + const createNewItemRenderer = sinon.spy( + (_query: string, _active: boolean, handleClick: React.MouseEventHandler) => { + triggerItemCreate = handleClick + return
+ } + ) + const queryList = shallow( + ({ title: 'irrelevant', rank: 0, year: 0 }) } + createNewItemRenderer={ createNewItemRenderer } + onQueryChange={ onQueryChangeSpy } + resetOnSelect={ resetOnSelect } + /> ); - const untrimmedQuery = " foo "; - const trimmedQuery = untrimmedQuery.trim(); + // Change the query to something non-empty so we can ensure it wasn't cleared. + // Ignore this change in the spy. + (queryList.instance() as QueryList).setQuery('some query') + onQueryChangeSpy.resetHistory() + + assert.isDefined(triggerItemCreate, 'query list should pass click handler to createNewItemRenderer') + triggerItemCreate!({}) - assert.isDefined(triggerInputQueryChange, "query list should render with input change callbacks"); - triggerInputQueryChange!({ target: { value: untrimmedQuery } }); - assert.isTrue(createNewItemFromQuerySpy.calledWith(trimmedQuery)); - assert.isTrue(createNewItemRendererSpy.calledWith(trimmedQuery)); - }); - }); -}); + return onQueryChangeSpy + } + }) +}) From 2e8f35471f8cef62a322d75fc5dc819b7d2c46c1 Mon Sep 17 00:00:00 2001 From: alexisvisco Date: Mon, 11 May 2020 10:07:50 +0200 Subject: [PATCH 3/4] select(queryListTests): fix eslint error due to "Lambdas are forbidden in JSX attributes" --- packages/select/test/queryListTests.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/select/test/queryListTests.tsx b/packages/select/test/queryListTests.tsx index 63335b5e35..2e13d949ef 100644 --- a/packages/select/test/queryListTests.tsx +++ b/packages/select/test/queryListTests.tsx @@ -372,7 +372,9 @@ describe('', () => { ({ title: 'irrelevant', rank: 0, year: 0 }) } + createNewItemFromQuery={ function () { + return ({ title: 'irrelevant', rank: 0, year: 0 }) + } } createNewItemRenderer={ createNewItemRenderer } onQueryChange={ onQueryChangeSpy } resetOnSelect={ resetOnSelect } From 799a1f2070b4d3ecf83b0adb868b92a1f3fa5c8c Mon Sep 17 00:00:00 2001 From: Adi Dahiya Date: Thu, 11 Jun 2020 15:52:45 -0400 Subject: [PATCH 4/4] yarn format --- packages/select/src/components/query-list/queryList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/select/src/components/query-list/queryList.tsx b/packages/select/src/components/query-list/queryList.tsx index 7c52bba04e..a7c09230b4 100644 --- a/packages/select/src/components/query-list/queryList.tsx +++ b/packages/select/src/components/query-list/queryList.tsx @@ -422,14 +422,14 @@ export class QueryList extends AbstractComponent2, IQueryL const item = Utils.safeInvoke(this.props.createNewItemFromQuery, query); if (item != null) { Utils.safeInvoke(this.props.onItemSelect, item, evt); - this.maybeResetQuery() + this.maybeResetQuery(); } }; private handleItemSelect = (item: T, event?: React.SyntheticEvent) => { this.setActiveItem(item); Utils.safeInvoke(this.props.onItemSelect, item, event); - this.maybeResetQuery() + this.maybeResetQuery(); }; private handlePaste = (queries: string[]) => {