Skip to content

Commit

Permalink
feat: cvNumberInput tests
Browse files Browse the repository at this point in the history
  • Loading branch information
OlkaB committed Jul 17, 2023
1 parent e62582b commit 2b5b046
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 19 deletions.
44 changes: 25 additions & 19 deletions src/components/CvNumberInput/CvNumberInput.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,6 @@ export default {
description:
"Toggles light version. For use on `$ui-01` backgrounds only. Don't use this to make tile background color same as container background color.",
},
modelValue: {
type: 'string',
table: {
type: { summary: 'string' },
category: 'props',
},
description:
"Input's value, modelValue is the vue3 default 'prop' for two-way data binding with v-model",
},
warnText: {
type: 'string',
table: {
Expand Down Expand Up @@ -199,28 +190,43 @@ Default.parameters = storyParametersObject(
Default.args
);

const vModelTemplate = `
<cv-number-input v-bind="args" v-model="value" />
<p style="margin-top: 1rem;">Entered value: {{ value }}</p>
const vModelHTML = `
<cv-number-input v-bind="args" v-model="modelValue" />
<p style="margin-top: 1rem;">Entered value: {{ modelValue }} | typeof: {{ typeof modelValue }}</p>
`;
const VModelTemplate = args => {
const NumericVModelTemplate = args => {
return {
components: { CvNumberInput },
setup: () => ({ args, value: ref(3) }),
template: vModelTemplate,
setup: () => ({ args, modelValue: ref(3) }),
template: vModelHTML,
};
};
export const vModel = VModelTemplate.bind({});
export const vModel = NumericVModelTemplate.bind({});
vModel.parameters = storyParametersObject(
vModel.parameters,
vModelTemplate,
vModelHTML,
vModel.args
);

export const NumberValue = VModelTemplate.bind({});
export const NumberValue = NumericVModelTemplate.bind({});
NumberValue.parameters = storyParametersObject(
NumberValue.parameters,
template,
vModelHTML,
NumberValue.args
);

const StringVModelTemplate = args => {
return {
components: { CvNumberInput },
setup: () => ({ args, modelValue: ref('3') }),
template: vModelHTML,
};
};

export const StringValue = StringVModelTemplate.bind({});
NumberValue.parameters = storyParametersObject(
NumberValue.parameters,
vModelHTML,
NumberValue.args
);

Expand Down
250 changes: 250 additions & 0 deletions src/components/CvNumberInput/__tests__/CvNumberInput.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
import { shallowMount, mount } from '@vue/test-utils';
import CvNumberInput from '../CvNumberInput.vue';

describe('CvNumberInput', () => {
// ***************
// SNAPSHOT TESTS
// ***************

it('should match snapshot when all props are default', async () => {
const wrapper = await shallowMount(CvNumberInput);
expect(wrapper.html()).toMatchSnapshot();
});

it('should match snapshot when it is not a formItem', async () => {
const formItem = false;
const wrapper = await shallowMount(CvNumberInput, { props: { formItem } });
expect(wrapper.html()).toMatchSnapshot();
});

it('should match snapshot when all props are provided', async () => {
const formItem = false;
const helperText = 'helperText';
const invalidMessage = 'invalidMessage';
const label = 'label';
const value = 5;
const ariaLabelForDownButton = 'ariaLabelForDownButton';
const ariaLabelForUpButton = 'ariaLabelForUpButton';
const wrapper = await shallowMount(CvNumberInput, {
props: {
formItem,
helperText,
invalidMessage,
label,
value,
ariaLabelForDownButton,
ariaLabelForUpButton,
},
});
expect(wrapper.html()).toMatchSnapshot();
});

it('should match snapshot when value is String', async () => {
const formItem = false;
const value = '15';
const wrapper = await shallowMount(CvNumberInput, {
props: { formItem, value },
});
expect(wrapper.html()).toMatchSnapshot();
});

it('should match snapshot when value is Number', async () => {
const formItem = false;
const value = 5;
const wrapper = await shallowMount(CvNumberInput, {
props: { formItem, value },
});
expect(wrapper.html()).toMatchSnapshot();
});

it('should match snapshot with min, max and step as Strings', async () => {
const formItem = false;
const value = '15';
const min = '-10';
const max = '10';
const step = '2';
const wrapper = await shallowMount(CvNumberInput, {
props: { formItem, value, min, max, step },
});
expect(wrapper.html()).toMatchSnapshot();
});

it('should match snapshot with optional min, max and step as numbers', async () => {
const formItem = false;
const value = 15;
const min = -10;
const max = 10;
const step = 2;
const wrapper = await shallowMount(CvNumberInput, {
props: { formItem, value, min, max, step },
});
expect(wrapper.html()).toMatchSnapshot();
});

it('should match snapshot when light theme', async () => {
const formItem = false;
const theme = 'light';
const wrapper = await shallowMount(CvNumberInput, {
props: { formItem, theme },
});
expect(wrapper.html()).toMatchSnapshot();
});

it('should match snapshot when invalid-message slot is provided', async () => {
const value = 5;
const props = { value };
const wrapper = await shallowMount(CvNumberInput, {
slots: {
'invalid-message': '<div class="fake-slot">my invalid message</div>',
},
props,
});
expect(wrapper.html()).toMatchSnapshot();
});

it('should match snapshot when helper-text slot is provided', async () => {
const value = 5;
const props = { value };
const wrapper = await shallowMount(CvNumberInput, {
slots: {
'helper-text': '<div class="fake-slot">my helper text</div>',
},
props,
});
expect(wrapper.html()).toMatchSnapshot();
});

// ***************
// FUNCTIONAL TESTS
// ***************
const EmittedModelValueEvent = 'update:modelValue';
const DefaultModelValue = 2;

const testEmittedModelValue = async (wrapper, expectedValue) => {
const modelValueEvent = wrapper.emitted(EmittedModelValueEvent);
await expect(modelValueEvent).toBeTruthy();
await expect(modelValueEvent[0][0]).toEqual(expectedValue);
};

const mountDefaultSetup = (modelValue = DefaultModelValue) => {
return mount(CvNumberInput, { props: { modelValue } });
};

it('should emit input on doDown', async () => {
const expectedValue = 1;

const wrapper = mountDefaultSetup();
const downButtonNode = wrapper.find('.down-icon');
await downButtonNode.trigger('click');

await testEmittedModelValue(wrapper, expectedValue);
});

it('should emit input on doUp', async () => {
const expectedValue = 3;

const wrapper = mountDefaultSetup();
const upButtonNode = wrapper.find('.up-icon');
await upButtonNode.trigger('click');

await testEmittedModelValue(wrapper, expectedValue);
});

it('should emit input on change', async () => {
const inputValue = 5;
const expectedValue = inputValue;

const wrapper = mountDefaultSetup();
wrapper.find('input').setValue(inputValue);
await wrapper.find('input').trigger('input');

await testEmittedModelValue(wrapper, expectedValue);
});

it('should emit String when value prop is String', async () => {
const modelValue = '555';
const expectedValue = '556';

const wrapper = mount(CvNumberInput, { props: { modelValue } });
const upButtonNode = wrapper.find('.up-icon');
await upButtonNode.trigger('click');

await testEmittedModelValue(wrapper, expectedValue);
});

it('should emit value increased by 1 on doUp', async () => {
const modelValue = 555;
const expectedValue = 556;

const wrapper = mount(CvNumberInput, { props: { modelValue } });
const upButtonNode = wrapper.find('.up-icon');
await upButtonNode.trigger('click');

await testEmittedModelValue(wrapper, expectedValue);
});

it('should emit value decreased by 1 on doDown', async () => {
const modelValue = 555;
const expectedValue = 554;

const wrapper = mount(CvNumberInput, { props: { modelValue } });
const upButtonNode = wrapper.find('.down-icon');
await upButtonNode.trigger('click');

await testEmittedModelValue(wrapper, expectedValue);
});

it('should respect max value', async () => {
const modelValue = 9;
const step = 2;
const max = 10;
const expectedValue = max;

const wrapper = mount(CvNumberInput, { props: { step, modelValue, max } });
await wrapper.find('.up-icon').trigger('click');
await wrapper.find('.up-icon').trigger('click');
const modelValueEvent = wrapper.emitted(EmittedModelValueEvent);

await expect(modelValueEvent[0][0]).toEqual(expectedValue);
await expect(modelValueEvent[1][0]).toEqual(expectedValue);
});

it('should respect min value', async () => {
const modelValue = 2;
const step = 2;
const min = 1;
const expectedValue = min;

const wrapper = await mount(CvNumberInput, {
props: { step, modelValue, min },
});
await wrapper.find('.down-icon').trigger('click');
await wrapper.find('.down-icon').trigger('click');
const modelValueEvent = wrapper.emitted(EmittedModelValueEvent);

await expect(modelValueEvent[0][0]).toEqual(expectedValue);
await expect(modelValueEvent[1][0]).toEqual(expectedValue);
});

it('should emit the correct value on input', async () => {
const modelValue = 2;
const inputValue = 100;
const expectedValue = inputValue;

const wrapper = await mount(CvNumberInput, { props: { modelValue } });
wrapper.find('input').setValue(inputValue);
await wrapper.find('input').trigger('input');
testEmittedModelValue(wrapper, expectedValue);
});

it('should watch modelValue', async () => {
const modelValue = 2;
const inputValue = 80;
const expectedValue = inputValue;

const wrapper = await mount(CvNumberInput, { props: { modelValue } });
await wrapper.setProps({ modelValue: inputValue });

expect(wrapper.vm.modelValue).toEqual(expectedValue);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CvNumberInput should match snapshot when all props are default 1`] = `<cv-wrapper-stub tagtype="div" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

exports[`CvNumberInput should match snapshot when all props are provided 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

exports[`CvNumberInput should match snapshot when helper-text slot is provided 1`] = `<cv-wrapper-stub tagtype="div" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

exports[`CvNumberInput should match snapshot when invalid-message slot is provided 1`] = `<cv-wrapper-stub tagtype="div" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

exports[`CvNumberInput should match snapshot when it is not a formItem 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

exports[`CvNumberInput should match snapshot when light theme 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

exports[`CvNumberInput should match snapshot when value is Number 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

exports[`CvNumberInput should match snapshot when value is String 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

exports[`CvNumberInput should match snapshot with min, max and step as Strings 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

exports[`CvNumberInput should match snapshot with optional min, max and step as numbers 1`] = `<cv-wrapper-stub tagtype="" class="cv-number-input bx--form-item"></cv-wrapper-stub>`;

0 comments on commit 2b5b046

Please sign in to comment.