Commit 449a63ad authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'mrincon-base_token-props-refactor' into 'master'

Refactor base token to make it reusable

See merge request gitlab-org/gitlab!63429
parents b0610d12 1fbf344f
......@@ -71,9 +71,9 @@ export default {
<template>
<base-token
:token-config="config"
:token-value="value"
:token-active="active"
:config="config"
:value="value"
:active="active"
:tokens-list-loading="loading"
:token-values="authors"
:fn-active-token-value="getActiveAuthor"
......@@ -81,6 +81,7 @@ export default {
:preloaded-token-values="preloadedAuthors"
:recent-token-values-storage-key="config.recentTokenValuesStorageKey"
@fetch-token-values="fetchAuthorBySearchTerm"
v-on="$listeners"
>
<template #view="{ viewTokenProps: { inputValue, activeTokenValue } }">
<gl-avatar
......
......@@ -19,29 +19,34 @@ export default {
GlLoadingIcon,
},
props: {
tokenConfig: {
config: {
type: Object,
required: true,
},
tokenValue: {
value: {
type: Object,
required: true,
},
tokenActive: {
active: {
type: Boolean,
required: true,
},
tokensListLoading: {
type: Boolean,
required: true,
required: false,
default: false,
},
tokenValues: {
type: Array,
required: true,
required: false,
default: () => [],
},
fnActiveTokenValue: {
type: Function,
required: true,
required: false,
default: (tokenValues, currentTokenValue) => {
return tokenValues.find(({ value }) => value === currentTokenValue);
},
},
defaultTokenValues: {
type: Array,
......@@ -90,9 +95,9 @@ export default {
},
currentTokenValue() {
if (this.fnCurrentTokenValue) {
return this.fnCurrentTokenValue(this.tokenValue.data);
return this.fnCurrentTokenValue(this.value.data);
}
return this.tokenValue.data.toLowerCase();
return this.value.data.toLowerCase();
},
activeTokenValue() {
return this.fnActiveTokenValue(this.tokenValues, this.currentTokenValue);
......@@ -113,11 +118,11 @@ export default {
},
},
watch: {
tokenActive: {
active: {
immediate: true,
handler(newValue) {
if (!newValue && !this.tokenValues.length) {
this.$emit('fetch-token-values', this.tokenValue.data);
this.$emit('fetch-token-values', this.value.data);
}
},
},
......@@ -148,9 +153,11 @@ export default {
<template>
<gl-filtered-search-token
:config="tokenConfig"
v-bind="{ ...this.$parent.$props, ...this.$parent.$attrs }"
v-on="this.$parent.$listeners"
:config="config"
:value="value"
:active="active"
v-bind="$attrs"
v-on="$listeners"
@input="handleInput"
@select="handleTokenValueSelected(activeTokenValue)"
>
......
......@@ -93,15 +93,16 @@ export default {
<template>
<base-token
:token-config="config"
:token-value="value"
:token-active="active"
:config="config"
:value="value"
:active="active"
:tokens-list-loading="loading"
:token-values="labels"
:fn-active-token-value="getActiveLabel"
:default-token-values="defaultLabels"
:recent-token-values-storage-key="config.recentTokenValuesStorageKey"
@fetch-token-values="fetchLabelBySearchTerm"
v-on="$listeners"
>
<template
#view-token="{ viewTokenProps: { inputValue, cssClasses, listeners, activeTokenValue } }"
......
......@@ -46,6 +46,7 @@ function createComponent(options = {}) {
active = false,
stubs = defaultStubs,
data = {},
listeners = {},
} = options;
return mount(AuthorToken, {
propsData: {
......@@ -62,6 +63,7 @@ function createComponent(options = {}) {
return { ...data };
},
stubs,
listeners,
});
}
......@@ -258,6 +260,18 @@ describe('AuthorToken', () => {
expect(suggestions.at(0).text()).toBe(DEFAULT_LABEL_ANY.text);
});
it('emits listeners in the base-token', () => {
const mockInput = jest.fn();
wrapper = createComponent({
listeners: {
input: mockInput,
},
});
wrapper.findComponent(BaseToken).vm.$emit('input', [{ data: 'mockData', operator: '=' }]);
expect(mockInput).toHaveBeenLastCalledWith([{ data: 'mockData', operator: '=' }]);
});
describe('when loading', () => {
beforeEach(() => {
wrapper = createComponent({
......
......@@ -46,12 +46,11 @@ const defaultSlots = {
};
const mockProps = {
tokenConfig: mockLabelToken,
tokenValue: { data: '' },
tokenActive: false,
tokensListLoading: false,
config: mockLabelToken,
value: { data: '' },
active: false,
tokenValues: [],
fnActiveTokenValue: jest.fn(),
tokensListLoading: false,
defaultTokenValues: DEFAULT_LABELS,
recentTokenValuesStorageKey: mockStorageKey,
fnCurrentTokenValue: jest.fn(),
......@@ -83,7 +82,7 @@ describe('BaseToken', () => {
wrapper = createComponent({
props: {
...mockProps,
tokenValue: { data: `"${mockRegularLabel.title}"` },
value: { data: `"${mockRegularLabel.title}"` },
tokenValues: mockLabels,
},
});
......@@ -112,17 +111,17 @@ describe('BaseToken', () => {
describe('activeTokenValue', () => {
it('calls `fnActiveTokenValue` when it is provided', async () => {
const mockFnActiveTokenValue = jest.fn();
wrapper.setProps({
fnActiveTokenValue: mockFnActiveTokenValue,
fnCurrentTokenValue: undefined,
});
await wrapper.vm.$nextTick();
// We're disabling lint to trigger computed prop execution for this test.
// eslint-disable-next-line no-unused-vars
const { activeTokenValue } = wrapper.vm;
expect(wrapper.vm.fnActiveTokenValue).toHaveBeenCalledWith(
expect(mockFnActiveTokenValue).toHaveBeenCalledTimes(1);
expect(mockFnActiveTokenValue).toHaveBeenCalledWith(
mockLabels,
`"${mockRegularLabel.title.toLowerCase()}"`,
);
......@@ -131,15 +130,15 @@ describe('BaseToken', () => {
});
describe('watch', () => {
describe('tokenActive', () => {
describe('active', () => {
let wrapperWithTokenActive;
beforeEach(() => {
wrapperWithTokenActive = createComponent({
props: {
...mockProps,
tokenActive: true,
tokenValue: { data: `"${mockRegularLabel.title}"` },
value: { data: `"${mockRegularLabel.title}"` },
active: true,
},
});
});
......@@ -150,7 +149,7 @@ describe('BaseToken', () => {
it('emits `fetch-token-values` event on the component when value of this prop is changed to false and `tokenValues` array is empty', async () => {
wrapperWithTokenActive.setProps({
tokenActive: false,
active: false,
});
await wrapperWithTokenActive.vm.$nextTick();
......@@ -238,7 +237,7 @@ describe('BaseToken', () => {
jest.runAllTimers();
expect(wrapperWithNoStubs.emitted('fetch-token-values')).toBeTruthy();
expect(wrapperWithNoStubs.emitted('fetch-token-values')[1]).toEqual(['foo']);
expect(wrapperWithNoStubs.emitted('fetch-token-values')[2]).toEqual(['foo']);
});
});
});
......
......@@ -40,6 +40,7 @@ function createComponent(options = {}) {
value = { data: '' },
active = false,
stubs = defaultStubs,
listeners = {},
} = options;
return mount(LabelToken, {
propsData: {
......@@ -53,6 +54,7 @@ function createComponent(options = {}) {
suggestionsListClass: 'custom-class',
},
stubs,
listeners,
});
}
......@@ -206,7 +208,7 @@ describe('LabelToken', () => {
expect(wrapper.find(GlDropdownDivider).exists()).toBe(false);
});
it('renders `DEFAULT_LABELS` as default suggestions', async () => {
it('renders `DEFAULT_LABELS` as default suggestions', () => {
wrapper = createComponent({
active: true,
config: { ...mockLabelToken },
......@@ -215,7 +217,6 @@ describe('LabelToken', () => {
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
const suggestionsSegment = tokenSegments.at(2);
suggestionsSegment.vm.$emit('activate');
await wrapper.vm.$nextTick();
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
......@@ -224,5 +225,17 @@ describe('LabelToken', () => {
expect(suggestions.at(index).text()).toBe(label.text);
});
});
it('emits listeners in the base-token', () => {
const mockInput = jest.fn();
wrapper = createComponent({
listeners: {
input: mockInput,
},
});
wrapper.findComponent(BaseToken).vm.$emit('input', [{ data: 'mockData', operator: '=' }]);
expect(mockInput).toHaveBeenLastCalledWith([{ data: 'mockData', operator: '=' }]);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment