import { mount, shallowMount } from '@vue/test-utils';
import { hasHorizontalOverflow } from '~/lib/utils/dom_utils';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
const DUMMY_TEXT = 'lorem-ipsum-dolar-sit-amit-consectur-adipiscing-elit-sed-do';
const createChildElement = () => `${DUMMY_TEXT}`;
jest.mock('~/lib/utils/dom_utils', () => ({
hasHorizontalOverflow: jest.fn(() => {
throw new Error('this needs to be mocked');
}),
}));
describe('TooltipOnTruncate component', () => {
let wrapper;
let parent;
const createComponent = ({ propsData, ...options } = {}) => {
wrapper = shallowMount(TooltipOnTruncate, {
attachToDocument: true,
propsData: {
...propsData,
},
...options,
});
};
const createWrappedComponent = ({ propsData, ...options }) => {
// set a parent around the tested component
parent = mount(
{
props: {
title: { default: '' },
},
template: `
{{title}}
`,
components: {
TooltipOnTruncate,
},
},
{
propsData: { ...propsData },
attachToDocument: true,
...options,
},
);
wrapper = parent.find(TooltipOnTruncate);
};
const hasTooltip = () => wrapper.classes('js-show-tooltip');
afterEach(() => {
wrapper.destroy();
});
describe('with default target', () => {
it('renders tooltip if truncated', () => {
hasHorizontalOverflow.mockReturnValueOnce(true);
createComponent({
propsData: {
title: DUMMY_TEXT,
},
slots: {
default: [DUMMY_TEXT],
},
});
return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element);
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(DUMMY_TEXT);
expect(wrapper.attributes('data-placement')).toEqual('top');
});
});
it('does not render tooltip if normal', () => {
hasHorizontalOverflow.mockReturnValueOnce(false);
createComponent({
propsData: {
title: DUMMY_TEXT,
},
slots: {
default: [DUMMY_TEXT],
},
});
return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element);
expect(hasTooltip()).toBe(false);
});
});
});
describe('with child target', () => {
it('renders tooltip if truncated', () => {
hasHorizontalOverflow.mockReturnValueOnce(true);
createComponent({
propsData: {
title: DUMMY_TEXT,
truncateTarget: 'child',
},
slots: {
default: createChildElement(),
},
});
return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element.childNodes[0]);
expect(hasTooltip()).toBe(true);
});
});
it('does not render tooltip if normal', () => {
hasHorizontalOverflow.mockReturnValueOnce(false);
createComponent({
propsData: {
truncateTarget: 'child',
},
slots: {
default: createChildElement(),
},
});
return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element.childNodes[0]);
expect(hasTooltip()).toBe(false);
});
});
});
describe('with fn target', () => {
it('renders tooltip if truncated', () => {
hasHorizontalOverflow.mockReturnValueOnce(true);
createComponent({
propsData: {
title: DUMMY_TEXT,
truncateTarget: el => el.childNodes[1],
},
slots: {
default: [createChildElement(), createChildElement()],
},
});
return wrapper.vm.$nextTick().then(() => {
expect(hasHorizontalOverflow).toHaveBeenCalledWith(wrapper.element.childNodes[1]);
expect(hasTooltip()).toBe(true);
});
});
});
describe('placement', () => {
it('sets data-placement when tooltip is rendered', () => {
const placement = 'bottom';
hasHorizontalOverflow.mockReturnValueOnce(true);
createComponent({
propsData: {
placement,
},
slots: {
default: DUMMY_TEXT,
},
});
return wrapper.vm.$nextTick().then(() => {
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-placement')).toEqual(placement);
});
});
});
describe('updates when title and slot content changes', () => {
describe('is initialized with a long text', () => {
beforeEach(() => {
hasHorizontalOverflow.mockReturnValueOnce(true);
createWrappedComponent({
propsData: { title: DUMMY_TEXT },
});
return parent.vm.$nextTick();
});
it('renders tooltip', () => {
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(DUMMY_TEXT);
expect(wrapper.attributes('data-placement')).toEqual('top');
});
it('does not render tooltip after updated to a short text', () => {
hasHorizontalOverflow.mockReturnValueOnce(false);
parent.setProps({
title: 'new-text',
});
return wrapper.vm
.$nextTick()
.then(() => wrapper.vm.$nextTick()) // wait 2 times to get an updated slot
.then(() => {
expect(hasTooltip()).toBe(false);
});
});
});
describe('is initialized with a short text', () => {
beforeEach(() => {
hasHorizontalOverflow.mockReturnValueOnce(false);
createWrappedComponent({
propsData: { title: DUMMY_TEXT },
});
return wrapper.vm.$nextTick();
});
it('does not render tooltip', () => {
expect(hasTooltip()).toBe(false);
});
it('renders tooltip after text is updated', () => {
hasHorizontalOverflow.mockReturnValueOnce(true);
const newText = 'new-text';
parent.setProps({
title: newText,
});
return wrapper.vm
.$nextTick()
.then(() => wrapper.vm.$nextTick()) // wait 2 times to get an updated slot
.then(() => {
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(newText);
expect(wrapper.attributes('data-placement')).toEqual('top');
});
});
});
});
});