Skip to content

Commit

Permalink
feat: add test scripts and bump Vue version to 3.3 to use inheritAttr…
Browse files Browse the repository at this point in the history
…s: false
  • Loading branch information
davidnixon committed Jul 5, 2023
1 parent a72ce97 commit e38e0f0
Show file tree
Hide file tree
Showing 30 changed files with 434 additions and 63 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-plugin-unit-jest": "^5.0.8",
"@vue/cli-service": "^5.0.8",
"@vue/compiler-sfc": "^3.2.45",
"@vue/compiler-sfc": "^3.3.4",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/test-utils": "^2.2.4",
"@vue/vue3-jest": "^27.0.0",
Expand All @@ -70,7 +70,7 @@
"stylelint": "^14.15.0",
"stylelint-config-property-sort-order-smacss": "^9.0.0",
"stylelint-config-sass-guidelines": "^9.0.1",
"vue": "^3.2.45",
"vue": "^3.3.4",
"vue-loader": "^17.0.1",
"webpack": "^5.75.0"
},
Expand Down
8 changes: 4 additions & 4 deletions src/components/CvMultiSelect/CvMultiSelect.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ const defaultTemplate = `
:title="title"
:value="value"
:warningMessage="warningMessage"
@change="change"
@filter="filter"
@change="onChange"
@filter="onFilter"
>
</cv-multi-select>
</div>
Expand All @@ -107,8 +107,8 @@ const slotsTemplate = `
:label="label"
:options="options"
:title="title"
@change="change"
@filter="filter"
@change="onChange"
@filter="onFilter"
>
<template v-if="slotInvalidText" v-slot:invalid-message>That is <span style="font-weight:900">NOT</span> a replicant</template>
<template v-if="slotWarningText" v-slot:warning-message>Are you sure that is a <span style="font-variant-caps: petite-caps;">Replicant</span></template>
Expand Down
5 changes: 5 additions & 0 deletions src/components/CvMultiSelect/CvMultiSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
<div
v-for="(item, index) in data.options"
ref="elOption"
role="menuitem"
:key="`multi-select-${index}`"
:class="[
`${carbonPrefix}--list-box__menu-item`,
Expand Down Expand Up @@ -226,6 +227,10 @@ import {
} from './consts';
import { tagKinds } from '../CvTag/consts';
defineOptions({
inheritAttrs: false,
});
/**
* Select options shape
* @typedef {Object} MultiSelectOption
Expand Down
278 changes: 278 additions & 0 deletions src/components/CvMultiSelect/__tests__/CvMultiSelect.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
import { render } from '@testing-library/vue';
import userEvent from '@testing-library/user-event';
import CvMultiSelect from '../CvMultiSelect.vue';
import CvSelect from '@/components/CvSelect/CvSelect.vue';
import { ref } from 'vue';
const pkdCharacters = [
'Rick Deckard',
'Garland',
'Rachael Rosen',
'Roy Batty',
'Harry Bryant',
'Hannibal Chew',
'Dave Holden',
'Leon Kowalski',
'Taffey Lewis',
'Pris Stratton',
'J.F. Sebastian',
'Dr. Eldon Rosen',
'Zhora Salome',
'John "J.R." Isidore',
'Iran Deckard',
'Wilbur Mercer',
'Buster Friendly',
'Phil Resch',
];
const pkdOptions = pkdCharacters.map(item => {
const nameVal = item.replace(/\W+/g, '_').toLowerCase();
return {
name: nameVal,
label: item,
value: nameVal,
disabled: false,
};
});
const pkdValues = pkdOptions.map(item => item.value);
describe('CvMultiSelect', () => {
it('CvMultiSelect - test default and attrs', async () => {
const ariaLabel = 'ABC-aria-label-123';
// The render method returns a collection of utilities to query your component.
const result = render(CvMultiSelect, {
props: {
options: pkdOptions,
value: pkdValues.slice(3, 6), // select 3 items
},
attrs: {
class: 'ABC-class-123',
'aria-label': ariaLabel,
},
});

const ms = result.container.querySelector('.cv-multi-select');
expect(ms.classList.contains('bx--multi-select__wrapper--inline')).toBe(
false
);

const cb = await result.findByLabelText(ariaLabel);
expect(cb.classList.contains('ABC-class-123')).toBe(true);
await result.findByText('3');
});
it('CvMultiSelect - test selections', async () => {
const ariaLabel = 'ABC-aria-label-123';
const initiallySelected = pkdValues.slice(3, 6); // select 3 items
const initiallySelectedLabels = pkdCharacters.slice(3, 6); // select 3 items
// The render method returns a collection of utilities to query your component.
const result = render(CvMultiSelect, {
props: {
options: pkdOptions,
value: initiallySelected,
},
attrs: {
class: 'ABC-class-123',
'aria-label': ariaLabel,
},
});

const ms = result.container.querySelector('.cv-multi-select');
expect(ms.classList.contains('bx--multi-select__wrapper--inline')).toBe(
false
);

const cb = await result.findByLabelText(ariaLabel);
expect(cb.classList.contains('ABC-class-123')).toBe(true);
await result.findByText('3');

// select an additional item for a total of 4 items
const buttons = await result.findAllByRole('button');
let button;
for (const htmlNode of buttons.values()) {
if (htmlNode.nodeName === 'BUTTON') {
button = htmlNode;
break;
}
}
expect(button).not.toBeUndefined();
const user = userEvent.setup();
await user.click(button);
const closeButton = await result.findByLabelText('close menu');
let menuItems = await result.findAllByRole('menuitem');

// Verify selected items are at the top by default
for (let i = 0; i < initiallySelectedLabels.length; i++) {
const item = menuItems[i];
const label = item.querySelector('label').textContent;
expect(label).toBe(initiallySelectedLabels[i]);
}

expect(menuItems.length).toBe(pkdValues.length);
await user.click(menuItems[9]);
await result.findByText('4');

// click one that is already selected
await user.click(closeButton);
await user.click(button);
menuItems = await result.findAllByRole('menuitem');
await user.click(menuItems[0]);
await result.findByText('3');

// click one that is already selected
await user.click(closeButton);
await user.click(button);
menuItems = await result.findAllByRole('menuitem');
await user.click(menuItems[0]);
await result.findByText('2');

// click one that is already selected
await user.click(closeButton);
await user.click(button);
menuItems = await result.findAllByRole('menuitem');
await user.click(menuItems[0]);
let tags = await result.queryByRole('listitem');
expect(tags).toBeDefined();
await result.findByText('1');

// click one that is already selected
await user.click(closeButton);
await user.click(button);
menuItems = await result.findAllByRole('menuitem');
await user.click(menuItems[0]);
tags = await result.queryByRole('listitem');
expect(tags).toBeFalsy();
});
it('CvMultiSelect - test helper slot', async () => {
const label = 'ABC-label-123';
const helper = 'ABC-helper-123';
const helperSlot = 'ABC-helper-slot-text-123';
const slots = {
'helper-text': helperSlot,
};

// The render method returns a collection of utilities to query your component.
let result = render(CvSelect, {
props: {
label: label,
helperText: helper,
},
slots: slots,
});

await result.findByLabelText(label);
await result.findByText(helperSlot);
const ht = await result.queryByText(helper);
expect(ht).toBeFalsy();
});
it('CvMultiSelect - test warning slot', async () => {
const label = 'ABC-label-123';
const helper = 'ABC-helper-123';
const helperSlot = 'ABC-helper-slot-text-123';
const warning = 'ABC-warning-123';
const warningSlot = 'ABC-warning-slot-text-123';
const slots = {
'helper-text': helperSlot,
'warning-message': warningSlot,
};

// The render method returns a collection of utilities to query your component.
let result = render(CvSelect, {
props: {
label: label,
helperText: helper,
warningMessage: warning,
},
slots: slots,
});

await result.findByLabelText(label);
const ht = await result.queryByText(helper);
expect(ht).toBeFalsy();
const hs = await result.queryByText(helperSlot);
expect(hs).toBeFalsy();
const wt = await result.queryByText(warning);
expect(wt).toBeFalsy();
await result.findByText(warningSlot);
});
it('CvMultiSelect - test invalid slot', async () => {
const label = 'ABC-label-123';
const helper = 'ABC-helper-123';
const helperSlot = 'ABC-helper-slot-text-123';
const warning = 'ABC-warning-123';
const warningSlot = 'ABC-warning-slot-text-123';
const invalid = 'ABC-invalid-123';
const invalidSlot = 'ABC-invalid-slot-text-123';
const slots = {
'helper-text': helperSlot,
'warning-message': warningSlot,
'invalid-message': invalidSlot,
};

// The render method returns a collection of utilities to query your component.
let result = render(CvSelect, {
props: {
label: label,
helperText: helper,
warningMessage: warning,
invalidMessage: invalid,
},
slots: slots,
});

await result.findByLabelText(label);
const ht = await result.queryByText(helper);
expect(ht).toBeFalsy();
const hs = await result.queryByText(helperSlot);
expect(hs).toBeFalsy();
const wt = await result.queryByText(warning);
expect(wt).toBeFalsy();
const ws = await result.queryByText(warningSlot);
expect(ws).toBeFalsy();
const it = await result.queryByText(invalid);
expect(it).toBeFalsy();
await result.findByText(invalidSlot);
});
it('CvMultiSelect - v-model', async () => {
const initiallySelectedLabels = pkdCharacters.slice(3, 6); // select 3 items
let myValue = pkdValues.slice(3, 6);
const options = {
props: {
options: pkdOptions,
value: myValue,
'onUpdate:value': e => {
myValue = e;
},
},
};
// The render method returns a collection of utilities to query your component.
const result = render(CvMultiSelect, options);

// select an additional item for a total of 4 items
const buttons = await result.findAllByRole('button');
let button;
for (const htmlNode of buttons.values()) {
if (htmlNode.nodeName === 'BUTTON') {
button = htmlNode;
break;
}
}
expect(button).not.toBeUndefined();
const user = userEvent.setup();
await user.click(button);
const closeButton = await result.findByLabelText('close menu');
let menuItems = await result.findAllByRole('menuitem');

// Verify selected items are at the top by default
for (let i = 0; i < myValue.length; i++) {
const item = menuItems[i];
const label = item.querySelector('label').textContent;
expect(label).toBe(initiallySelectedLabels[i]);
}

expect(menuItems.length).toBe(pkdValues.length);
await user.click(menuItems[9]);
await result.findByText('4');
expect(myValue.length).toBe(4);

await user.click(menuItems[10]);
await result.findByText('5');
expect(myValue.length).toBe(5);
});
});
4 changes: 2 additions & 2 deletions storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"@storybook/addon-storysource": "^6.5.15",
"stylelint-config-property-sort-order-smacss": "^9.0.0",
"stylelint-config-sass-guidelines": "^9.0.1",
"vue": "^3.2.45"
"vue": "^3.3.4"
},
"devDependencies": {
"@babel/core": "^7.17.10",
Expand All @@ -48,7 +48,7 @@
"@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-plugin-unit-jest": "^5.0.8",
"@vue/cli-service": "^5.0.8",
"@vue/compiler-sfc": "^3.2.45",
"@vue/compiler-sfc": "^3.3.4",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/test-utils": "^2.2.4",
"@vue/vue3-jest": "^27.0.0",
Expand Down
Loading

0 comments on commit e38e0f0

Please sign in to comment.