fix labeledselect getOptionLabel to use reduce prop when labels change (#8176)

* fix labeledselect getOptionLabel to use reduce prop when labels change

* Add unit tests

---------

Co-authored-by: cnotv <giuseppe.leo@suse.com>
This commit is contained in:
Nancy 2023-02-15 09:19:48 -07:00 committed by GitHub
parent 5f91d46762
commit 21167e1dc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 132 additions and 33 deletions

View File

@ -5,6 +5,7 @@ import { get } from '@shell/utils/object';
import { LabeledTooltip } from '@components/LabeledTooltip'; import { LabeledTooltip } from '@components/LabeledTooltip';
import VueSelectOverrides from '@shell/mixins/vue-select-overrides'; import VueSelectOverrides from '@shell/mixins/vue-select-overrides';
import { onClickOption, calculatePosition } from '@shell/utils/select'; import { onClickOption, calculatePosition } from '@shell/utils/select';
import isEqual from 'lodash/isEqual';
export default { export default {
name: 'LabeledSelect', name: 'LabeledSelect',
@ -152,10 +153,13 @@ export default {
const isOutdated = !this.options.find(opt => option[this.optionLabel] === opt[this.optionLabel]); const isOutdated = !this.options.find(opt => option[this.optionLabel] === opt[this.optionLabel]);
if (isOutdated && this.options) { if (isOutdated && this.options) {
const newOption = this.options.find(opt => option[this.optionKey] === opt[this.optionKey]); const newOption = this.options.find(opt => isEqual(this.reduce(option), this.reduce(opt)));
const label = get(newOption, this.optionLabel);
return this.localizedLabel ? this.$store.getters['i18n/t'](label) || label : label; if (newOption) {
const label = get(newOption, this.optionLabel);
return this.localizedLabel ? this.$store.getters['i18n/t'](label) || label : label;
}
} }
if (this.$attrs['get-option-label']) { if (this.$attrs['get-option-label']) {

View File

@ -2,42 +2,137 @@ import { mount } from '@vue/test-utils';
import LabeledSelect from '@shell/components/form/LabeledSelect.vue'; import LabeledSelect from '@shell/components/form/LabeledSelect.vue';
describe('component: LabeledSelect', () => { describe('component: LabeledSelect', () => {
it('should automatically pick option for given value', () => { describe('should display correct label', () => {
const label = 'Foo'; it('given an existing value and option', () => {
const value = 'foo'; const label = 'Foo';
const wrapper = mount(LabeledSelect, { const value = 'foo';
propsData: { const wrapper = mount(LabeledSelect, {
value, propsData: {
options: [ value,
{ label, value }, options: [
], { label, value },
} ],
}
});
// Component is from a library and class is not going to be changed
expect(wrapper.find('.vs__selected').text()).toBe(label);
}); });
// Component is from a library and class is not going to be changed it('using value as label if no options', () => {
expect(wrapper.find('.vs__selected').text()).toBe(label); const value = 'foo';
}); const wrapper = mount(LabeledSelect, {
propsData: {
value,
options: [],
}
});
it('should update the displayed label if options are changed', async() => { // Component is from a library and class is not going to be changed
const newLabel = 'Baz'; expect(wrapper.find('.vs__selected').text()).toBe(value);
const oldLabel = 'Foo';
const value = 'foo';
const wrapper = mount(LabeledSelect, {
propsData: {
value,
options: [
{ label: oldLabel, value },
],
}
}); });
await wrapper.setProps({ it('using custom key as label for option object', () => {
options: [ const value = 'foo';
{ label: newLabel, value }, const label = 'Foo';
] const customLabelKey = 'bananas';
const wrapper = mount(LabeledSelect, {
propsData: {
value,
optionLabel: customLabelKey,
options: [{
[customLabelKey]: label,
value
}],
}
});
// Component is from a library and class is not going to be changed
expect(wrapper.find('.vs__selected').text()).toBe(label);
}); });
// Component is from a library and class is not going to be changed it('translating localized cases', () => {
expect(wrapper.find('.vs__selected').text()).toBe(newLabel); const value = 'foo';
const translation = 'bananas';
const wrapper = mount(LabeledSelect, {
propsData: {
localizedLabel: true,
value,
options: [{ label: 'whatever', value }],
},
mocks: { $store: { getters: { 'i18n/t': () => translation } } }
});
// Component is from a library and class is not going to be changed
expect(wrapper.find('.vs__selected').text()).toBe(translation);
});
describe('updating the value on options change', () => {
it('using new label', async() => {
const value = 'foo';
const oldLabel = 'Foo';
const newLabel = 'Baz';
const wrapper = mount(LabeledSelect, {
propsData: {
value,
options: [
{ label: oldLabel, value },
],
}
});
await wrapper.setProps({
options: [
{ label: newLabel, value },
]
});
// Component is from a library and class is not going to be changed
expect(wrapper.find('.vs__selected').text()).toBe(newLabel);
});
it('using values only and no labels', async() => {
const value = 'foo';
const newValue = 'bananas';
const wrapper = mount(LabeledSelect, {
propsData: {
value,
options: [value],
}
});
await wrapper.setProps({ options: [newValue] });
// Component is from a library and class is not going to be changed
expect(wrapper.find('.vs__selected').text()).toBe(value);
});
it('using translated value', async() => {
const value = 'foo';
const oldLabel = 'Foo';
const newLabel = 'Baz';
const translation = 'bananas';
const i18nMap: Record<string, string> = { [newLabel]: translation };
const wrapper = mount(LabeledSelect, {
propsData: {
value,
localizedLabel: true,
options: [
{ label: oldLabel, value },
],
},
mocks: { $store: { getters: { 'i18n/t': (text: string) => i18nMap[text] } } }
});
await wrapper.setProps({
options: [
{ label: newLabel, value },
]
});
// Component is from a library and class is not going to be changed
expect(wrapper.find('.vs__selected').text()).toBe(translation);
});
});
}); });
}); });