summaryrefslogtreecommitdiff
path: root/spec/frontend/popovers
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-10-27 15:08:39 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-10-27 15:08:39 +0000
commit2b1e7f7dac0fa5d7bb3bdf415cec1b3c67ed77b0 (patch)
tree725ae8200573957bff6fa03aee237f738dadf1d7 /spec/frontend/popovers
parenteb004dc626d3a1c9497e8b9dc0f3f578afd05fd9 (diff)
downloadgitlab-ce-2b1e7f7dac0fa5d7bb3bdf415cec1b3c67ed77b0.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/popovers')
-rw-r--r--spec/frontend/popovers/components/popovers_spec.js129
-rw-r--r--spec/frontend/popovers/index_spec.js104
2 files changed, 233 insertions, 0 deletions
diff --git a/spec/frontend/popovers/components/popovers_spec.js b/spec/frontend/popovers/components/popovers_spec.js
new file mode 100644
index 00000000000..63e0b3d9c49
--- /dev/null
+++ b/spec/frontend/popovers/components/popovers_spec.js
@@ -0,0 +1,129 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlPopover } from '@gitlab/ui';
+import { useMockMutationObserver } from 'helpers/mock_dom_observer';
+import Popovers from '~/popovers/components/popovers.vue';
+
+describe('popovers/components/popovers.vue', () => {
+ const { trigger: triggerMutate, observersCount } = useMockMutationObserver();
+ let wrapper;
+
+ const buildWrapper = (...targets) => {
+ wrapper = shallowMount(Popovers);
+ wrapper.vm.addPopovers(targets);
+ return wrapper.vm.$nextTick();
+ };
+
+ const createPopoverTarget = (options = {}) => {
+ const target = document.createElement('button');
+ const dataset = {
+ title: 'default title',
+ content: 'some content',
+ ...options,
+ };
+
+ Object.entries(dataset).forEach(([key, value]) => {
+ target.dataset[key] = value;
+ });
+
+ document.body.appendChild(target);
+
+ return target;
+ };
+
+ const allPopovers = () => wrapper.findAll(GlPopover);
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('addPopovers', () => {
+ it('attaches popovers to the targets specified', async () => {
+ const target = createPopoverTarget();
+ await buildWrapper(target);
+ expect(wrapper.find(GlPopover).props('target')).toBe(target);
+ });
+
+ it('does not attach a popover twice to the same element', async () => {
+ const target = createPopoverTarget();
+ buildWrapper(target);
+ wrapper.vm.addPopovers([target]);
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.findAll(GlPopover)).toHaveLength(1);
+ });
+
+ it('supports HTML content', async () => {
+ const content = 'content with <b>HTML</b>';
+ await buildWrapper(
+ createPopoverTarget({
+ content,
+ html: true,
+ }),
+ );
+ const html = wrapper.find(GlPopover).html();
+
+ expect(html).toContain(content);
+ });
+
+ it.each`
+ option | value
+ ${'placement'} | ${'bottom'}
+ ${'triggers'} | ${'manual'}
+ `('sets $option to $value when data-$option is set in target', async ({ option, value }) => {
+ await buildWrapper(createPopoverTarget({ [option]: value }));
+
+ expect(wrapper.find(GlPopover).props(option)).toBe(value);
+ });
+ });
+
+ describe('dispose', () => {
+ it('removes all popovers when elements is nil', async () => {
+ await buildWrapper(createPopoverTarget(), createPopoverTarget());
+
+ wrapper.vm.dispose();
+ await wrapper.vm.$nextTick();
+
+ expect(allPopovers()).toHaveLength(0);
+ });
+
+ it('removes the popovers that target the elements specified', async () => {
+ const target = createPopoverTarget();
+
+ await buildWrapper(target, createPopoverTarget());
+
+ wrapper.vm.dispose(target);
+ await wrapper.vm.$nextTick();
+
+ expect(allPopovers()).toHaveLength(1);
+ });
+ });
+
+ describe('observe', () => {
+ it('removes popover when target is removed from the document', async () => {
+ const target = createPopoverTarget();
+ await buildWrapper(target);
+
+ wrapper.vm.addPopovers([target, createPopoverTarget()]);
+ await wrapper.vm.$nextTick();
+
+ triggerMutate(document.body, {
+ entry: { removedNodes: [target] },
+ options: { childList: true },
+ });
+ await wrapper.vm.$nextTick();
+
+ expect(allPopovers()).toHaveLength(1);
+ });
+ });
+
+ it('disconnects mutation observer on beforeDestroy', async () => {
+ await buildWrapper(createPopoverTarget());
+
+ expect(observersCount()).toBe(1);
+
+ wrapper.destroy();
+ expect(observersCount()).toBe(0);
+ });
+});
diff --git a/spec/frontend/popovers/index_spec.js b/spec/frontend/popovers/index_spec.js
new file mode 100644
index 00000000000..ea3b78332d7
--- /dev/null
+++ b/spec/frontend/popovers/index_spec.js
@@ -0,0 +1,104 @@
+import { initPopovers, dispose, destroy } from '~/popovers';
+
+describe('popovers/index.js', () => {
+ let popoversApp;
+
+ const createPopoverTarget = (trigger = 'hover') => {
+ const target = document.createElement('button');
+ const dataset = {
+ title: 'default title',
+ content: 'some content',
+ toggle: 'popover',
+ trigger,
+ };
+
+ Object.entries(dataset).forEach(([key, value]) => {
+ target.dataset[key] = value;
+ });
+
+ document.body.appendChild(target);
+
+ return target;
+ };
+
+ const buildPopoversApp = () => {
+ popoversApp = initPopovers('[data-toggle="popover"]');
+ };
+
+ const triggerEvent = (target, eventName = 'mouseenter') => {
+ const event = new Event(eventName);
+
+ target.dispatchEvent(event);
+ };
+
+ afterEach(() => {
+ document.body.innerHTML = '';
+ destroy();
+ });
+
+ describe('initPopover', () => {
+ it('attaches a GlPopover for the elements specified in the selector', async () => {
+ const target = createPopoverTarget();
+
+ buildPopoversApp();
+
+ triggerEvent(target);
+
+ await popoversApp.$nextTick();
+ const html = document.querySelector('.gl-popover').innerHTML;
+
+ expect(document.querySelector('.gl-popover')).not.toBe(null);
+ expect(html).toContain('default title');
+ expect(html).toContain('some content');
+ });
+
+ it('supports triggering a popover via custom events', async () => {
+ const trigger = 'click';
+ const target = createPopoverTarget(trigger);
+
+ buildPopoversApp();
+ triggerEvent(target, trigger);
+
+ await popoversApp.$nextTick();
+
+ expect(document.querySelector('.gl-popover')).not.toBe(null);
+ expect(document.querySelector('.gl-popover').innerHTML).toContain('default title');
+ });
+
+ it('inits popovers on targets added after content load', async () => {
+ buildPopoversApp();
+
+ expect(document.querySelector('.gl-popover')).toBe(null);
+
+ const trigger = 'click';
+ const target = createPopoverTarget(trigger);
+ triggerEvent(target, trigger);
+ await popoversApp.$nextTick();
+
+ expect(document.querySelector('.gl-popover')).not.toBe(null);
+ });
+ });
+
+ describe('dispose', () => {
+ it('removes popovers that target the elements specified', async () => {
+ const fakeTarget = createPopoverTarget();
+ const target = createPopoverTarget();
+ buildPopoversApp();
+ triggerEvent(target);
+ triggerEvent(createPopoverTarget());
+ await popoversApp.$nextTick();
+
+ expect(document.querySelectorAll('.gl-popover')).toHaveLength(2);
+
+ dispose([fakeTarget]);
+ await popoversApp.$nextTick();
+
+ expect(document.querySelectorAll('.gl-popover')).toHaveLength(2);
+
+ dispose([target]);
+ await popoversApp.$nextTick();
+
+ expect(document.querySelectorAll('.gl-popover')).toHaveLength(1);
+ });
+ });
+});