diff --git a/e2e/base/fields/CheckPicker.spec.tsx b/e2e/base/fields/CheckPicker.spec.tsx index 2caa133be..b0f3bedf7 100644 --- a/e2e/base/fields/CheckPicker.spec.tsx +++ b/e2e/base/fields/CheckPicker.spec.tsx @@ -39,191 +39,191 @@ function CheckPickerStory({ value, ...otherProps }: CheckPickerProps) { ) } -Object.keys(OPTIONS_TYPES).forEach(optionType => { - context(`With ${optionType} options`, () => { - const options = OPTIONS_TYPES[optionType] - const commonProps: CheckPickerProps = { - label: 'A check picker', - name: 'myCheckPicker', - options, - ...(optionType === 'object' - ? { - optionValueKey: 'name' as any - } - : {}) - } +describe('fields/CheckPicker', () => { + Object.keys(OPTIONS_TYPES).forEach(optionType => { + context(`With ${optionType} options`, () => { + const options = OPTIONS_TYPES[optionType] + const commonProps: CheckPickerProps = { + label: 'A check picker', + name: 'myCheckPicker', + options, + ...(optionType === 'object' + ? { + optionValueKey: 'name' as any + } + : {}) + } - it('Should fill, change and clear the check picker', () => { - mountAndWait( - - - - ) + it('Should fill, change and clear the check picker', () => { + mountAndWait( + + + + ) - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A check picker', [options[0].label]) + cy.fill('A check picker', [options[0].label]) - outputShouldBe([options[0].value]) + outputShouldBe([options[0].value]) - cy.fill('A check picker', [options[1].label, options[2].label]) + cy.fill('A check picker', [options[1].label, options[2].label]) - outputShouldBe([options[1].value, options[2].value]) + outputShouldBe([options[1].value, options[2].value]) - cy.fill('A check picker', undefined) + cy.fill('A check picker', undefined) - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it(`Should fill, change and clear the check picker with \`value={[${JSON.stringify(options[2].value)}]\``, () => { - mountAndWait( - - - - ) + it('Should fill, change and clear the check picker with `value`', () => { + mountAndWait( + + + + ) - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A check picker', [options[0].label]) + cy.fill('A check picker', [options[0].label]) - outputShouldBe([options[0].value]) + outputShouldBe([options[0].value]) - cy.fill('A check picker', [options[1].label, options[2].label]) + cy.fill('A check picker', [options[1].label, options[2].label]) - outputShouldBe([options[1].value, options[2].value]) + outputShouldBe([options[1].value, options[2].value]) - cy.fill('A check picker', undefined) + cy.fill('A check picker', undefined) - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it('Should fill the check picker with `isLabelHidden`', () => { - mountAndWait( - - - - ) + it('Should fill the check picker with `isLabelHidden`', () => { + mountAndWait( + + + + ) - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A check picker', [options[0].label]) + cy.fill('A check picker', [options[0].label]) - outputShouldBe([options[0].value]) - }) + outputShouldBe([options[0].value]) + }) - it('Should fill the check picker with `searcheable`', () => { - mountAndWait( - - - - ) + it('Should fill the check picker with `searcheable`', () => { + mountAndWait( + + + + ) - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A check picker', [options[0].label]) + cy.fill('A check picker', [options[0].label]) - outputShouldBe([options[0].value]) + outputShouldBe([options[0].value]) - cy.fill('A check picker', [options[1].label, options[2].label]) + cy.fill('A check picker', [options[1].label, options[2].label]) - outputShouldBe([options[1].value, options[2].value]) - }) + outputShouldBe([options[1].value, options[2].value]) + }) - it('Should NOT call `onChange(undefined)` with `disabled`', () => { - mountAndWait( - - - - ) + it('Should NOT call `onChange(undefined)` with `disabled`', () => { + mountAndWait( + + + + ) - outputShouldNotBe() - }) + outputShouldNotBe() + }) - it(`Should NOT call \`onChange(undefined)\` with \`disabled value={[${JSON.stringify(options[2].value)}]\``, () => { - mountAndWait( - - - - ) + it('Should NOT call `onChange(undefined)` with `disabled value`', () => { + mountAndWait( + + + + ) - outputShouldNotBe() - }) + outputShouldNotBe() + }) - it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { - mountAndWait( - - - - ) + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { + mountAndWait( + + + + ) - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it(`Should call \`onChange(undefined)\` with \`disabled isUndefinedWhenDisabled value={[${JSON.stringify( - options[2].value - )}]\``, () => { - mountAndWait( - - - - ) + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled value`', () => { + mountAndWait( + + + + ) - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it('Should filter and select the expected options when using `customSearch`', () => { - const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) + it('Should filter and select the expected options when using `customSearch`', () => { + const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) - mountAndWait( - - - - ) + mountAndWait( + + + + ) - outputShouldNotBe() + outputShouldNotBe() - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('la remie') - cy.get('.rs-picker-popup').find('[role="option"]').first().click() - cy.clickOutside() + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('la remie') + cy.get('.rs-picker-popup').find('[role="option"]').first().click() + cy.clickOutside() - outputShouldBe([options[0].value]) + outputShouldBe([options[0].value]) - // Clear the CheckPicker - cy.fill('A check picker', undefined) + // Clear the CheckPicker + cy.fill('A check picker', undefined) - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('la option') - cy.get('.rs-picker-popup').find('[role="option"]').first().click() - cy.clickOutside() + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('la option') + cy.get('.rs-picker-popup').find('[role="option"]').first().click() + cy.clickOutside() - outputShouldBe([options[0].value]) + outputShouldBe([options[0].value]) - // Clear the CheckPicker - cy.fill('A check picker', undefined) + // Clear the CheckPicker + cy.fill('A check picker', undefined) - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('sêcôndÈ') - cy.get('.rs-picker-popup').find('[role="option"]').first().click() - cy.clickOutside() + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('sêcôndÈ') + cy.get('.rs-picker-popup').find('[role="option"]').first().click() + cy.clickOutside() - outputShouldBe([options[1].value]) - }) - it('Should fill, clear and get all list', () => { - const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) - mountAndWait( - - - - ) + outputShouldBe([options[1].value]) + }) + it('Should fill, clear and get all list', () => { + const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) + mountAndWait( + + + + ) - outputShouldNotBe() + outputShouldNotBe() - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('sêc') - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('{backspace}{backspace}{backspace}') + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('sêc') + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('{backspace}{backspace}{backspace}') - cy.get('.rs-picker-check-menu').find('[role="option"]').should('have.length', 3) + cy.get('.rs-picker-check-menu').find('[role="option"]').should('have.length', 3) + }) }) }) }) diff --git a/e2e/base/fields/MultiCascader.spec.tsx b/e2e/base/fields/MultiCascader.spec.tsx new file mode 100644 index 000000000..5ee0d81ea --- /dev/null +++ b/e2e/base/fields/MultiCascader.spec.tsx @@ -0,0 +1,151 @@ +import { useState } from 'react' + +import { Output } from '../../../.storybook/components/Output' +import { StoryBox } from '../../../.storybook/components/StoryBox' +import { + FAKE_NUMBER_TREE_OPTIONS, + FAKE_OBJECT_TREE_OPTIONS, + FAKE_STRING_TREE_OPTIONS +} from '../../../__mocks__/fake_tree_options' +import { type MultiCascaderProps, MultiCascader, useFieldControl } from '../../../src' +import { mountAndWait, outputShouldBe, outputShouldNotBe } from '../utils' + +/* eslint-disable sort-keys-fix/sort-keys-fix */ +const OPTIONS_TYPES = { + string: FAKE_STRING_TREE_OPTIONS, + number: FAKE_NUMBER_TREE_OPTIONS, + object: FAKE_OBJECT_TREE_OPTIONS +} +/* eslint-enable sort-keys-fix/sort-keys-fix */ + +describe('fields/MultiCascader', () => { + function MultiCascaderStory({ value, ...otherProps }: MultiCascaderProps) { + const [outputValue, setOutputValue] = useState('∅') + + const { controlledOnChange, controlledValue } = useFieldControl(value, setOutputValue) + + return ( + + + + {outputValue !== '∅' && } + + ) + } + + Object.keys(OPTIONS_TYPES).forEach(optionType => { + context(`With ${optionType} tree options`, () => { + const options = OPTIONS_TYPES[optionType] + const commonProps: MultiCascaderProps = { + label: 'A multiple cascader', + name: 'myMultiCascader', + options, + ...(optionType === 'object' + ? { + optionValueKey: 'name' as any + } + : {}) + } + + it('Should fill the multiple cascader with `searcheable`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + + cy.fill('A multiple cascader', [options[0].children[0].label]) + + outputShouldBe([options[0].children[0].value]) + + cy.fill('A multiple cascader', [options[0].children[1].label, options[1].children[0].label]) + + outputShouldBe([options[0].children[1].value, options[1].children[0].value]) + }) + + it('Should fill, change and clear the multiple cascader with `searchable value`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + + cy.fill('A multiple cascader', [options[0].children[0].label]) + + outputShouldBe([options[0].children[0].value]) + + cy.fill('A multiple cascader', [options[0].children[1].label, options[1].children[0].label]) + + outputShouldBe([options[0].children[1].value, options[1].children[0].value]) + + cy.fill('A multiple cascader', undefined) + + outputShouldBe(undefined) + }) + + it('Should fill the multiple cascader with `isLabelHidden searcheable`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + + cy.fill('A multiple cascader', [options[0].children[0].label]) + + outputShouldBe([options[0].children[0].value]) + }) + + it('Should NOT call `onChange(undefined)` with `disabled searcheable`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + }) + + it('Should NOT call `onChange(undefined)` with `disabled searchable value`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + }) + + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled searchable`', () => { + mountAndWait( + + + + ) + + outputShouldBe(undefined) + }) + + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled searchable value`', () => { + mountAndWait( + + + + ) + + outputShouldBe(undefined) + }) + }) + }) +}) diff --git a/e2e/base/fields/MultiCheckbox.spec.tsx b/e2e/base/fields/MultiCheckbox.spec.tsx index 6bb4bcfc7..811ab3878 100644 --- a/e2e/base/fields/MultiCheckbox.spec.tsx +++ b/e2e/base/fields/MultiCheckbox.spec.tsx @@ -39,92 +39,92 @@ function MultiCheckboxStory({ value, ...otherProps }: MultiCheckboxProps) { ) } -Object.keys(OPTIONS_TYPES).forEach(optionType => { - context(`With ${optionType} options`, () => { - const options = OPTIONS_TYPES[optionType] - const commonProps: MultiCheckboxProps = { - label: 'A multiple checkbox', - name: 'myMultiCheckbox', - options, - ...(optionType === 'object' - ? { - optionValueKey: 'name' as any - } - : {}) - } +describe('fields/MultiCheckbox', () => { + Object.keys(OPTIONS_TYPES).forEach(optionType => { + context(`With ${optionType} options`, () => { + const options = OPTIONS_TYPES[optionType] + const commonProps: MultiCheckboxProps = { + label: 'A multiple checkbox', + name: 'myMultiCheckbox', + options, + ...(optionType === 'object' + ? { + optionValueKey: 'name' as any + } + : {}) + } - it('Should fill, change and clear the multiple checkbox', () => { - mountAndWait() + it('Should fill, change and clear the multiple checkbox', () => { + mountAndWait() - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A multiple checkbox', [options[0].label]) + cy.fill('A multiple checkbox', [options[0].label]) - outputShouldBe([options[0].value]) + outputShouldBe([options[0].value]) - cy.fill('A multiple checkbox', [options[1].label, options[2].label]) + cy.fill('A multiple checkbox', [options[1].label, options[2].label]) - outputShouldBe([options[1].value, options[2].value]) + outputShouldBe([options[1].value, options[2].value]) - cy.fill('A multiple checkbox', undefined) + cy.fill('A multiple checkbox', undefined) - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it(`Should fill, change and clear the multiple checkbox with \`value={[${JSON.stringify( - options[2].value - )}]\``, () => { - mountAndWait() + it('Should fill, change and clear the multiple checkbox with `value`', () => { + mountAndWait() - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A multiple checkbox', [options[0].label]) + cy.fill('A multiple checkbox', [options[0].label]) - outputShouldBe([options[0].value]) + outputShouldBe([options[0].value]) - cy.fill('A multiple checkbox', [options[1].label, options[2].label]) + cy.fill('A multiple checkbox', [options[1].label, options[2].label]) - outputShouldBe([options[1].value, options[2].value]) + outputShouldBe([options[1].value, options[2].value]) - cy.fill('A multiple checkbox', undefined) + cy.fill('A multiple checkbox', undefined) - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it('Should fill the multiple checkbox with `isLabelHidden`', () => { - mountAndWait() + it('Should fill the multiple checkbox with `isLabelHidden`', () => { + mountAndWait() - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A multiple checkbox', [options[0].label]) + cy.fill('A multiple checkbox', [options[0].label]) - outputShouldBe([options[0].value]) - }) + outputShouldBe([options[0].value]) + }) - it('Should NOT call `onChange(undefined)` with `disabled`', () => { - mountAndWait() + it('Should NOT call `onChange(undefined)` with `disabled`', () => { + mountAndWait() - outputShouldNotBe() - }) + outputShouldNotBe() + }) - it(`Should NOT call \`onChange(undefined)\` with \`disabled value={[${JSON.stringify(options[2].value)}]\``, () => { - mountAndWait() + it('Should NOT call `onChange(undefined)` with `disabled value`', () => { + mountAndWait() - outputShouldNotBe() - }) + outputShouldNotBe() + }) - it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { - mountAndWait() + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { + mountAndWait() - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it(`Should call \`onChange(undefined)\` with \`disabled isUndefinedWhenDisabled value={[${JSON.stringify( - options[2].value - )}]\``, () => { - mountAndWait() + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled value`', () => { + mountAndWait( + + ) - outputShouldBe(undefined) + outputShouldBe(undefined) + }) }) }) }) diff --git a/e2e/base/fields/MultiRadio.spec.tsx b/e2e/base/fields/MultiRadio.spec.tsx index 501cfc851..e4cc7c186 100644 --- a/e2e/base/fields/MultiRadio.spec.tsx +++ b/e2e/base/fields/MultiRadio.spec.tsx @@ -43,110 +43,110 @@ function MultiRadioStory({ value, ...otherProps }: MultiRadioProps) { ) } -Object.keys(OPTIONS_TYPES).forEach(optionType => { - context(`With ${optionType} options`, () => { - const options = OPTIONS_TYPES[optionType] - const commonProps: MultiRadioProps = { - label: 'A multiple radio', - name: 'myMultiRadio', - options, - ...(optionType === 'object' - ? { - optionValueKey: 'name' as any - } - : {}) - } - - it('Should fill and change the multiple radio', () => { - mountAndWait( - - - - ) - - outputShouldNotBe() - - cy.fill('A multiple radio', options[0].label) - - outputShouldBe(options[0].value) - - cy.fill('A multiple radio', options[1].label) - - outputShouldBe(options[1].value) - }) - - it(`Should fill and change the multiple radio with \`value={${JSON.stringify(options[1].value)}}\``, () => { - mountAndWait( - - - - ) - - outputShouldNotBe() - - cy.fill('A multiple radio', options[0].label) - - outputShouldBe(options[0].value) - - cy.fill('A multiple radio', options[1].label) - - outputShouldBe(options[1].value) - }) - - it('Should fill the multiple radio with `isLabelHidden`', () => { - mountAndWait( - - - - ) - - outputShouldNotBe() - - cy.fill('A multiple radio', options[0].label) - - outputShouldBe(options[0].value) - }) - - it('Should NOT call `onChange(undefined)` with `disabled`', () => { - mountAndWait( - - - - ) - - outputShouldNotBe() - }) - - it(`Should NOT call \`onChange(undefined)\` with \`disabled value={${JSON.stringify(options[1].value)}}\``, () => { - mountAndWait( - - - - ) - - outputShouldNotBe() - }) - - it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { - mountAndWait( - - - - ) - - outputShouldBe(undefined) - }) - - it(`Should call \`onChange(undefined)\` with \`disabled isUndefinedWhenDisabled value={${JSON.stringify( - options[1].value - )}}\``, () => { - mountAndWait( - - - - ) - - outputShouldBe(undefined) +describe('fields/MultiRadio', () => { + Object.keys(OPTIONS_TYPES).forEach(optionType => { + context(`With ${optionType} options`, () => { + const options = OPTIONS_TYPES[optionType] + const commonProps: MultiRadioProps = { + label: 'A multiple radio', + name: 'myMultiRadio', + options, + ...(optionType === 'object' + ? { + optionValueKey: 'name' as any + } + : {}) + } + + it('Should fill and change the multiple radio', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + + cy.fill('A multiple radio', options[0].label) + + outputShouldBe(options[0].value) + + cy.fill('A multiple radio', options[1].label) + + outputShouldBe(options[1].value) + }) + + it('Should fill and change the multiple radio with `value`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + + cy.fill('A multiple radio', options[0].label) + + outputShouldBe(options[0].value) + + cy.fill('A multiple radio', options[1].label) + + outputShouldBe(options[1].value) + }) + + it('Should fill the multiple radio with `isLabelHidden`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + + cy.fill('A multiple radio', options[0].label) + + outputShouldBe(options[0].value) + }) + + it('Should NOT call `onChange(undefined)` with `disabled`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + }) + + it('Should NOT call `onChange(undefined)` with `disabled value`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + }) + + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { + mountAndWait( + + + + ) + + outputShouldBe(undefined) + }) + + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled value`', () => { + mountAndWait( + + + + ) + + outputShouldBe(undefined) + }) }) }) }) diff --git a/e2e/base/fields/MultiSelect.spec.tsx b/e2e/base/fields/MultiSelect.spec.tsx index 8752b64d9..f25aa282d 100644 --- a/e2e/base/fields/MultiSelect.spec.tsx +++ b/e2e/base/fields/MultiSelect.spec.tsx @@ -39,215 +39,241 @@ function MultiSelectStory({ value, ...otherProps }: MultiSelectProps) { ) } -Object.keys(OPTIONS_TYPES).forEach(optionType => { - context(`With ${optionType} options`, () => { - const options = OPTIONS_TYPES[optionType] - const commonProps: MultiSelectProps = { - label: 'A multiple select', - name: 'myMultiSelect', - options, - ...(optionType === 'object' - ? { - optionValueKey: 'name' as any - } - : {}) - } +describe('fields/MultiSelect', () => { + Object.keys(OPTIONS_TYPES).forEach(optionType => { + context(`With ${optionType} options`, () => { + const options = OPTIONS_TYPES[optionType] + const commonProps: MultiSelectProps = { + label: 'A multiple select', + name: 'myMultiSelect', + options, + ...(optionType === 'object' + ? { + optionValueKey: 'name' as any + } + : {}) + } - it('Should fill, change and clear the multiple select', () => { - mountAndWait( - - - - ) + it('Should fill, change and clear the multiple select', () => { + mountAndWait( + + + + ) - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A multiple select', [options[0].label]) + cy.fill('A multiple select', [options[0].label]) - outputShouldBe([options[0].value]) + outputShouldBe([options[0].value]) - cy.fill('A multiple select', [options[1].label, options[2].label]) + cy.fill('A multiple select', [options[1].label, options[2].label]) - outputShouldBe([options[1].value, options[2].value]) + outputShouldBe([options[1].value, options[2].value]) - cy.fill('A multiple select', undefined) + cy.fill('A multiple select', undefined) - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it('Should fill the multiple select with `isLabelHidden`', () => { - mountAndWait( - - - - ) + it('Should fill, change and clear the multiple select with `value`', () => { + mountAndWait( + + + + ) - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A multiple select', [options[0].label]) + cy.fill('A multiple select', [options[0].label]) - outputShouldBe([options[0].value]) - }) + outputShouldBe([options[0].value]) - it('Should fill the multiple picker with `searcheable`', () => { - mountAndWait( - - - - ) + cy.fill('A multiple select', [options[1].label, options[2].label]) - outputShouldNotBe() + outputShouldBe([options[1].value, options[2].value]) - cy.fill('A multiple select', [options[0].label]) + cy.fill('A multiple select', undefined) - outputShouldBe([options[0].value]) + outputShouldBe(undefined) + }) - cy.fill('A multiple select', [options[1].label, options[2].label]) + it('Should fill the multiple select with `isLabelHidden`', () => { + mountAndWait( + + + + ) - outputShouldBe([options[1].value, options[2].value]) - }) + outputShouldNotBe() - it('Should NOT call `onChange(undefined)` with `disabled`', () => { - mountAndWait( - - - - ) + cy.fill('A multiple select', [options[0].label]) - outputShouldNotBe() - }) + outputShouldBe([options[0].value]) + }) - it(`Should NOT call \`onChange(undefined)\` with \`disabled value={[${JSON.stringify(options[2].value)}]\``, () => { - mountAndWait( - - - - ) + it('Should fill the multiple picker with `searcheable`', () => { + mountAndWait( + + + + ) - outputShouldNotBe() - }) + outputShouldNotBe() - it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { - mountAndWait( - - - - ) + cy.fill('A multiple select', [options[0].label]) - outputShouldBe(undefined) - }) + outputShouldBe([options[0].value]) - it(`Should call \`onChange(undefined)\` with \`disabled isUndefinedWhenDisabled value={[${JSON.stringify( - options[2].value - )}]\``, () => { - mountAndWait( - - - - ) + cy.fill('A multiple select', [options[1].label, options[2].label]) - outputShouldBe(undefined) - }) + outputShouldBe([options[1].value, options[2].value]) + }) - it('Should filter and select the expected options when using `customSearch`', () => { - const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) + it('Should NOT call `onChange(undefined)` with `disabled`', () => { + mountAndWait( + + + + ) - mountAndWait( - - - - ) + outputShouldNotBe() + }) - outputShouldNotBe() + it('Should NOT call `onChange(undefined)` with `disabled value`', () => { + mountAndWait( + + + + ) + + outputShouldNotBe() + }) + + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { + mountAndWait( + + + + ) + + outputShouldBe(undefined) + }) + + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled value`', () => { + mountAndWait( + + + + ) + + outputShouldBe(undefined) + }) + + it('Should filter and select the expected options when using `customSearch`', () => { + const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) + + mountAndWait( + + + + ) + + outputShouldNotBe() + + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() + cy.get('.rs-picker-search-input').find('input').type('la remie') + cy.get('.rs-picker-popup').find('[role="option"]').first().click() + cy.clickOutside() + + outputShouldBe([options[0].value]) - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() - cy.get('.rs-picker-search-input').find('input').type('la remie') - cy.get('.rs-picker-popup').find('[role="option"]').first().click() - cy.clickOutside() + // Clear the MultiSelect + cy.fill('A multiple select', undefined) - outputShouldBe([options[0].value]) + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() + cy.get('.rs-picker-search-input').find('input').type('la option') + cy.get('.rs-picker-popup').find('[role="option"]').first().click() + cy.clickOutside() - // Clear the MultiSelect - cy.fill('A multiple select', undefined) + outputShouldBe([options[0].value]) - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() - cy.get('.rs-picker-search-input').find('input').type('la option') - cy.get('.rs-picker-popup').find('[role="option"]').first().click() - cy.clickOutside() + // Clear the MultiSelect + cy.fill('A multiple select', undefined) - outputShouldBe([options[0].value]) + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() + cy.get('.rs-picker-search-input').find('input').type('sêcôndÈ') + cy.get('.rs-picker-popup').find('[role="option"]').first().click() + cy.clickOutside() - // Clear the MultiSelect - cy.fill('A multiple select', undefined) + outputShouldBe([options[1].value]) + }) - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() - cy.get('.rs-picker-search-input').find('input').type('sêcôndÈ') - cy.get('.rs-picker-popup').find('[role="option"]').first().click() - cy.clickOutside() + it('Should fill, clear and get all list', () => { + const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) + mountAndWait( + + + + ) - outputShouldBe([options[1].value]) + outputShouldNotBe() + + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() + cy.get('.rs-picker-search-input').find('input').type('sêc') + cy.get('.rs-picker-search-input').find('input').type('{backspace}{backspace}{backspace}') + + cy.get('.rs-picker-popup').find('[role="option"]').should('have.length', 3) + }) }) + }) + + context('With `searchable` in a long list', () => { + const options = [ + { label: 'La Première Option', value: 'FIRST_OPTION' }, + { label: 'La Seconde Option', value: 'SECOND_OPTION' }, + { label: 'La Troisième Option', value: 'THIRD_OPTION' }, + { label: 'La Quatrième Option', value: 'FOURTH_OPTION' }, + { label: 'La Cinquième Option', value: 'FIFTH_OPTION' }, + { label: 'La Sixième Option', value: 'SIXTH_OPTION' }, + { label: 'La Septième Option', value: 'SEVENTH_OPTION' }, + { label: 'La Huitième Option', value: 'EIGHTH_OPTION' }, + { label: 'La Neuvième Option', value: 'NINTH_OPTION' }, + { label: 'La Dixième Option', value: 'TENTH_OPTION' }, + { label: 'La Onzième Option', value: 'ELEVENTH_OPTION' }, + { label: 'La Douzième Option', value: 'TWELFTH_OPTION' }, + { label: 'La Treizième Option', value: 'THIRTEENTH_OPTION' }, + { label: 'La Quatorzième Option', value: 'FOURTEENTH_OPTION' }, + { label: 'La Quinzième Option', value: 'FIFTEENTH_OPTION' }, + { label: 'La Seizième Option', value: 'SIXTEENTH_OPTION' }, + { label: 'La Dix-septième Option', value: 'SEVENTEENTH_OPTION' }, + { label: 'La Dix-huitième Option', value: 'EIGHTEENTH_OPTION' }, + { label: 'La Dix-neuvième Option', value: 'NINETEENTH_OPTION' }, + { label: 'La Vingtième Option', value: 'TWENTIETH_OPTION' } + ] + const commonProps: MultiSelectProps = { + label: 'A multiple select', + name: 'myMultiSelect', + options, + searchable: true + } - it('Should fill, clear and get all list', () => { - const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) + it('Should search for options', () => { mountAndWait( - + ) outputShouldNotBe() - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click() - cy.get('.rs-picker-search-input').find('input').type('sêc') - cy.get('.rs-picker-search-input').find('input').type('{backspace}{backspace}{backspace}') + cy.fill('A multiple select', ['Vingtième']) - cy.get('.rs-picker-popup').find('[role="option"]').should('have.length', 3) - }) - }) -}) - -context('With `searchable`', () => { - const options = [ - { label: 'La Première Option', value: 'FIRST_OPTION' }, - { label: 'La Seconde Option', value: 'SECOND_OPTION' }, - { label: 'La Troisième Option', value: 'THIRD_OPTION' }, - { label: 'La Quatrième Option', value: 'FOURTH_OPTION' }, - { label: 'La Cinquième Option', value: 'FIFTH_OPTION' }, - { label: 'La Sixième Option', value: 'SIXTH_OPTION' }, - { label: 'La Septième Option', value: 'SEVENTH_OPTION' }, - { label: 'La Huitième Option', value: 'EIGHTH_OPTION' }, - { label: 'La Neuvième Option', value: 'NINTH_OPTION' }, - { label: 'La Dixième Option', value: 'TENTH_OPTION' }, - { label: 'La Onzième Option', value: 'ELEVENTH_OPTION' }, - { label: 'La Douzième Option', value: 'TWELFTH_OPTION' }, - { label: 'La Treizième Option', value: 'THIRTEENTH_OPTION' }, - { label: 'La Quatorzième Option', value: 'FOURTEENTH_OPTION' }, - { label: 'La Quinzième Option', value: 'FIFTEENTH_OPTION' }, - { label: 'La Seizième Option', value: 'SIXTEENTH_OPTION' }, - { label: 'La Dix-septième Option', value: 'SEVENTEENTH_OPTION' }, - { label: 'La Dix-huitième Option', value: 'EIGHTEENTH_OPTION' }, - { label: 'La Dix-neuvième Option', value: 'NINETEENTH_OPTION' }, - { label: 'La Vingtième Option', value: 'TWENTIETH_OPTION' } - ] - const commonProps: MultiSelectProps = { - label: 'A multiple select', - name: 'myMultiSelect', - options, - searchable: true - } - - it('Should search for options', () => { - mountAndWait( - - - - ) + outputShouldBe([options[19]!.value]) - outputShouldNotBe() + cy.fill('A multiple select', ['Onzième', 'Seizième']) - cy.fill('A multiple select', ['Vingtième']) - - outputShouldBe([options[19]!.value]) + outputShouldBe([options[10]!.value, options[15]!.value]) + }) }) }) diff --git a/e2e/base/fields/Search.spec.tsx b/e2e/base/fields/Search.spec.tsx index 052f5bc19..cebbc7c4b 100644 --- a/e2e/base/fields/Search.spec.tsx +++ b/e2e/base/fields/Search.spec.tsx @@ -1,9 +1,10 @@ +import { useState } from 'react' + +import { Output } from '../../../.storybook/components/Output' import { StoryBox } from '../../../.storybook/components/StoryBox' -import { _Search as SearchStory } from '../../../stories/fields/Search.stories' +import { Search, useFieldControl, type SearchProps } from '../../../src' import { mountAndWait, outputShouldBe, outputShouldNotBe } from '../utils' -import type { SearchProps } from '../../../src' - /* eslint-disable sort-keys-fix/sort-keys-fix */ const OPTIONS_TYPES = { string: [ @@ -24,36 +25,52 @@ const OPTIONS_TYPES = { } /* eslint-enable sort-keys-fix/sort-keys-fix */ -Object.keys(OPTIONS_TYPES).forEach(optionType => { - context(`With (${optionType} options`, () => { - const options = OPTIONS_TYPES[optionType] - const commonProps: SearchProps = { - label: 'A search', - name: 'mySearch', - options, - ...(optionType === 'object' - ? { - optionValueKey: 'name' as any - } - : {}) - } +function SearchStory({ value, ...otherProps }: SearchProps) { + const [outputValue, setOutputValue] = useState('∅') + + const { controlledOnChange, controlledValue } = useFieldControl(value, setOutputValue) + + return ( + + + + {outputValue !== '∅' && } + + ) +} + +describe('fields/Search', () => { + Object.keys(OPTIONS_TYPES).forEach(optionType => { + context(`With ${optionType} options`, () => { + const options = OPTIONS_TYPES[optionType] + const commonProps: SearchProps = { + label: 'A search', + name: 'mySearch', + options, + ...(optionType === 'object' + ? { + optionValueKey: 'name' as any + } + : {}) + } - it('Should fill, change and clear the select', () => { - mountAndWait( - - - - ) + it('Should fill, change and clear the search', () => { + mountAndWait( + + + + ) - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A search', 'first') + cy.fill('A search', 'first') - outputShouldBe(options[0].value) + outputShouldBe(options[0].value) - cy.fill('A search', 'second') + cy.fill('A search', 'second') - outputShouldBe(options[1].value) + outputShouldBe(options[1].value) + }) }) }) }) diff --git a/e2e/base/fields/Select.spec.tsx b/e2e/base/fields/Select.spec.tsx index fd0c71879..d26e61e77 100644 --- a/e2e/base/fields/Select.spec.tsx +++ b/e2e/base/fields/Select.spec.tsx @@ -39,143 +39,147 @@ function SelectStory({ value, ...otherProps }: SelectProps) { ) } -Object.keys(OPTIONS_TYPES).forEach(optionType => { - context(`Story (${optionType} options)`, () => { - const options = OPTIONS_TYPES[optionType] - const commonProps: SelectProps = { - label: 'A select', - name: 'mySelect', - options, - ...(optionType === 'object' - ? { - optionValueKey: 'name' as any - } - : {}) - } +describe('fields/Select', () => { + Object.keys(OPTIONS_TYPES).forEach(optionType => { + context(`With ${optionType} options`, () => { + const options = OPTIONS_TYPES[optionType] + const commonProps: SelectProps = { + label: 'A select', + name: 'mySelect', + options, + ...(optionType === 'object' + ? { + optionValueKey: 'name' as any + } + : {}) + } - it('Should fill, change and clear the select', () => { - mountAndWait() + it('Should fill, change and clear the select', () => { + mountAndWait() - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A select', options[0].label) + cy.fill('A select', options[0].label) - outputShouldBe(options[0].value) + outputShouldBe(options[0].value) - cy.fill('A select', options[1].label) + cy.fill('A select', options[1].label) - outputShouldBe(options[1].value) + outputShouldBe(options[1].value) - cy.fill('A select', undefined) + cy.fill('A select', undefined) - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it(`Should fill, change and clear the select with \`value={${JSON.stringify(options[2].value)}}\``, () => { - mountAndWait() + it(`Should fill, change and clear the select with \`value={${JSON.stringify(options[2].value)}}\``, () => { + mountAndWait() - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A select', options[0].label) + cy.fill('A select', options[0].label) - outputShouldBe(options[0].value) + outputShouldBe(options[0].value) - cy.fill('A select', options[1].label) + cy.fill('A select', options[1].label) - outputShouldBe(options[1].value) + outputShouldBe(options[1].value) - cy.fill('A select', undefined) + cy.fill('A select', undefined) - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it('Should fill the select with `isLabelHidden`', () => { - mountAndWait() + it('Should fill the select with `isLabelHidden`', () => { + mountAndWait() - outputShouldNotBe() + outputShouldNotBe() - cy.fill('A select', options[0].label) + cy.fill('A select', options[0].label) - outputShouldBe(options[0].value) - }) + outputShouldBe(options[0].value) + }) - it('Should NOT call `onChange(undefined)` with `disabled`', () => { - mountAndWait() + it('Should NOT call `onChange(undefined)` with `disabled`', () => { + mountAndWait() - outputShouldNotBe() - }) + outputShouldNotBe() + }) - it(`Should NOT call \`onChange(undefined)\` with \`disabled value={${JSON.stringify(options[2].value)}}\``, () => { - mountAndWait() + it(`Should NOT call \`onChange(undefined)\` with \`disabled value={${JSON.stringify( + options[2].value + )}}\``, () => { + mountAndWait() - outputShouldNotBe() - }) + outputShouldNotBe() + }) - it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { - mountAndWait() + it('Should call `onChange(undefined)` with `disabled isUndefinedWhenDisabled`', () => { + mountAndWait() - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it(`Should call \`onChange(undefined)\` with \`disabled isUndefinedWhenDisabled value={${JSON.stringify( - options[2].value - )}}\``, () => { - mountAndWait() + it(`Should call \`onChange(undefined)\` with \`disabled isUndefinedWhenDisabled value={${JSON.stringify( + options[2].value + )}}\``, () => { + mountAndWait() - outputShouldBe(undefined) - }) + outputShouldBe(undefined) + }) - it('Should filter and select the expected options when using `customSearch`', () => { - const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) + it('Should filter and select the expected options when using `customSearch`', () => { + const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) - mountAndWait() + mountAndWait() - outputShouldNotBe() + outputShouldNotBe() - // TODO Investigate why we need to wait here (expecting the popup to be visible doesn't fix the failing case). - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click().wait(100) - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('la remie') - cy.get('.rs-picker-popup').find('div[role="option"]').first().click() + // TODO Investigate why we need to wait here (expecting the popup to be visible doesn't fix the failing case). + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click().wait(100) + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('la remie') + cy.get('.rs-picker-popup').find('div[role="option"]').first().click() - outputShouldBe(options[0].value) + outputShouldBe(options[0].value) - // Clear the Select - cy.fill('A select', undefined) + // Clear the Select + cy.fill('A select', undefined) - // TODO Investigate why we need to wait here (expecting the popup to be visible doesn't fix the failing case). - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click().wait(100) - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('la option') - cy.get('.rs-picker-popup').find('div[role="option"]').first().click() + // TODO Investigate why we need to wait here (expecting the popup to be visible doesn't fix the failing case). + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click().wait(100) + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('la option') + cy.get('.rs-picker-popup').find('div[role="option"]').first().click() - outputShouldBe(options[0].value) + outputShouldBe(options[0].value) - // Clear the Select - cy.fill('A select', undefined) + // Clear the Select + cy.fill('A select', undefined) - // TODO Investigate why we need to wait here (expecting the popup to be visible doesn't fix the failing case). - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click().wait(100) - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('sêcôndÈ') - cy.get('.rs-picker-popup').find('div[role="option"]').first().click() + // TODO Investigate why we need to wait here (expecting the popup to be visible doesn't fix the failing case). + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click().wait(100) + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('sêcôndÈ') + cy.get('.rs-picker-popup').find('div[role="option"]').first().click() - outputShouldBe(options[1].value) - }) + outputShouldBe(options[1].value) + }) - it('Should fill, clear and get all list', () => { - const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) - mountAndWait() + it('Should fill, clear and get all list', () => { + const customSearch = new CustomSearch(options, ['label'], { isStrict: true }) + mountAndWait() - outputShouldNotBe() + outputShouldNotBe() - // TODO Investigate why we need to wait here (expecting the popup to be visible doesn't fix the failing case). - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click().wait(100) - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('sêc') - cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('{backspace}{backspace}{backspace}') + // TODO Investigate why we need to wait here (expecting the popup to be visible doesn't fix the failing case). + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.get('.rs-stack > .rs-stack-item > .rs-picker-caret-icon').click().wait(100) + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('sêc') + cy.get('.rs-picker-popup').find('input[role="searchbox"]').type('{backspace}{backspace}{backspace}') - cy.get('.rs-picker-popup').find('[role="option"]').should('have.length', 3) + cy.get('.rs-picker-popup').find('[role="option"]').should('have.length', 3) + }) }) }) }) diff --git a/src/cypress/commands/fill/index.ts b/src/cypress/commands/fill/index.ts index 0945ed719..7acaec9fd 100644 --- a/src/cypress/commands/fill/index.ts +++ b/src/cypress/commands/fill/index.ts @@ -10,6 +10,7 @@ import { fillNumberInput } from './fillNumberInput' import { fillTextarea } from './fillTextarea' import { fillTextInput } from './fillTextInput' import { pickCheckPickerOptions } from './pickCheckPickerOptions' +import { pickMultiCascaderOptions } from './pickMultiCascaderOptions' import { pickMultiSelectOptions } from './pickMultiSelectOptions' import { pickSearchOption } from './pickSearchOption' import { pickSelectOption } from './pickSelectOption' @@ -71,6 +72,15 @@ export function fill(label: string, value: any, options: Partial ({ + 'Applied to': fieldElement, + Elements: 1 + }), + name: 'pickMultiCascaderOptions' + }) + + cy.wrap(fieldElement).scrollIntoView({ offset: { left: 0, top: -100 } }) + + // Clear the field if there is a clear button + const maybeClearButton = fieldElement.querySelector('.rs-stack > .rs-stack-item > .rs-picker-clean') + if (maybeClearButton) { + cy.wrap(fieldElement).find('.rs-stack > .rs-stack-item > .rs-picker-clean').click({ force }).wait(250) + } + + // If `values` is undefined, we don't need to select anything + if (!values) { + return + } + + cy.wrap(fieldElement).find('.rs-picker-toggle').click({ force }) + + // Wait for the picker to open + cy.wrap(fieldElement) + .find('.rs-picker-popup') + .then(([rsuitePickerPopupElement]) => { + if (!rsuitePickerPopupElement) { + throwError(`Could not find '.rs-picker-popup' in in field with label "${label}". Did the picker open?`) + } + + // Search for the value if there is a search input + const maybeSearchInput = rsuitePickerPopupElement.querySelector('input[role="searchbox"]') + if (!maybeSearchInput) { + throwError( + throwError( + `\`cy.fill()\` can't handle the MultiCascader with \`