Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ACS-3919 - small dev fixes, unit tests #152

Merged
merged 2 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ Runs both unit and e2e/accesibility tests.

### Visual Regression Testing

> [!NOTE]
> this has been temporarily disabled due to Vue3 compatibility issues.

Check [backstop](https://github.com/garris/BackstopJS) for general configuration questions.

Our visual regressions audits can be performed against all patterns documented within the project's component proving grounds. To do so, follow the steps below:
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rei/cedar",
"version": "14.1.0",
"version": "14.1.1",
"description": "REI Cedar Component Library",
"homepage": "https://rei.github.io/rei-cedar/",
"license": "MIT",
Expand Down Expand Up @@ -31,6 +31,7 @@
"url": "https://github.com/rei/rei-cedar.git"
},
"scripts": {
"prepare": "npm run build",
daemoncron marked this conversation as resolved.
Show resolved Hide resolved
"prepublishOnly": "npm-run-all lint build",
"dev": "vite",
"build": "vue-tsc && vite build && npm run build:umd && npm run build:extractcss && npm run build:icons && npm run build:docgen",
Expand Down
70 changes: 41 additions & 29 deletions src/components/modal/CdrModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@
import { debounce } from '../../utils/debounce'
import tabbable from 'tabbable';
import {
useCssModule, computed, ref, watch, onMounted, nextTick, onUnmounted, useAttrs,
useCssModule,
computed,
ref,
watch,
onMounted,
nextTick,
onUnmounted,
useAttrs,
} from 'vue';
import {
CdrBreakpointSm, CdrSpaceOneX, CdrSpaceTwoX,
CdrBreakpointSm,
CdrSpaceOneX,
CdrSpaceTwoX,
} from '@rei/cdr-tokens/dist/rei-dot-com/js/cdr-tokens.mjs';
import onTransitionEnd from './onTransitionEnd';
import CdrButton from '../button/CdrButton.vue';
Expand All @@ -14,14 +23,16 @@ import mapClasses from '../../utils/mapClasses';

/** Disruptive, action-blocking overlays used to display important information */
defineOptions({
name: 'CdrModal'
name: 'CdrModal',
inheritAttrs: false,
daemoncron marked this conversation as resolved.
Show resolved Hide resolved
});

const props = defineProps({
/**
* Toggles the state of the modal
* @demoIgnore true
*/
opened: {
opened: {
type: Boolean,
required: true,
},
Expand Down Expand Up @@ -78,10 +89,8 @@ const props = defineProps({
},
});

const emits = defineEmits({
/** Fires when modal is closed */
closed: null,
});
/** Fires when modal is closed */
const emits = defineEmits({ closed: null });

const attrs = useAttrs();
const style = useCssModule();
Expand All @@ -95,8 +104,8 @@ const isOpening = ref(false);
interface offsetValues {
x: number | undefined,
y: number | undefined,
}
const offset = ref<offsetValues>({ x: undefined, y: undefined});
}
const offset = ref<offsetValues>({ x: undefined, y: undefined });
const headerHeight = ref(0);
const totalHeight = ref(0);
const scrollHeight = ref(0);
Expand Down Expand Up @@ -126,7 +135,7 @@ const onClick = (e?: Event) => {
emits('closed', e);
};

const handleKeyDown = ({ key }: { key: string}) => {
const handleKeyDown = ({ key }: { key: string }) => {
switch (key) {
case 'Escape':
case 'Esc':
Expand Down Expand Up @@ -155,13 +164,13 @@ const addNoScroll = () => {
const { documentElement, body } = document;
offset.value = {
x: window.scrollX
|| (documentElement || {}).scrollLeft
|| (body || {}).scrollLeft
|| 0,
|| (documentElement || {}).scrollLeft
|| (body || {}).scrollLeft
|| 0,
y: window.scrollY
|| (documentElement || {}).scrollTop
|| (body || {}).scrollTop
|| 0,
|| (documentElement || {}).scrollTop
|| (body || {}).scrollTop
|| 0,
};

if (documentElement) {
Expand Down Expand Up @@ -203,7 +212,8 @@ const handleOpened = () => {
lastActive = activeElement;

nextTick(() => {
if (modalEl.value) (modalEl.value as HTMLDivElement).focus(); // wrapped in if so testing error isn't thrown
// wrapped in if so testing error isn't thrown
if (modalEl.value) (modalEl.value as HTMLDivElement).focus();
measureContent();
addHandlers();

Expand Down Expand Up @@ -253,6 +263,7 @@ const dialogAttrs = computed(() => ({
'aria-describedby': props.ariaDescribedby,
id: props.id,
}));

const verticalSpace = computed(() => {
// contentWrap vertical padding
const fullscreenSpace = Number(CdrSpaceTwoX);
Expand All @@ -263,9 +274,10 @@ const verticalSpace = computed(() => {
: windowedSpace + fullscreenSpace;
// fullscreen, here, would account for outerWrap padding, which is the same CdrSpaceTwoX
});
const scrollMaxHeight = computed(() => totalHeight.value
- headerHeight.value
- verticalSpace.value);

const scrollMaxHeight = computed(() => totalHeight.value
- headerHeight.value
- verticalSpace.value);

const scrollPadding = computed(() => {
const isScrolling = scrollHeight.value > offsetHeight.value;
Expand All @@ -278,6 +290,11 @@ const scrollPadding = computed(() => {
return 0;
});

const textContentStyle = computed(() => ({
maxHeight: `${scrollMaxHeight.value}px`,
paddingRight: `${scrollPadding.value}px`,
}));

daemoncron marked this conversation as resolved.
Show resolved Hide resolved
watch(() => props.opened, (newValue, oldValue) => {
if (!!newValue === !!oldValue) return;
// eslint-disable-next-line no-unused-expressions
Expand All @@ -294,18 +311,14 @@ onMounted(() => {
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
});


</script>

<template>
<div
:class="mapClasses(style, baseClass, !opened ? 'cdr-modal--closed' : '')"
ref="wrapperEl"
>
<div
:class="[style['cdr-modal__outerWrap'], wrapperClass]"
>
<div :class="[style['cdr-modal__outerWrap'], wrapperClass]">
<div
aria-hidden="true"
@click="onClick"
Expand All @@ -331,7 +344,7 @@ onUnmounted(() => {
<slot name="modal">
<div
:class="[style['cdr-modal__innerWrap'], contentClass]"
:style="modalClosed ? {display: 'none'} : undefined"
:style="modalClosed ? { display: 'none' } : undefined"
>
<section>
<div :class="style['cdr-modal__content']">
Expand Down Expand Up @@ -364,7 +377,7 @@ onUnmounted(() => {

<div
:class="style['cdr-modal__text-content']"
:style="{ maxHeight: `${scrollMaxHeight}px`, paddingRight: `${scrollPadding}px`}"
:style="textContentStyle"
role="document"
ref="contentEl"
tabindex="0"
Expand All @@ -380,7 +393,6 @@ onUnmounted(() => {
<div :tabIndex="opened ? '0' : undefined" />
</div>
</div>

</template>

<style lang="scss" module src="./styles/CdrModal.module.scss">
Expand Down
106 changes: 90 additions & 16 deletions src/components/modal/__tests__/CdrModal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { mount } from '../../../../test/vue-jest-style-workaround.js';
import CdrModal from '../CdrModal.vue';

describe('CdrModal.vue', () => {

describe('default open', ()=>{
let wrapper;
let elem;
Expand All @@ -13,7 +14,7 @@ describe('CdrModal.vue', () => {
wrapper = mount(CdrModal, {
propsData: {
opened: true,
label: "Label is the modal title"
label: 'Label is the modal title',
},
slots: {
default: 'Sticky content',
Expand All @@ -35,34 +36,107 @@ describe('CdrModal.vue', () => {
key: 'a'
});
await wrapper.vm.$nextTick();

wrapper.trigger('keydown', {
key: 'Esc',
});
await wrapper.vm.$nextTick();

wrapper.trigger('keydown', {
key: 'Escape',
});
await wrapper.vm.$nextTick();

expect(wrapper.emitted().closed.length).toBe(2);
});
daemoncron marked this conversation as resolved.
Show resolved Hide resolved
});

describe('prop handling', () => {
let wrapper;
let elem;
let dialogEl;
beforeEach(()=>{
elem = document.createElement('div')
if (document.body) {
document.body.appendChild(elem)
}
wrapper = mount(CdrModal, {
propsData: {
opened: true,
label: 'Label is the modal title',
ariaDescribedby: 'some-selector',
role: 'alertdialog',
id: 'some-id',
wrapperClass: "wrapper-class",
contentClass: "content-class",
},
attrs: {
'data-ui': 'my-modal',
},
slots: {
default: 'Sticky content',
},
attachTo: elem,
});
dialogEl = wrapper.find({ref: 'modalEl'})
});

// describe('after removeNoScroll has been called', ()=>{
// beforeEach(()=>{
// wrapper.vm.removeNoScroll();
// });
it('hides title', async () => {
expect(wrapper.text()).to.include('Label is the modal title',
'it should be there on mount');
await wrapper.setProps( { showTitle: false} );
expect(wrapper.text()).to.not.include('Label is the modal title',
'now it should be gone');
});

// it('renders correctly', () => {
// expect(wrapper.element).toMatchSnapshot();
// });
it('passes aria-describedby to the dialog element', () => {
expect(dialogEl.attributes('aria-describedby')).to.equal('some-selector');
});

// it('does NOT contain the "cdr-modal__noscroll" class', () => {
// expect(document.documentElement.classList.contains('cdr-modal__noscroll')).toBeFalsy();
// expect(document.body.classList.contains('cdr-modal__noscroll')).toBeFalsy();
// });
// });
it('passes id to the dialog element', () => {
expect(dialogEl.attributes('id')).to.equal('some-id');
});

it('sets the role of the dialog if alertdialog', () => {
expect(dialogEl.attributes('role')).to.equal('alertdialog');
});

it('sets the dialog class', () => {
console.log(dialogEl.classes());
const innerWrapEl = dialogEl.find('.cdr-modal__innerWrap');
expect(innerWrapEl.classes('content-class')).to.be.true;
});

it('sets the wrapper class', () => {
const outerwrap = wrapper.find('.cdr-modal__outerWrap');
expect(outerwrap.classes('wrapper-class')).to.be.true;
});
})

describe('other variations', () => {
let elem;
beforeEach(()=>{
elem = document.createElement('div')
if (document.body) {
document.body.appendChild(elem)
}
});

it('should pass non-prop attributes to the proper child', () => {
const wrapper = mount(CdrModal, {
propsData: {
opened: true,
label: 'Label is the modal title',
},
attrs: {
'data-ui': 'my-modal',
},
attachTo: elem,
});
const dialog = wrapper.find({ref: 'modalEl'});

expect(dialog.attributes('data-ui')).to.equal('my-modal')
});
});


Expand Down
6 changes: 4 additions & 2 deletions src/components/modal/examples/Modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@
</h2>

<cdr-modal
label="label text is title or aria"
:opened="opened"
@closed="closed"
wrapper-class="wrapper-test-class"
overlay-class="overlay-test-class"
data-backstop="modal"
role="dialog"
data-ui="hamburger-modal"
aria-labelledby="some-heading"
daemoncron marked this conversation as resolved.
Show resolved Hide resolved
>
<template #title>
<cdr-text
tag="h2"
class="cdr-text-dev--heading-serif-600 modal-title"
id="some-heading"
>
Terms & Conditions
</cdr-text>
Expand Down Expand Up @@ -92,7 +94,7 @@ export default {
},
data() {
return {
opened: this.$route.name === 'Modals',
opened: false,
daemoncron marked this conversation as resolved.
Show resolved Hide resolved
overflowContent: false,
override: false,
};
Expand Down
Loading
Loading