Frontend: Review app changes
This commit is contained in:
parent
1438e322a5
commit
25170fbe7b
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
|
||||
import FilteredSearchDropdown from '~/vue_shared/components/filtered_search_dropdown.vue';
|
||||
import timeagoMixin from '../../vue_shared/mixins/timeago';
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
import LoadingButton from '../../vue_shared/components/loading_button.vue';
|
||||
|
@ -18,6 +19,7 @@ export default {
|
|||
StatusIcon,
|
||||
Icon,
|
||||
TooltipOnTruncate,
|
||||
FilteredSearchDropdown,
|
||||
},
|
||||
directives: {
|
||||
tooltip,
|
||||
|
@ -30,8 +32,10 @@ export default {
|
|||
},
|
||||
},
|
||||
data() {
|
||||
const features = window.gon.features || {};
|
||||
return {
|
||||
isStopping: false,
|
||||
enableCiEnvironmentsStatusChanges: features.ciEnvironmentsStatusChanges,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -118,18 +122,65 @@ export default {
|
|||
/>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
v-if="hasExternalUrls"
|
||||
:href="deployment.external_url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
class="deploy-link js-deploy-url btn btn-default btn-sm inline"
|
||||
>
|
||||
<span>
|
||||
View app
|
||||
<icon name="external-link" />
|
||||
</span>
|
||||
</a>
|
||||
<template v-if="hasExternalUrls">
|
||||
<filtered-search-dropdown
|
||||
v-if="enableCiEnvironmentsStatusChanges"
|
||||
class="js-mr-wigdet-deployment-dropdown inline"
|
||||
:items="deployment.changes"
|
||||
:main-action-link="deployment.external_url"
|
||||
filter-key="path"
|
||||
>
|
||||
<template
|
||||
slot="mainAction"
|
||||
slot-scope="slotProps"
|
||||
>
|
||||
<a
|
||||
:href="deployment.external_url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
class="deploy-link js-deploy-url inline"
|
||||
:class="slotProps.className"
|
||||
>
|
||||
<span>
|
||||
{{ __('View app') }}
|
||||
<icon name="external-link" />
|
||||
</span>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<template
|
||||
slot="result"
|
||||
slot-scope="slotProps"
|
||||
>
|
||||
<a
|
||||
:href="slotProps.result.external_url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
class="menu-item"
|
||||
>
|
||||
<strong class="str-truncated-100 append-bottom-0 d-block">
|
||||
{{ slotProps.result.path }}
|
||||
</strong>
|
||||
|
||||
<p class="text-secondary str-truncated-100 append-bottom-0 d-block">
|
||||
{{ slotProps.result.external_url }}
|
||||
</p>
|
||||
</a>
|
||||
</template>
|
||||
</filtered-search-dropdown>
|
||||
<a
|
||||
v-else
|
||||
:href="deployment.external_url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow"
|
||||
class="js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inline"
|
||||
>
|
||||
<span>
|
||||
{{ __('View app') }}
|
||||
<icon name="external-link" />
|
||||
</span>
|
||||
</a>
|
||||
</template>
|
||||
<loading-button
|
||||
v-if="deployment.stop_url"
|
||||
:loading="isStopping"
|
||||
|
|
|
@ -112,7 +112,8 @@ export default {
|
|||
eventHub.$on('mr.discussion.updated', this.checkStatus);
|
||||
},
|
||||
mounted() {
|
||||
this.handleMounted();
|
||||
this.setFaviconHelper();
|
||||
this.initDeploymentsPolling();
|
||||
},
|
||||
beforeDestroy() {
|
||||
eventHub.$off('mr.discussion.updated', this.checkStatus);
|
||||
|
@ -250,10 +251,6 @@ export default {
|
|||
this.stopPolling();
|
||||
});
|
||||
},
|
||||
handleMounted() {
|
||||
this.setFaviconHelper();
|
||||
this.initDeploymentsPolling();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
<script>
|
||||
import $ from 'jquery';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
/**
|
||||
* Renders a split dropdown with
|
||||
* an input that allows to search through the given
|
||||
* array of options.
|
||||
*/
|
||||
export default {
|
||||
name: 'FilteredSearchDropdown',
|
||||
components: {
|
||||
Icon,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
buttonType: {
|
||||
required: false,
|
||||
validator: value =>
|
||||
['primary', 'default', 'secondary', 'success', 'info', 'warning', 'danger'].indexOf(
|
||||
value,
|
||||
) !== -1,
|
||||
default: 'default',
|
||||
},
|
||||
size: {
|
||||
required: false,
|
||||
type: String,
|
||||
default: 'sm',
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
visibleItems: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 5,
|
||||
},
|
||||
filterKey: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filter: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
className() {
|
||||
return `btn btn-${this.buttonType} btn-${this.size}`;
|
||||
},
|
||||
filteredResults() {
|
||||
if (this.filter !== '') {
|
||||
return this.items.filter(
|
||||
item => item[this.filterKey] && item[this.filterKey].toLowerCase().includes(this.filter.toLowerCase()),
|
||||
);
|
||||
}
|
||||
|
||||
return this.items.slice(0, this.visibleItems);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
/**
|
||||
* Resets the filter every time the user closes the dropdown
|
||||
*/
|
||||
$(this.$el)
|
||||
.on('shown.bs.dropdown', () => {
|
||||
this.$nextTick(() => this.$refs.searchInput.focus());
|
||||
})
|
||||
.on('hidden.bs.dropdown', () => {
|
||||
this.filter = '';
|
||||
});
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="dropdown">
|
||||
<div class="btn-group">
|
||||
<slot
|
||||
name="mainAction"
|
||||
:class-name="className"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
:class="className"
|
||||
>
|
||||
{{ title }}
|
||||
</button>
|
||||
</slot>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
:class="className"
|
||||
class="dropdown-toggle dropdown-toggle-split"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
aria-label="Expand dropdown"
|
||||
>
|
||||
<icon
|
||||
name="angle-down"
|
||||
:size="12"
|
||||
/>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<div class="dropdown-input">
|
||||
<input
|
||||
ref="searchInput"
|
||||
v-model="filter"
|
||||
type="search"
|
||||
placeholder="Filter"
|
||||
class="js-filtered-dropdown-input dropdown-input-field"
|
||||
/>
|
||||
<icon
|
||||
class="dropdown-input-search"
|
||||
name="search"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-content">
|
||||
<ul>
|
||||
<li
|
||||
v-for="(result, i) in filteredResults"
|
||||
:key="i"
|
||||
class="js-filtered-dropdown-result"
|
||||
>
|
||||
<slot
|
||||
name="result"
|
||||
:result="result"
|
||||
>
|
||||
{{ result[filterKey] }}
|
||||
</slot>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -47,7 +47,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.mr-widget-heading {
|
||||
position: relative;
|
||||
border: 1px solid $border-color;
|
||||
|
@ -454,7 +453,7 @@
|
|||
|
||||
.mr-list {
|
||||
.merge-request {
|
||||
padding: 10px 0 10px 15px;
|
||||
padding: 10px 0 10px 15px;
|
||||
position: relative;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
|
@ -468,7 +467,6 @@
|
|||
margin-bottom: 2px;
|
||||
|
||||
.ci-status-link {
|
||||
|
||||
svg {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
|
@ -698,7 +696,6 @@
|
|||
|
||||
.table-holder {
|
||||
.ci-table {
|
||||
|
||||
th {
|
||||
background-color: $white-light;
|
||||
color: $gl-text-color-secondary;
|
||||
|
@ -775,7 +772,7 @@
|
|||
|
||||
&.affix {
|
||||
left: 0;
|
||||
transition: right .15s;
|
||||
transition: right 0.15s;
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
right: 0;
|
||||
|
@ -884,7 +881,7 @@
|
|||
}
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: .3em;
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
|
||||
svg {
|
||||
|
@ -907,6 +904,10 @@
|
|||
.btn svg {
|
||||
fill: $theme-gray-700;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
width: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
// Hack alert: we've rewritten `btn` class in a way that
|
||||
|
@ -917,7 +918,7 @@
|
|||
&[disabled] {
|
||||
cursor: not-allowed;
|
||||
box-shadow: none;
|
||||
opacity: .65;
|
||||
opacity: 0.65;
|
||||
|
||||
&:hover {
|
||||
color: $gl-gray-500;
|
||||
|
|
|
@ -14,6 +14,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
before_action :set_issuables_index, only: [:index]
|
||||
before_action :authenticate_user!, only: [:assign_related_issues]
|
||||
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
|
||||
before_action do
|
||||
push_frontend_feature_flag(:ci_environments_status_changes)
|
||||
end
|
||||
|
||||
def index
|
||||
@merge_requests = @issuables
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Adds filtered dropdown with changed files in review
|
||||
merge_request:
|
||||
author:
|
||||
type: changed
|
|
@ -6717,6 +6717,9 @@ msgstr ""
|
|||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
msgid "View app"
|
||||
msgstr ""
|
||||
|
||||
msgid "View file @ "
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -14,6 +14,20 @@ const deploymentMockData = {
|
|||
external_url_formatted: 'diplo.',
|
||||
deployed_at: '2017-03-22T22:44:42.258Z',
|
||||
deployed_at_formatted: 'Mar 22, 2017 10:44pm',
|
||||
changes: [
|
||||
{
|
||||
path: 'index.html',
|
||||
external_url: 'http://root-master-patch-91341.volatile-watch.surge.sh/index.html',
|
||||
},
|
||||
{
|
||||
path: 'imgs/gallery.html',
|
||||
external_url: 'http://root-master-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
|
||||
},
|
||||
{
|
||||
path: 'about/',
|
||||
external_url: 'http://root-master-patch-91341.volatile-watch.surge.sh/about/',
|
||||
},
|
||||
],
|
||||
};
|
||||
const createComponent = () => {
|
||||
const Component = Vue.extend(deploymentComponent);
|
||||
|
@ -176,4 +190,42 @@ describe('Deployment component', () => {
|
|||
expect(el.querySelector('.js-mr-memory-usage')).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with `features.ciEnvironmentsStatusChanges` enabled', () => {
|
||||
beforeEach(() => {
|
||||
window.gon = window.gon || {};
|
||||
window.gon.features = window.gon.features || {};
|
||||
window.gon.features.ciEnvironmentsStatusChanges = true;
|
||||
|
||||
vm = createComponent(deploymentMockData);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.gon.features = {};
|
||||
});
|
||||
|
||||
it('renders dropdown with changes', () => {
|
||||
expect(vm.$el.querySelector('.js-mr-wigdet-deployment-dropdown')).not.toBeNull();
|
||||
expect(vm.$el.querySelector('.js-deploy-url-feature-flag')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with `features.ciEnvironmentsStatusChanges` disabled', () => {
|
||||
beforeEach(() => {
|
||||
window.gon = window.gon || {};
|
||||
window.gon.features = window.gon.features || {};
|
||||
window.gon.features.ciEnvironmentsStatusChanges = false;
|
||||
|
||||
vm = createComponent(deploymentMockData);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete window.gon.features.ciEnvironmentsStatusChanges;
|
||||
});
|
||||
|
||||
it('renders the old link to the review app', () => {
|
||||
expect(vm.$el.querySelector('.js-mr-wigdet-deployment-dropdown')).toBeNull();
|
||||
expect(vm.$el.querySelector('.js-deploy-url-feature-flag')).not.toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,11 +7,12 @@ import mountComponent from 'spec/helpers/vue_mount_component_helper';
|
|||
import mockData from './mock_data';
|
||||
import { faviconDataUrl, overlayDataUrl, faviconWithOverlayDataUrl } from '../lib/utils/mock_data';
|
||||
|
||||
const returnPromise = data => new Promise((resolve) => {
|
||||
resolve({
|
||||
data,
|
||||
const returnPromise = data =>
|
||||
new Promise(resolve => {
|
||||
resolve({
|
||||
data,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mrWidgetOptions', () => {
|
||||
let vm;
|
||||
|
@ -135,7 +136,7 @@ describe('mrWidgetOptions', () => {
|
|||
|
||||
describe('methods', () => {
|
||||
describe('checkStatus', () => {
|
||||
it('should tell service to check status', (done) => {
|
||||
it('should tell service to check status', done => {
|
||||
spyOn(vm.service, 'checkStatus').and.returnValue(returnPromise(mockData));
|
||||
spyOn(vm.mr, 'setData');
|
||||
spyOn(vm, 'handleNotification');
|
||||
|
@ -185,7 +186,7 @@ describe('mrWidgetOptions', () => {
|
|||
});
|
||||
|
||||
describe('fetchDeployments', () => {
|
||||
it('should fetch deployments', (done) => {
|
||||
it('should fetch deployments', done => {
|
||||
spyOn(vm.service, 'fetchDeployments').and.returnValue(returnPromise([{ id: 1 }]));
|
||||
|
||||
vm.fetchDeployments();
|
||||
|
@ -200,7 +201,7 @@ describe('mrWidgetOptions', () => {
|
|||
});
|
||||
|
||||
describe('fetchActionsContent', () => {
|
||||
it('should fetch content of Cherry Pick and Revert modals', (done) => {
|
||||
it('should fetch content of Cherry Pick and Revert modals', done => {
|
||||
spyOn(vm.service, 'fetchMergeActionsContent').and.returnValue(returnPromise('hello world'));
|
||||
|
||||
vm.fetchActionsContent();
|
||||
|
@ -251,7 +252,7 @@ describe('mrWidgetOptions', () => {
|
|||
};
|
||||
|
||||
const allArgs = eventHub.$on.calls.allArgs();
|
||||
allArgs.forEach((params) => {
|
||||
allArgs.forEach(params => {
|
||||
const eventName = params[0];
|
||||
const callback = params[1];
|
||||
|
||||
|
@ -270,18 +271,6 @@ describe('mrWidgetOptions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('handleMounted', () => {
|
||||
it('should call required methods to do the initial kick-off', () => {
|
||||
spyOn(vm, 'initDeploymentsPolling');
|
||||
spyOn(vm, 'setFaviconHelper');
|
||||
|
||||
vm.handleMounted();
|
||||
|
||||
expect(vm.setFaviconHelper).toHaveBeenCalled();
|
||||
expect(vm.initDeploymentsPolling).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setFavicon', () => {
|
||||
let faviconElement;
|
||||
|
||||
|
@ -298,13 +287,14 @@ describe('mrWidgetOptions', () => {
|
|||
document.body.removeChild(document.getElementById('favicon'));
|
||||
});
|
||||
|
||||
it('should call setFavicon method', (done) => {
|
||||
it('should call setFavicon method', done => {
|
||||
vm.mr.ciStatusFaviconPath = overlayDataUrl;
|
||||
vm.setFaviconHelper().then(() => {
|
||||
expect(faviconElement.getAttribute('href')).toEqual(faviconWithOverlayDataUrl);
|
||||
done();
|
||||
})
|
||||
.catch(done.fail);
|
||||
vm.setFaviconHelper()
|
||||
.then(() => {
|
||||
expect(faviconElement.getAttribute('href')).toEqual(faviconWithOverlayDataUrl);
|
||||
done();
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
|
||||
it('should not call setFavicon when there is no ciStatusFaviconPath', () => {
|
||||
|
@ -379,7 +369,7 @@ describe('mrWidgetOptions', () => {
|
|||
});
|
||||
|
||||
describe('rendering relatedLinks', () => {
|
||||
beforeEach((done) => {
|
||||
beforeEach(done => {
|
||||
vm.mr.relatedLinks = {
|
||||
assignToMe: null,
|
||||
closing: `
|
||||
|
@ -396,7 +386,7 @@ describe('mrWidgetOptions', () => {
|
|||
expect(vm.$el.querySelector('.close-related-link')).toBeDefined();
|
||||
});
|
||||
|
||||
it('does not render if state is nothingToMerge', (done) => {
|
||||
it('does not render if state is nothingToMerge', done => {
|
||||
vm.mr.state = stateKey.nothingToMerge;
|
||||
Vue.nextTick(() => {
|
||||
expect(vm.$el.querySelector('.close-related-link')).toBeNull();
|
||||
|
@ -406,7 +396,7 @@ describe('mrWidgetOptions', () => {
|
|||
});
|
||||
|
||||
describe('rendering source branch removal status', () => {
|
||||
it('renders when user cannot remove branch and branch should be removed', (done) => {
|
||||
it('renders when user cannot remove branch and branch should be removed', done => {
|
||||
vm.mr.canRemoveSourceBranch = false;
|
||||
vm.mr.shouldRemoveSourceBranch = true;
|
||||
vm.mr.state = 'readyToMerge';
|
||||
|
@ -423,7 +413,7 @@ describe('mrWidgetOptions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('does not render in merged state', (done) => {
|
||||
it('does not render in merged state', done => {
|
||||
vm.mr.canRemoveSourceBranch = false;
|
||||
vm.mr.shouldRemoveSourceBranch = true;
|
||||
vm.mr.state = 'merged';
|
||||
|
@ -438,6 +428,20 @@ describe('mrWidgetOptions', () => {
|
|||
});
|
||||
|
||||
describe('rendering deployments', () => {
|
||||
const changes = [
|
||||
{
|
||||
path: 'index.html',
|
||||
external_url: 'http://root-master-patch-91341.volatile-watch.surge.sh/index.html',
|
||||
},
|
||||
{
|
||||
path: 'imgs/gallery.html',
|
||||
external_url: 'http://root-master-patch-91341.volatile-watch.surge.sh/imgs/gallery.html',
|
||||
},
|
||||
{
|
||||
path: 'about/',
|
||||
external_url: 'http://root-master-patch-91341.volatile-watch.surge.sh/about/',
|
||||
},
|
||||
];
|
||||
const deploymentMockData = {
|
||||
id: 15,
|
||||
name: 'review/diplo',
|
||||
|
@ -449,15 +453,23 @@ describe('mrWidgetOptions', () => {
|
|||
external_url_formatted: 'diplo.',
|
||||
deployed_at: '2017-03-22T22:44:42.258Z',
|
||||
deployed_at_formatted: 'Mar 22, 2017 10:44pm',
|
||||
changes,
|
||||
};
|
||||
|
||||
beforeEach((done) => {
|
||||
vm.mr.deployments.push({
|
||||
...deploymentMockData,
|
||||
}, {
|
||||
...deploymentMockData,
|
||||
id: deploymentMockData.id + 1,
|
||||
});
|
||||
beforeEach(done => {
|
||||
window.gon = window.gon || {};
|
||||
window.gon.features = window.gon.features || {};
|
||||
window.gon.features.ciEnvironmentsStatusChanges = true;
|
||||
|
||||
vm.mr.deployments.push(
|
||||
{
|
||||
...deploymentMockData,
|
||||
},
|
||||
{
|
||||
...deploymentMockData,
|
||||
id: deploymentMockData.id + 1,
|
||||
},
|
||||
);
|
||||
|
||||
vm.$nextTick(done);
|
||||
});
|
||||
|
@ -465,5 +477,13 @@ describe('mrWidgetOptions', () => {
|
|||
it('renders multiple deployments', () => {
|
||||
expect(vm.$el.querySelectorAll('.deploy-heading').length).toBe(2);
|
||||
});
|
||||
|
||||
it('renders dropdpown with multiple file changes', () => {
|
||||
expect(
|
||||
vm.$el
|
||||
.querySelector('.js-mr-wigdet-deployment-dropdown')
|
||||
.querySelectorAll('.js-filtered-dropdown-result').length,
|
||||
).toEqual(changes.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
import Vue from 'vue';
|
||||
import component from '~/vue_shared/components/filtered_search_dropdown.vue';
|
||||
import mountComponent from 'spec/helpers/vue_mount_component_helper';
|
||||
|
||||
describe('Filtered search dropdown', () => {
|
||||
const Component = Vue.extend(component);
|
||||
let vm;
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
});
|
||||
|
||||
describe('with an empty array of items', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(Component, {
|
||||
items: [],
|
||||
filterKey: '',
|
||||
});
|
||||
});
|
||||
|
||||
it('renders empty list', () => {
|
||||
expect(vm.$el.querySelectorAll('.js-filtered-dropdown-result').length).toEqual(0);
|
||||
});
|
||||
|
||||
it('renders filter input', () => {
|
||||
expect(vm.$el.querySelector('.js-filtered-dropdown-input')).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when visible numbers is less than the items length', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(Component, {
|
||||
items: [{ title: 'One' }, { title: 'Two' }, { title: 'Three' }],
|
||||
visibleItems: 2,
|
||||
filterKey: 'title',
|
||||
});
|
||||
});
|
||||
|
||||
it('it renders only the maximum number provided', () => {
|
||||
expect(vm.$el.querySelectorAll('.js-filtered-dropdown-result').length).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when visible number is bigger than the items lenght', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(Component, {
|
||||
items: [{ title: 'One' }, { title: 'Two' }, { title: 'Three' }],
|
||||
filterKey: 'title',
|
||||
});
|
||||
});
|
||||
|
||||
it('it renders the full list of items the maximum number provided', () => {
|
||||
expect(vm.$el.querySelectorAll('.js-filtered-dropdown-result').length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('while filtering', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(Component, {
|
||||
items: [
|
||||
{ title: 'One' },
|
||||
{ title: 'Two/three' },
|
||||
{ title: 'Three four' },
|
||||
{ title: 'Five' },
|
||||
],
|
||||
filterKey: 'title',
|
||||
});
|
||||
});
|
||||
|
||||
it('updates the results to match the typed value', done => {
|
||||
vm.$el.querySelector('.js-filtered-dropdown-input').value = 'three';
|
||||
vm.$el.querySelector('.js-filtered-dropdown-input').dispatchEvent(new Event('input'));
|
||||
vm.$nextTick(() => {
|
||||
expect(vm.$el.querySelectorAll('.js-filtered-dropdown-result').length).toEqual(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when no value matches the typed one', () => {
|
||||
it('does not render any result', done => {
|
||||
vm.$el.querySelector('.js-filtered-dropdown-input').value = 'six';
|
||||
vm.$el.querySelector('.js-filtered-dropdown-input').dispatchEvent(new Event('input'));
|
||||
|
||||
vm.$nextTick(() => {
|
||||
expect(vm.$el.querySelectorAll('.js-filtered-dropdown-result').length).toEqual(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue