Skip to content

Commit

Permalink
feat: add index prop to NativeOption component and update selection l…
Browse files Browse the repository at this point in the history
…ogic

Refs: #7032
  • Loading branch information
Makko74 committed Nov 27, 2024
1 parent a7182a9 commit b4a633d
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ export type NativeOptionProps = Omit<JSXBase.OptionHTMLAttributes<HTMLOptionElem
selectedValue?: W3CInputValue | W3CInputValue[];
value: W3CInputValue;
label: W3CInputValue;
index?: string | number;
};

const NativeOptionFc: FC<NativeOptionProps> = ({ selectedValue, selected, value, label, ...other }) => {
const NativeOptionFc: FC<NativeOptionProps> = ({ index, selectedValue, selected, value, label, ...other }) => {
if (!selectedValue) {
selectedValue = [];
} else if (!Array.isArray(selectedValue)) {
selectedValue = [selectedValue];
}

return (
<option selected={selected || selectedValue.includes(label)} value={value} {...other}>
<option selected={selected || selectedValue.includes(value)} value={index || value} {...other}>
{label}
</option>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,43 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`NativeOptionFc should render an option tag with the correct index as value and label 1`] = `
<option value="-1">
testLabel
</option>
`;

exports[`NativeOptionFc should render an option tag with the correct value and label 1`] = `
<option value="testValue">
testLabel
</option>
`;

exports[`NativeOptionFc should render and match snapshot 1`] = `
<option value="testValue">
testLabel
</option>
`;

exports[`NativeOptionFc should set selected attribute correctly based on selected prop 1`] = `
<option selected="" value="testValue">
testLabel
</option>
`;

exports[`NativeOptionFc should set selected attribute correctly based on selectedValue (with index as value) 1`] = `
<option selected="" value="-1">
testLabel
</option>
`;

exports[`NativeOptionFc should set selected attribute correctly based on selectedValue 1`] = `
<option selected="" value="testValue">
testLabel
</option>
`;

exports[`NativeOptionFc should set selected attribute correctly based on selectedValue as number (with index as value) 1`] = `
<option selected="" value="-1">
testLabel
</option>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,58 @@ describe('NativeOptionFc', () => {

it('should render an option tag with the correct value and label', async () => {
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionFc value="testValue" label="testLabel" />);

expect(page.root).toMatchSnapshot();

const option = page.root;
expect(option?.tagName).toBe('OPTION');
expect(option?.getAttribute('value')).toBe('testValue');
expect(option?.textContent).toBe('testLabel');
});

it('should render an option tag with the correct index as value and label', async () => {
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionFc index={-1} value="testValue" label="testLabel" />);

expect(page.root).toMatchSnapshot();

const option = page.root;
expect(option?.tagName).toBe('OPTION');
expect(option?.getAttribute('value')).toBe('-1');
expect(option?.textContent).toBe('testLabel');
});

it('should set selected attribute correctly based on selectedValue', async () => {
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionFc value="testValue" label="testLabel" selectedValue="testLabel" />);
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionFc value="testValue" label="testLabel" selectedValue="testValue" />);

expect(page.root).toMatchSnapshot();

const option = page.root;
expect(option?.hasAttribute('selected')).toBe(true);
});

it('should set selected attribute correctly based on selectedValue (with index as value)', async () => {
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionFc index={-1} value="testValue" label="testLabel" selectedValue="testValue" />);

expect(page.root).toMatchSnapshot();

const option = page.root;
expect(option?.hasAttribute('selected')).toBe(true);
});

it('should set selected attribute correctly based on selectedValue as number (with index as value)', async () => {
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionFc index={-1} value={5} label="testLabel" selectedValue={5} />);

expect(page.root).toMatchSnapshot();

const option = page.root;
expect(option?.hasAttribute('selected')).toBe(true);
});

it('should set selected attribute correctly based on selected prop', async () => {
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionFc value="testValue" label="testLabel" selected />);

expect(page.root).toMatchSnapshot();

const option = page.root;
expect(option?.hasAttribute('selected')).toBe(true);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,35 @@ export type NativeOptionListProps = {
OptionGroupProps?: Omit<JSXBase.OptgroupHTMLAttributes<HTMLOptGroupElement>, 'label'>;
};

const NativeOptionListFc: FC<NativeOptionListProps> = ({ preKey, options, value, OptionProps = {}, OptionGroupProps = {} }) => {
const NativeOptionListFc: FC<NativeOptionListProps> = ({ preKey, options, value: selectedValue, OptionProps = {}, OptionGroupProps = {} }) => {
if (!options?.length) {
return null;
}

return (
<>
{options.map(({ label, disabled, ...other }, index) => {
{options.map((option, index) => {
const key = [preKey, `-${index}`].join('');

if ('options' in other && options.length) {
if ('options' in option) {
if (!options.length) {
return null;
}

const { label, ...other } = option;

return (
<optgroup key={key} {...OptionGroupProps} label={label?.toString()}>
<NativeOptionListFc
OptionGroupProps={OptionGroupProps}
OptionProps={OptionProps}
options={other.options}
value={value}
disabled={disabled}
preKey={key}
/>
<NativeOptionListFc OptionGroupProps={OptionGroupProps} OptionProps={OptionProps} value={selectedValue} preKey={key} {...other} />
</optgroup>
);
}

return <NativeOptionFc key={key} {...OptionProps} label={label} selectedValue={value} value={key} disabled={disabled} />;
if ('value' in option) {
return <NativeOptionFc key={key} {...OptionProps} index={key} selectedValue={selectedValue} {...option} />;
}

return null;
})}
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,65 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`NativeOptionListFc should render and match snapshot 1`] = `
<option value="-0">
Option 1
</option>
<div id="jest-test">
<option value="-0">
Option 1
</option>
</div>
`;

exports[`NativeOptionListFc should render with a single option 1`] = `
<option value="-0">
Option 1
</option>
<div id="jest-test">
<option value="-0">
Option 1
</option>
</div>
`;

exports[`NativeOptionListFc should render with multiple options 1`] = `
<option value="-0">
Option 1
</option>
<div id="jest-test">
<option value="-0">
Option 1
</option>
<option value="-1">
Option 2
</option>
</div>
`;

exports[`NativeOptionListFc should render with nested option groups 1`] = `
<optgroup label="Group 1">
<option value="-0-0">
exports[`NativeOptionListFc should render with multiple options with selected value 1`] = `
<div id="jest-test">
<option value="-0">
Option 1
</option>
<option value="-0-1">
<option selected="" value="-1">
Option 2
</option>
</optgroup>
</div>
`;

exports[`NativeOptionListFc should render with nested option groups 1`] = `
<div id="jest-test">
<optgroup label="Group 1">
<option value="-0-0">
Option 1
</option>
<option value="-0-1">
Option 2
</option>
</optgroup>
</div>
`;

exports[`NativeOptionListFc should render with nested option groups with selected value 1`] = `
<div id="jest-test">
<optgroup label="Group 1">
<option value="-0-0">
Option 1
</option>
<option selected="" value="-0-1">
Option 2
</option>
</optgroup>
</div>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import NativeOptionListFc from '../NativeOptionList';
describe('NativeOptionListFc', () => {
it('should render and match snapshot', async () => {
const options = [{ label: 'Option 1', value: '1' }];
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionListFc options={options} />);
const page = await renderFunctionalComponentToSpecPage(() => (
<div id="jest-test">
<NativeOptionListFc options={options} />
</div>
));
expect(page.root).toMatchSnapshot();
});

Expand All @@ -16,17 +20,43 @@ describe('NativeOptionListFc', () => {

it('should render with a single option', async () => {
const options = [{ label: 'Option 1', value: '1' }];
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionListFc options={options} />);
const page = await renderFunctionalComponentToSpecPage(() => (
<div id="jest-test">
<NativeOptionListFc options={options} />
</div>
));
expect(page.root).toMatchSnapshot();
expect(page.root?.querySelectorAll('option').length).toBe(1);
});

it('should render with multiple options', async () => {
const options = [
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' },
];
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionListFc options={options} />);
const page = await renderFunctionalComponentToSpecPage(() => (
<div id="jest-test">
<NativeOptionListFc options={options} />
</div>
));
expect(page.root).toMatchSnapshot();
expect(page.root?.querySelectorAll('option').length).toBe(2);
});

it('should render with multiple options with selected value', async () => {
const options = [
{ label: 'Option 1', value: 1 },
{ label: 'Option 2', value: 2 },
];
const page = await renderFunctionalComponentToSpecPage(() => (
<div id="jest-test">
<NativeOptionListFc options={options} value={2} />
</div>
));
expect(page.root).toMatchSnapshot();
expect(page.root?.querySelectorAll('option').length).toBe(2);
expect(page.root?.querySelectorAll('option')[0].hasAttribute('selected')).toBe(false);
expect(page.root?.querySelectorAll('option')[1].hasAttribute('selected')).toBe(true);
});

it('should render with nested option groups', async () => {
Expand All @@ -39,7 +69,35 @@ describe('NativeOptionListFc', () => {
],
},
];
const page = await renderFunctionalComponentToSpecPage(() => <NativeOptionListFc options={options} />);
const page = await renderFunctionalComponentToSpecPage(() => (
<div id="jest-test">
<NativeOptionListFc options={options} />
</div>
));
expect(page.root).toMatchSnapshot();
expect(page.root?.querySelectorAll('optgroup').length).toBe(1);
expect(page.root?.querySelectorAll('option').length).toBe(2);
});

it('should render with nested option groups with selected value', async () => {
const options = [
{
label: 'Group 1',
options: [
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' },
],
},
];
const page = await renderFunctionalComponentToSpecPage(() => (
<div id="jest-test">
<NativeOptionListFc options={options} value="2" />
</div>
));
expect(page.root).toMatchSnapshot();
expect(page.root?.querySelectorAll('optgroup').length).toBe(1);
expect(page.root?.querySelectorAll('option').length).toBe(2);
expect(page.root?.querySelectorAll('option')[0].hasAttribute('selected')).toBe(false);
expect(page.root?.querySelectorAll('option')[1].hasAttribute('selected')).toBe(true);
});
});

0 comments on commit b4a633d

Please sign in to comment.