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,11 +153,14 @@ 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)));
if (newOption) {
const label = get(newOption, this.optionLabel); const label = get(newOption, this.optionLabel);
return this.localizedLabel ? this.$store.getters['i18n/t'](label) || label : label; return this.localizedLabel ? this.$store.getters['i18n/t'](label) || label : label;
} }
}
if (this.$attrs['get-option-label']) { if (this.$attrs['get-option-label']) {
return this.$attrs['get-option-label'](option); return this.$attrs['get-option-label'](option);

View File

@ -2,7 +2,8 @@ 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', () => {
it('given an existing value and option', () => {
const label = 'Foo'; const label = 'Foo';
const value = 'foo'; const value = 'foo';
const wrapper = mount(LabeledSelect, { const wrapper = mount(LabeledSelect, {
@ -18,10 +19,59 @@ describe('component: LabeledSelect', () => {
expect(wrapper.find('.vs__selected').text()).toBe(label); expect(wrapper.find('.vs__selected').text()).toBe(label);
}); });
it('should update the displayed label if options are changed', async() => { it('using value as label if no options', () => {
const newLabel = 'Baz';
const oldLabel = 'Foo';
const value = 'foo'; const value = 'foo';
const wrapper = mount(LabeledSelect, {
propsData: {
value,
options: [],
}
});
// Component is from a library and class is not going to be changed
expect(wrapper.find('.vs__selected').text()).toBe(value);
});
it('using custom key as label for option object', () => {
const value = 'foo';
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);
});
it('translating localized cases', () => {
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, { const wrapper = mount(LabeledSelect, {
propsData: { propsData: {
value, value,
@ -40,4 +90,49 @@ describe('component: LabeledSelect', () => {
// Component is from a library and class is not going to be changed // Component is from a library and class is not going to be changed
expect(wrapper.find('.vs__selected').text()).toBe(newLabel); 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);
});
});
});
}); });