Skip to content

Commit

Permalink
Update ListUniqueValues component
Browse files Browse the repository at this point in the history
- Add a spinner when colunm unique values are loading
- Emit an event at click on "Load All Values" button
  • Loading branch information
raphael committed Apr 10, 2020
1 parent 7b38388 commit e1303d4
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 69 deletions.
58 changes: 41 additions & 17 deletions src/components/ListUniqueValues.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,24 @@
<span class="list-unique-values__select-all" @click="selectAll">Select all</span> &nbsp;
<span class="list-unique-values__clear-all" @click="clearAll">Clear all</span>
</div>
<div
class="list-unique-values__checkbox-container"
v-for="option in searchedOptions"
:key="option.value"
>
<CheckboxWidget
:label="`${option.value} (${option.count})`"
:value="isChecked(option)"
@input="toggleCheck(option)"
/>
</div>
<div class="list-unique-values__load-all-values" v-if="loaded">
<div>List maybe incomplete</div>
<div @click="loadAllValues" class="list-unique-values__load-all-values-button">
Load all values
<div v-if="isLoadingFunction(filter.column)" class="list-unique-values__loader-spinner" />
<div v-else>
<div
class="list-unique-values__checkbox-container"
v-for="option in searchedOptions"
:key="option.value"
>
<CheckboxWidget
:label="`${option.value} (${option.count})`"
:value="isChecked(option)"
@input="toggleCheck(option)"
/>
</div>
<div class="list-unique-values__load-all-values" v-if="loaded">
<div>List maybe incomplete</div>
<div @click="loadAllValues" class="list-unique-values__load-all-values-button">
Load all values
</div>
</div>
</div>
</div>
Expand All @@ -31,6 +34,9 @@ import _union from 'lodash/union';
import { Component, Prop, Vue } from 'vue-property-decorator';
import { FilterConditionInclusion } from '@/lib/steps.ts';
import { VQBModule } from '@/store';
import CheckboxWidget from './stepforms/widgets/Checkbox.vue';
// This type will be imported from @/lib/dataset/helpers.ts
type ColumnValueStat = {
Expand All @@ -46,7 +52,6 @@ type ColumnValueStat = {
value: ['France', 'UK', 'Spain']
}
*/
import CheckboxWidget from './stepforms/widgets/Checkbox.vue';
@Component({
name: 'list-unique-values',
components: { CheckboxWidget },
Expand All @@ -70,6 +75,8 @@ export default class ListUniqueValues extends Vue {
})
loaded!: boolean;
@VQBModule.Getter('isUniqueValuesLoading') isLoadingFunction!: (column: string) => boolean;
search = '';
isChecked(option: ColumnValueStat): boolean {
Expand Down Expand Up @@ -138,7 +145,7 @@ export default class ListUniqueValues extends Vue {
}
loadAllValues() {
throw new Error('Not implemented');
this.$emit('loadAllValues');
}
}
</script>
Expand Down Expand Up @@ -202,6 +209,23 @@ export default class ListUniqueValues extends Vue {
.list-unique-values__load-all-values-button {
text-decoration: underline;
font-weight: 700;
cursor: pointer;
}
}
.list-unique-values__loader-spinner {
border-radius: 50%;
border: 4px solid #efefef;
border-top-color: $active-color;
width: 30px;
height: 30px;
animation: spin 1500ms ease-in-out infinite;
margin: 30px auto;
}
@keyframes spin {
to {
transform: rotate(1turn);
}
}
</style>
118 changes: 66 additions & 52 deletions tests/unit/list-unique-values.spec.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,62 @@
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { createLocalVue, shallowMount, Wrapper } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';

import ListUniqueValues from '@/components/ListUniqueValues.vue';
import { FilterConditionInclusion } from '@/lib/steps.ts';

import { setupMockStore } from './utils';

const localVue = createLocalVue();
localVue.use(Vuex);

describe('List Unique Value', () => {
const DUMMY_UNIQUE_VALUES = [
{ value: 'France', count: 10 },
{ value: 'Framboise', count: 9 },
{ value: 'UK', count: 4 },
{ value: 'Spain', count: 2 },
];
let filter!: FilterConditionInclusion;
let wrapper: any;

let wrapper: Wrapper<Vue>;
/**
`shallowMountWrapper` is utility function for the `ListUniqueValues` component
It shallow mount the component with several options:
@param filterValue the value key of the prop `filter`
@param operator the operator key of the prop `filter`
@param loaded the `loaded` props of the component
@param isUniqueValuesLoading the store parameter indicating if column unique value is loading
By default the wrapper is mounted with 4 options: "France", "Framboise", "Spain" and "UK"
- The checked values are "France" and "Spain"
- All uniques are loaded
*/
const shallowMountWrapper = (
filterValue: string[] = ['France', 'Spain'],
operator: 'in' | 'nin' = 'in',
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
loaded: boolean = true,
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
isUniqueValuesLoading: boolean = false,
): Wrapper<Vue> => {
return shallowMount(ListUniqueValues, {
store: setupMockStore({
dataset: {
headers: [{ name: 'col1', isUniqueValuesLoading }],
data: [],
},
}),
localVue,
propsData: {
filter: {
column: 'col1',
operator,
value: filterValue,
},
options: [
{ value: 'France', count: 10 },
{ value: 'Framboise', count: 9 },
{ value: 'UK', count: 4 },
{ value: 'Spain', count: 2 },
],
loaded,
},
});
};
beforeEach(() => {
filter = {
column: 'col1',
operator: 'in',
value: ['France', 'Spain'],
};
wrapper = shallowMount(ListUniqueValues, {
propsData: { filter, options: DUMMY_UNIQUE_VALUES, loaded: true },
});
wrapper = shallowMountWrapper();
});

it('should display the list of unique values and how much time they are present in the whole dataset', () => {
Expand All @@ -47,14 +78,7 @@ describe('List Unique Value', () => {
});

it('should display the list of unique values and how much time they are present in the whole dataset (with "nin" operator)', () => {
filter = {
column: 'col1',
operator: 'nin',
value: ['Framboise', 'UK'],
};
wrapper = shallowMount(ListUniqueValues, {
propsData: { filter, options: DUMMY_UNIQUE_VALUES, loaded: true },
});
wrapper = shallowMountWrapper(['France', 'Spain'], 'nin');
expect(wrapper.exists()).toBeTruthy();
const CheckboxWidgetArray = wrapper.findAll('CheckboxWidget-stub');
expect(CheckboxWidgetArray.length).toEqual(4);
Expand All @@ -65,38 +89,35 @@ describe('List Unique Value', () => {
});

it('should instantiate with correct value checked (with "nin" operator)', () => {
filter = {
column: 'col1',
operator: 'nin',
value: ['Framboise', 'UK'],
};
wrapper = shallowMount(ListUniqueValues, {
propsData: { filter, options: DUMMY_UNIQUE_VALUES, loaded: true },
});
wrapper = shallowMountWrapper(['Framboise', 'UK'], 'nin');
const CheckboxWidgetArray = wrapper.findAll('CheckboxWidget-stub');
expect(CheckboxWidgetArray.at(0).vm.$props.value).toBeTruthy();
expect(CheckboxWidgetArray.at(1).vm.$props.value).toBeFalsy();
expect(CheckboxWidgetArray.at(2).vm.$props.value).toBeFalsy();
expect(CheckboxWidgetArray.at(3).vm.$props.value).toBeTruthy();
});

it('should instantiate without the spinner', async () => {
expect(wrapper.find('.list-unique-values__loader-spinner').exists()).toBeFalsy();
});

it('should instantiate with the spinner', async () => {
wrapper = shallowMountWrapper(['France', 'Spain'], 'in', true, true);
expect(wrapper.find('.list-unique-values__loader-spinner').exists()).toBeTruthy();
});

describe('"load all values" message', () => {
it('should instantiate with the "load all values" message', () => {
expect(wrapper.find('.list-unique-values__load-all-values').exists()).toBeTruthy();
});

it('should throw an error when click on "load all values"', async () => {
try {
await wrapper.find('.list-unique-values__load-all-values-button').trigger('click');
} catch (e) {
expect(e).toEqual(Error('Not implemented'));
}
it('should emit "loadAllValues" when click on "load all values"', async () => {
await wrapper.find('.list-unique-values__load-all-values-button').trigger('click');
expect(wrapper.emitted().loadAllValues.length).toBe(1);
});

it('should not instantiate with the "load all values" message', () => {
wrapper = shallowMount(ListUniqueValues, {
propsData: { filter, options: DUMMY_UNIQUE_VALUES, loaded: false },
});
wrapper = shallowMountWrapper(['France', 'Spain'], 'in', false);
expect(wrapper.find('.list-unique-values__load-all-values').exists()).toBeFalsy();
});
});
Expand Down Expand Up @@ -186,14 +207,7 @@ describe('List Unique Value', () => {

describe('search box with "nin" operator', () => {
beforeEach(async () => {
filter = {
column: 'col1',
operator: 'nin',
value: ['France', 'Spain'],
};
wrapper = shallowMount(ListUniqueValues, {
propsData: { filter, options: DUMMY_UNIQUE_VALUES, loaded: true },
});
wrapper = shallowMountWrapper(['France', 'Spain'], 'nin');
const input = wrapper.find('.list-unique-values__search-box').element as HTMLInputElement;
input.value = 'Fr'; // "Fr" like the start of "France" and "Framboise"
await wrapper.find('.list-unique-values__search-box').trigger('input');
Expand Down

0 comments on commit e1303d4

Please sign in to comment.