diff --git a/superset-frontend/src/components/Select/Select.stories.tsx b/superset-frontend/src/components/Select/Select.stories.tsx index d64eb78a4..204ebff80 100644 --- a/superset-frontend/src/components/Select/Select.stories.tsx +++ b/superset-frontend/src/components/Select/Select.stories.tsx @@ -18,7 +18,7 @@ */ import React, { ReactNode, useState, useCallback } from 'react'; import ControlHeader from 'src/explore/components/ControlHeader'; -import Select, { SelectProps, OptionsTypePage } from './Select'; +import Select, { SelectProps, OptionsTypePage, OptionsType } from './Select'; export default { title: 'Select', @@ -27,7 +27,7 @@ export default { const DEFAULT_WIDTH = 200; -const options = [ +const options: OptionsType = [ { label: 'Such an incredibly awesome long long label', value: 'Such an incredibly awesome long long label', @@ -147,13 +147,42 @@ const mountHeader = (type: String) => { return header; }; -export const InteractiveSelect = (args: SelectProps & { header: string }) => ( +const generateOptions = (opts: OptionsType, count: number) => { + let generated = opts.slice(); + let iteration = 0; + while (generated.length < count) { + iteration += 1; + generated = generated.concat( + // eslint-disable-next-line no-loop-func + generated.map(({ label, value }) => ({ + label: `${label} ${iteration}`, + value: `${value} ${iteration}`, + })), + ); + } + return generated.slice(0, count); +}; + +export const InteractiveSelect = ({ + header, + options, + optionsCount, + ...args +}: SelectProps & { header: string; optionsCount: number }) => (
-
); @@ -170,6 +199,12 @@ InteractiveSelect.args = { InteractiveSelect.argTypes = { ...ARG_TYPES, + optionsCount: { + defaultValue: options.length, + control: { + type: 'number', + }, + }, header: { defaultValue: 'none', description: `It adds a header on top of the Select. Can be any ReactNode.`, diff --git a/superset-frontend/src/components/Select/Select.test.tsx b/superset-frontend/src/components/Select/Select.test.tsx index c23f57d52..15489c14e 100644 --- a/superset-frontend/src/components/Select/Select.test.tsx +++ b/superset-frontend/src/components/Select/Select.test.tsx @@ -46,6 +46,9 @@ const OPTIONS = [ { label: 'Irfan', value: 18, gender: 'Male' }, { label: 'George', value: 19, gender: 'Male' }, { label: 'Ashfaq', value: 20, gender: 'Male' }, + { label: 'Herme', value: 21, gender: 'Male' }, + { label: 'Cher', value: 22, gender: 'Female' }, + { label: 'Her', value: 23, gender: 'Male' }, ].sort((option1, option2) => option1.label.localeCompare(option2.label)); const loadOptions = async (search: string, page: number, pageSize: number) => { @@ -111,9 +114,21 @@ test('displays a header', async () => { }); test('adds a new option if the value is not in the options', async () => { - render(, + ); await open(); expect(await findSelectOption(OPTIONS[0].label)).toBeInTheDocument(); + + rerender( + ); + await type('Her'); + const options = await findAllSelectOptions(); + expect(options.length).toBe(4); + expect(options[0]?.textContent).toEqual('Her'); + expect(options[1]?.textContent).toEqual('Herme'); + expect(options[2]?.textContent).toEqual('Cher'); + expect(options[3]?.textContent).toEqual('Guilherme'); +}); + test('ignores case when searching', async () => { render(, + ); + await type('Ac'); + const options = await findAllSelectOptions(); + expect(options.length).toBe(4); + expect(options[0]?.textContent).toEqual('acbc'); + expect(options[1]?.textContent).toEqual('CAc'); + expect(options[2]?.textContent).toEqual('abac'); + expect(options[3]?.textContent).toEqual('Cac'); +}); + test('ignores special keys when searching', async () => { render(