Commit 7178e65a authored by Paul Slaughter's avatar Paul Slaughter

Merge branch 'winniehell-jestify-tooltip_on_truncate_browser_spec.js' into 'master'

Migrate tooltip_on_truncate_spec.js to Jest

See merge request gitlab-org/gitlab!47582
parents d26d90bd e6fca870
import { has } from 'lodash'; import { has } from 'lodash';
import { isInIssuePage, isInMRPage, isInEpicPage } from './common_utils'; import { isInIssuePage, isInMRPage, isInEpicPage } from './common_utils';
/**
* Checks whether an element's content exceeds the element's width.
*
* @param element DOM element to check
*/
export const hasHorizontalOverflow = element =>
Boolean(element && element.scrollWidth > element.offsetWidth);
export const addClassIfElementExists = (element, className) => { export const addClassIfElementExists = (element, className) => {
if (element) { if (element) {
element.classList.add(className); element.classList.add(className);
......
...@@ -49,5 +49,3 @@ export const toggleDisableButton = ($button, disable) => { ...@@ -49,5 +49,3 @@ export const toggleDisableButton = ($button, disable) => {
if (disable && $button.prop('disabled')) return; if (disable && $button.prop('disabled')) return;
$button.prop('disabled', disable); $button.prop('disabled', disable);
}; };
export default {};
<script> <script>
import { isFunction } from 'lodash'; import { isFunction } from 'lodash';
import tooltip from '../directives/tooltip'; import tooltip from '../directives/tooltip';
import { hasHorizontalOverflow } from '~/lib/utils/dom_utils';
export default { export default {
directives: { directives: {
...@@ -49,7 +50,7 @@ export default { ...@@ -49,7 +50,7 @@ export default {
}, },
updateTooltip() { updateTooltip() {
const target = this.selectTarget(); const target = this.selectTarget();
this.showTooltip = Boolean(target && target.scrollWidth > target.offsetWidth); this.showTooltip = hasHorizontalOverflow(target);
}, },
}, },
}; };
......
// this file can't be migrated to jest because it relies on the browser to perform integration tests:
// (specifically testing around css properties `overflow` and `white-space`)
// see: https://gitlab.com/groups/gitlab-org/-/epics/895#what-if-theres-a-karma-spec-which-is-simply-unmovable-to-jest-ie-it-is-dependent-on-a-running-browser-environment
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from '@vue/test-utils';
import { hasHorizontalOverflow } from '~/lib/utils/dom_utils';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
const TEXT_SHORT = 'lorem'; const DUMMY_TEXT = 'lorem-ipsum-dolar-sit-amit-consectur-adipiscing-elit-sed-do';
const TEXT_LONG = 'lorem-ipsum-dolar-sit-amit-consectur-adipiscing-elit-sed-do';
const TEXT_TRUNCATE = 'white-space: nowrap; overflow:hidden;'; const createChildElement = () => `<a href="#">${DUMMY_TEXT}</a>`;
const STYLE_NORMAL = `${TEXT_TRUNCATE} display: inline-block; max-width: 1000px;`; // does not overflows
const STYLE_OVERFLOWED = `${TEXT_TRUNCATE} display: inline-block; max-width: 50px;`; // overflowed when text is long
const createElementWithStyle = (style, content) => `<a href="#" style="${style}">${content}</a>`; jest.mock('~/lib/utils/dom_utils', () => ({
hasHorizontalOverflow: jest.fn(() => {
throw new Error('this needs to be mocked');
}),
}));
describe('TooltipOnTruncate component', () => { describe('TooltipOnTruncate component', () => {
let wrapper; let wrapper;
...@@ -24,9 +22,6 @@ describe('TooltipOnTruncate component', () => { ...@@ -24,9 +22,6 @@ describe('TooltipOnTruncate component', () => {
propsData: { propsData: {
...propsData, ...propsData,
}, },
attrs: {
style: STYLE_OVERFLOWED,
},
...options, ...options,
}); });
}; };
...@@ -39,7 +34,7 @@ describe('TooltipOnTruncate component', () => { ...@@ -39,7 +34,7 @@ describe('TooltipOnTruncate component', () => {
title: { default: '' }, title: { default: '' },
}, },
template: ` template: `
<TooltipOnTruncate :title="title" truncate-target="child" style="${STYLE_OVERFLOWED}"> <TooltipOnTruncate :title="title" truncate-target="child">
<div>{{title}}</div> <div>{{title}}</div>
</TooltipOnTruncate> </TooltipOnTruncate>
`, `,
...@@ -65,33 +60,37 @@ describe('TooltipOnTruncate component', () => { ...@@ -65,33 +60,37 @@ describe('TooltipOnTruncate component', () => {
describe('with default target', () => { describe('with default target', () => {
it('renders tooltip if truncated', () => { it('renders tooltip if truncated', () => {
hasHorizontalOverflow.mockReturnValueOnce(true);
createComponent({ createComponent({
propsData: { propsData: {
title: TEXT_LONG, title: DUMMY_TEXT,
}, },
slots: { slots: {
default: [TEXT_LONG], default: [DUMMY_TEXT],
}, },
}); });
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element);
expect(hasTooltip()).toBe(true); expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(TEXT_LONG); expect(wrapper.attributes('data-original-title')).toEqual(DUMMY_TEXT);
expect(wrapper.attributes('data-placement')).toEqual('top'); expect(wrapper.attributes('data-placement')).toEqual('top');
}); });
}); });
it('does not render tooltip if normal', () => { it('does not render tooltip if normal', () => {
hasHorizontalOverflow.mockReturnValueOnce(false);
createComponent({ createComponent({
propsData: { propsData: {
title: TEXT_SHORT, title: DUMMY_TEXT,
}, },
slots: { slots: {
default: [TEXT_SHORT], default: [DUMMY_TEXT],
}, },
}); });
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element);
expect(hasTooltip()).toBe(false); expect(hasTooltip()).toBe(false);
}); });
}); });
...@@ -99,35 +98,36 @@ describe('TooltipOnTruncate component', () => { ...@@ -99,35 +98,36 @@ describe('TooltipOnTruncate component', () => {
describe('with child target', () => { describe('with child target', () => {
it('renders tooltip if truncated', () => { it('renders tooltip if truncated', () => {
hasHorizontalOverflow.mockReturnValueOnce(true);
createComponent({ createComponent({
attrs: {
style: STYLE_NORMAL,
},
propsData: { propsData: {
title: TEXT_LONG, title: DUMMY_TEXT,
truncateTarget: 'child', truncateTarget: 'child',
}, },
slots: { slots: {
default: createElementWithStyle(STYLE_OVERFLOWED, TEXT_LONG), default: createChildElement(),
}, },
}); });
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element.childNodes[0]);
expect(hasTooltip()).toBe(true); expect(hasTooltip()).toBe(true);
}); });
}); });
it('does not render tooltip if normal', () => { it('does not render tooltip if normal', () => {
hasHorizontalOverflow.mockReturnValueOnce(false);
createComponent({ createComponent({
propsData: { propsData: {
truncateTarget: 'child', truncateTarget: 'child',
}, },
slots: { slots: {
default: createElementWithStyle(STYLE_NORMAL, TEXT_LONG), default: createChildElement(),
}, },
}); });
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element.childNodes[0]);
expect(hasTooltip()).toBe(false); expect(hasTooltip()).toBe(false);
}); });
}); });
...@@ -135,23 +135,19 @@ describe('TooltipOnTruncate component', () => { ...@@ -135,23 +135,19 @@ describe('TooltipOnTruncate component', () => {
describe('with fn target', () => { describe('with fn target', () => {
it('renders tooltip if truncated', () => { it('renders tooltip if truncated', () => {
hasHorizontalOverflow.mockReturnValueOnce(true);
createComponent({ createComponent({
attrs: {
style: STYLE_NORMAL,
},
propsData: { propsData: {
title: TEXT_LONG, title: DUMMY_TEXT,
truncateTarget: el => el.childNodes[1], truncateTarget: el => el.childNodes[1],
}, },
slots: { slots: {
default: [ default: [createChildElement(), createChildElement()],
createElementWithStyle('', TEXT_LONG),
createElementWithStyle(STYLE_OVERFLOWED, TEXT_LONG),
],
}, },
}); });
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element.childNodes[1]);
expect(hasTooltip()).toBe(true); expect(hasTooltip()).toBe(true);
}); });
}); });
...@@ -161,15 +157,13 @@ describe('TooltipOnTruncate component', () => { ...@@ -161,15 +157,13 @@ describe('TooltipOnTruncate component', () => {
it('sets data-placement when tooltip is rendered', () => { it('sets data-placement when tooltip is rendered', () => {
const placement = 'bottom'; const placement = 'bottom';
hasHorizontalOverflow.mockReturnValueOnce(true);
createComponent({ createComponent({
propsData: { propsData: {
placement, placement,
}, },
attrs: {
style: STYLE_OVERFLOWED,
},
slots: { slots: {
default: TEXT_LONG, default: DUMMY_TEXT,
}, },
}); });
...@@ -183,21 +177,23 @@ describe('TooltipOnTruncate component', () => { ...@@ -183,21 +177,23 @@ describe('TooltipOnTruncate component', () => {
describe('updates when title and slot content changes', () => { describe('updates when title and slot content changes', () => {
describe('is initialized with a long text', () => { describe('is initialized with a long text', () => {
beforeEach(() => { beforeEach(() => {
hasHorizontalOverflow.mockReturnValueOnce(true);
createWrappedComponent({ createWrappedComponent({
propsData: { title: TEXT_LONG }, propsData: { title: DUMMY_TEXT },
}); });
return parent.vm.$nextTick(); return parent.vm.$nextTick();
}); });
it('renders tooltip', () => { it('renders tooltip', () => {
expect(hasTooltip()).toBe(true); expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(TEXT_LONG); expect(wrapper.attributes('data-original-title')).toEqual(DUMMY_TEXT);
expect(wrapper.attributes('data-placement')).toEqual('top'); expect(wrapper.attributes('data-placement')).toEqual('top');
}); });
it('does not render tooltip after updated to a short text', () => { it('does not render tooltip after updated to a short text', () => {
hasHorizontalOverflow.mockReturnValueOnce(false);
parent.setProps({ parent.setProps({
title: TEXT_SHORT, title: 'new-text',
}); });
return wrapper.vm return wrapper.vm
...@@ -211,8 +207,9 @@ describe('TooltipOnTruncate component', () => { ...@@ -211,8 +207,9 @@ describe('TooltipOnTruncate component', () => {
describe('is initialized with a short text', () => { describe('is initialized with a short text', () => {
beforeEach(() => { beforeEach(() => {
hasHorizontalOverflow.mockReturnValueOnce(false);
createWrappedComponent({ createWrappedComponent({
propsData: { title: TEXT_SHORT }, propsData: { title: DUMMY_TEXT },
}); });
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
}); });
...@@ -221,9 +218,11 @@ describe('TooltipOnTruncate component', () => { ...@@ -221,9 +218,11 @@ describe('TooltipOnTruncate component', () => {
expect(hasTooltip()).toBe(false); expect(hasTooltip()).toBe(false);
}); });
it('renders tooltip after updated to a long text', () => { it('renders tooltip after text is updated', () => {
hasHorizontalOverflow.mockReturnValueOnce(true);
const newText = 'new-text';
parent.setProps({ parent.setProps({
title: TEXT_LONG, title: newText,
}); });
return wrapper.vm return wrapper.vm
...@@ -231,7 +230,7 @@ describe('TooltipOnTruncate component', () => { ...@@ -231,7 +230,7 @@ describe('TooltipOnTruncate component', () => {
.then(() => wrapper.vm.$nextTick()) // wait 2 times to get an updated slot .then(() => wrapper.vm.$nextTick()) // wait 2 times to get an updated slot
.then(() => { .then(() => {
expect(hasTooltip()).toBe(true); expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(TEXT_LONG); expect(wrapper.attributes('data-original-title')).toEqual(newText);
expect(wrapper.attributes('data-placement')).toEqual('top'); expect(wrapper.attributes('data-placement')).toEqual('top');
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment