diff options
Diffstat (limited to 'spec/frontend/helpers')
-rw-r--r-- | spec/frontend/helpers/class_spec_helper.js | 1 | ||||
-rw-r--r-- | spec/frontend/helpers/event_hub_factory_spec.js | 94 | ||||
-rw-r--r-- | spec/frontend/helpers/filtered_search_spec_helper.js | 69 | ||||
-rw-r--r-- | spec/frontend/helpers/fixtures.js | 5 | ||||
-rw-r--r-- | spec/frontend/helpers/set_window_location_helper.js | 40 | ||||
-rw-r--r-- | spec/frontend/helpers/set_window_location_helper_spec.js | 40 | ||||
-rw-r--r-- | spec/frontend/helpers/vue_mount_component_helper.js | 25 | ||||
-rw-r--r-- | spec/frontend/helpers/web_worker_mock.js | 10 |
8 files changed, 282 insertions, 2 deletions
diff --git a/spec/frontend/helpers/class_spec_helper.js b/spec/frontend/helpers/class_spec_helper.js index 7a60d33b471..b26f087f0c5 100644 --- a/spec/frontend/helpers/class_spec_helper.js +++ b/spec/frontend/helpers/class_spec_helper.js @@ -1,3 +1,4 @@ +// eslint-disable-next-line jest/no-export export default class ClassSpecHelper { static itShouldBeAStaticMethod(base, method) { return it('should be a static method', () => { diff --git a/spec/frontend/helpers/event_hub_factory_spec.js b/spec/frontend/helpers/event_hub_factory_spec.js new file mode 100644 index 00000000000..dcfec6b836a --- /dev/null +++ b/spec/frontend/helpers/event_hub_factory_spec.js @@ -0,0 +1,94 @@ +import createEventHub from '~/helpers/event_hub_factory'; + +describe('event bus factory', () => { + let eventBus; + + beforeEach(() => { + eventBus = createEventHub(); + }); + + afterEach(() => { + eventBus = null; + }); + + describe('underlying module', () => { + let mitt; + + beforeEach(() => { + jest.resetModules(); + jest.mock('mitt'); + + // eslint-disable-next-line global-require + mitt = require('mitt'); + mitt.mockReturnValue(() => ({})); + + const createEventHubActual = jest.requireActual('~/helpers/event_hub_factory').default; + eventBus = createEventHubActual(); + }); + + it('creates an emitter', () => { + expect(mitt).toHaveBeenCalled(); + }); + }); + + describe('instance', () => { + it.each` + method + ${'on'} + ${'once'} + ${'off'} + ${'emit'} + `('binds $$method to $method ', ({ method }) => { + expect(typeof eventBus[method]).toBe('function'); + expect(eventBus[method]).toBe(eventBus[`$${method}`]); + }); + }); + + describe('once', () => { + const event = 'foobar'; + let handler; + + beforeEach(() => { + jest.spyOn(eventBus, 'on'); + jest.spyOn(eventBus, 'off'); + handler = jest.fn(); + eventBus.once(event, handler); + }); + + it('calls on internally', () => { + expect(eventBus.on).toHaveBeenCalled(); + }); + + it('calls handler when event is emitted', () => { + eventBus.emit(event); + expect(handler).toHaveBeenCalled(); + }); + + it('calls off when event is emitted', () => { + eventBus.emit(event); + expect(eventBus.off).toHaveBeenCalled(); + }); + + it('calls the handler only once when event is emitted multiple times', () => { + eventBus.emit(event); + eventBus.emit(event); + expect(handler).toHaveBeenCalledTimes(1); + }); + + describe('when the handler thows an error', () => { + beforeEach(() => { + handler = jest.fn().mockImplementation(() => { + throw new Error(); + }); + eventBus.once(event, handler); + }); + + it('calls off when event is emitted', () => { + expect(() => { + eventBus.emit(event); + }).toThrow(); + expect(eventBus.off).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/spec/frontend/helpers/filtered_search_spec_helper.js b/spec/frontend/helpers/filtered_search_spec_helper.js new file mode 100644 index 00000000000..ceb7982bbc3 --- /dev/null +++ b/spec/frontend/helpers/filtered_search_spec_helper.js @@ -0,0 +1,69 @@ +export default class FilteredSearchSpecHelper { + static createFilterVisualTokenHTML(name, operator, value, isSelected) { + return FilteredSearchSpecHelper.createFilterVisualToken(name, operator, value, isSelected) + .outerHTML; + } + + static createFilterVisualToken(name, operator, value, isSelected = false) { + const li = document.createElement('li'); + li.classList.add('js-visual-token', 'filtered-search-token', `search-token-${name}`); + + li.innerHTML = ` + <div class="selectable ${isSelected ? 'selected' : ''}" role="button"> + <div class="name">${name}</div> + <div class="operator">${operator}</div> + <div class="value-container"> + <div class="value">${value}</div> + <div class="remove-token" role="button"> + <i class="fa fa-close"></i> + </div> + </div> + </div> + `; + + return li; + } + + static createNameFilterVisualTokenHTML(name) { + return ` + <li class="js-visual-token filtered-search-token"> + <div class="name">${name}</div> + </li> + `; + } + + static createNameOperatorFilterVisualTokenHTML(name, operator) { + return ` + <li class="js-visual-token filtered-search-token"> + <div class="name">${name}</div> + <div class="operator">${operator}</div> + </li> + `; + } + + static createSearchVisualToken(name) { + const li = document.createElement('li'); + li.classList.add('js-visual-token', 'filtered-search-term'); + li.innerHTML = `<div class="name">${name}</div>`; + return li; + } + + static createSearchVisualTokenHTML(name) { + return FilteredSearchSpecHelper.createSearchVisualToken(name).outerHTML; + } + + static createInputHTML(placeholder = '', value = '') { + return ` + <li class="input-token"> + <input type='text' class='filtered-search' placeholder='${placeholder}' value='${value}'/> + </li> + `; + } + + static createTokensContainerHTML(html, inputPlaceholder) { + return ` + ${html} + ${FilteredSearchSpecHelper.createInputHTML(inputPlaceholder)} + `; + } +} diff --git a/spec/frontend/helpers/fixtures.js b/spec/frontend/helpers/fixtures.js index 778196843db..a89ceab3f8e 100644 --- a/spec/frontend/helpers/fixtures.js +++ b/spec/frontend/helpers/fixtures.js @@ -23,11 +23,12 @@ Did you run bin/rake frontend:fixtures?`, export const getJSONFixture = relativePath => JSON.parse(getFixture(relativePath)); export const resetHTMLFixture = () => { - document.body.textContent = ''; + document.head.innerHTML = ''; + document.body.innerHTML = ''; }; export const setHTMLFixture = (htmlContent, resetHook = afterEach) => { - document.body.outerHTML = htmlContent; + document.body.innerHTML = htmlContent; resetHook(resetHTMLFixture); }; diff --git a/spec/frontend/helpers/set_window_location_helper.js b/spec/frontend/helpers/set_window_location_helper.js new file mode 100644 index 00000000000..a94e73762c9 --- /dev/null +++ b/spec/frontend/helpers/set_window_location_helper.js @@ -0,0 +1,40 @@ +/** + * setWindowLocation allows for setting `window.location` + * (doing so directly is causing an error in jsdom) + * + * Example usage: + * assert(window.location.hash === undefined); + * setWindowLocation('http://example.com#foo') + * assert(window.location.hash === '#foo'); + * + * More information: + * https://github.com/facebook/jest/issues/890 + * + * @param url + */ +export default function setWindowLocation(url) { + const parsedUrl = new URL(url); + + const newLocationValue = [ + 'hash', + 'host', + 'hostname', + 'href', + 'origin', + 'pathname', + 'port', + 'protocol', + 'search', + ].reduce( + (location, prop) => ({ + ...location, + [prop]: parsedUrl[prop], + }), + {}, + ); + + Object.defineProperty(window, 'location', { + value: newLocationValue, + writable: true, + }); +} diff --git a/spec/frontend/helpers/set_window_location_helper_spec.js b/spec/frontend/helpers/set_window_location_helper_spec.js new file mode 100644 index 00000000000..2a2c024c824 --- /dev/null +++ b/spec/frontend/helpers/set_window_location_helper_spec.js @@ -0,0 +1,40 @@ +import setWindowLocation from './set_window_location_helper'; + +describe('setWindowLocation', () => { + const originalLocation = window.location; + + afterEach(() => { + window.location = originalLocation; + }); + + it.each` + url | property | value + ${'https://gitlab.com#foo'} | ${'hash'} | ${'#foo'} + ${'http://gitlab.com'} | ${'host'} | ${'gitlab.com'} + ${'http://gitlab.org'} | ${'hostname'} | ${'gitlab.org'} + ${'http://gitlab.org/foo#bar'} | ${'href'} | ${'http://gitlab.org/foo#bar'} + ${'http://gitlab.com'} | ${'origin'} | ${'http://gitlab.com'} + ${'http://gitlab.com/foo/bar/baz'} | ${'pathname'} | ${'/foo/bar/baz'} + ${'https://gitlab.com'} | ${'protocol'} | ${'https:'} + ${'http://gitlab.com#foo'} | ${'protocol'} | ${'http:'} + ${'http://gitlab.com:8080'} | ${'port'} | ${'8080'} + ${'http://gitlab.com?foo=bar&bar=foo'} | ${'search'} | ${'?foo=bar&bar=foo'} + `( + 'sets "window.location.$property" to be "$value" when called with: "$url"', + ({ url, property, value }) => { + expect(window.location).toBe(originalLocation); + + setWindowLocation(url); + + expect(window.location[property]).toBe(value); + }, + ); + + it.each([null, 1, undefined, false, '', 'gitlab.com'])( + 'throws an error when called with an invalid url: "%s"', + invalidUrl => { + expect(() => setWindowLocation(invalidUrl)).toThrow(new TypeError('Invalid URL')); + expect(window.location).toBe(originalLocation); + }, + ); +}); diff --git a/spec/frontend/helpers/vue_mount_component_helper.js b/spec/frontend/helpers/vue_mount_component_helper.js index 6848c95d95d..615ff69a01c 100644 --- a/spec/frontend/helpers/vue_mount_component_helper.js +++ b/spec/frontend/helpers/vue_mount_component_helper.js @@ -1,22 +1,38 @@ import Vue from 'vue'; +/** + * Deprecated. Please do not use. + * Please see https://gitlab.com/groups/gitlab-org/-/epics/2445 + */ const mountComponent = (Component, props = {}, el = null) => new Component({ propsData: props, }).$mount(el); +/** + * Deprecated. Please do not use. + * Please see https://gitlab.com/groups/gitlab-org/-/epics/2445 + */ export const createComponentWithStore = (Component, store, propsData = {}) => new Component({ store, propsData, }); +/** + * Deprecated. Please do not use. + * Please see https://gitlab.com/groups/gitlab-org/-/epics/2445 + */ export const mountComponentWithStore = (Component, { el, props, store }) => new Component({ store, propsData: props || {}, }).$mount(el); +/** + * Deprecated. Please do not use. + * Please see https://gitlab.com/groups/gitlab-org/-/epics/2445 + */ export const mountComponentWithSlots = (Component, { props, slots }) => { const component = new Component({ propsData: props || {}, @@ -30,9 +46,18 @@ export const mountComponentWithSlots = (Component, { props, slots }) => { /** * Mount a component with the given render method. * + * ----------------------------- + * Deprecated. Please do not use. + * Please see https://gitlab.com/groups/gitlab-org/-/epics/2445 + * ----------------------------- + * * This helps with inserting slots that need to be compiled. */ export const mountComponentWithRender = (render, el = null) => mountComponent(Vue.extend({ render }), {}, el); +/** + * Deprecated. Please do not use. + * Please see https://gitlab.com/groups/gitlab-org/-/epics/2445 + */ export default mountComponent; diff --git a/spec/frontend/helpers/web_worker_mock.js b/spec/frontend/helpers/web_worker_mock.js new file mode 100644 index 00000000000..2b4a391e1d2 --- /dev/null +++ b/spec/frontend/helpers/web_worker_mock.js @@ -0,0 +1,10 @@ +/* eslint-disable class-methods-use-this */ +export default class WebWorkerMock { + addEventListener() {} + + removeEventListener() {} + + terminate() {} + + postMessage() {} +} |