diff options
Diffstat (limited to 'spec/frontend/helpers')
62 files changed, 43 insertions, 1836 deletions
diff --git a/spec/frontend/helpers/README.md b/spec/frontend/helpers/README.md new file mode 100644 index 00000000000..22f9ea3442d --- /dev/null +++ b/spec/frontend/helpers/README.md @@ -0,0 +1,3 @@ +This folder should only contain specs for '~/helpers' application code. + +If you want to create a helper to be used in tests, please place it under [__helpers__](../__helpers__). diff --git a/spec/frontend/helpers/backoff_helper.js b/spec/frontend/helpers/backoff_helper.js deleted file mode 100644 index e5c0308d3fb..00000000000 --- a/spec/frontend/helpers/backoff_helper.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * A mock version of a commonUtils `backOff` to test multiple - * retries. - * - * Usage: - * - * ``` - * import * as commonUtils from '~/lib/utils/common_utils'; - * import { backoffMockImplementation } from '../../helpers/backoff_helper'; - * - * beforeEach(() => { - * // ... - * jest.spyOn(commonUtils, 'backOff').mockImplementation(backoffMockImplementation); - * }); - * ``` - * - * @param {Function} callback - */ -export const backoffMockImplementation = callback => { - const q = new Promise((resolve, reject) => { - const stop = arg => (arg instanceof Error ? reject(arg) : resolve(arg)); - const next = () => callback(next, stop); - // Define a timeout based on a mock timer - setTimeout(() => { - callback(next, stop); - }); - }); - // Run all resolved promises in chain - jest.runOnlyPendingTimers(); - return q; -}; - -export default { backoffMockImplementation }; diff --git a/spec/frontend/helpers/class_spec_helper.js b/spec/frontend/helpers/class_spec_helper.js deleted file mode 100644 index b26f087f0c5..00000000000 --- a/spec/frontend/helpers/class_spec_helper.js +++ /dev/null @@ -1,10 +0,0 @@ -// eslint-disable-next-line jest/no-export -export default class ClassSpecHelper { - static itShouldBeAStaticMethod(base, method) { - return it('should be a static method', () => { - expect(Object.prototype.hasOwnProperty.call(base, method)).toBeTruthy(); - }); - } -} - -window.ClassSpecHelper = ClassSpecHelper; diff --git a/spec/frontend/helpers/class_spec_helper_spec.js b/spec/frontend/helpers/class_spec_helper_spec.js deleted file mode 100644 index 533d5687bde..00000000000 --- a/spec/frontend/helpers/class_spec_helper_spec.js +++ /dev/null @@ -1,26 +0,0 @@ -/* global ClassSpecHelper */ - -import './class_spec_helper'; - -describe('ClassSpecHelper', () => { - let testContext; - - beforeEach(() => { - testContext = {}; - }); - - describe('itShouldBeAStaticMethod', () => { - beforeEach(() => { - class TestClass { - instanceMethod() { - this.prop = 'val'; - } - static staticMethod() {} - } - - testContext.TestClass = TestClass; - }); - - ClassSpecHelper.itShouldBeAStaticMethod(ClassSpecHelper, 'itShouldBeAStaticMethod'); - }); -}); diff --git a/spec/frontend/helpers/dom_events_helper.js b/spec/frontend/helpers/dom_events_helper.js deleted file mode 100644 index 423e5c58bb4..00000000000 --- a/spec/frontend/helpers/dom_events_helper.js +++ /dev/null @@ -1,8 +0,0 @@ -export const triggerDOMEvent = type => { - window.document.dispatchEvent( - new Event(type, { - bubbles: true, - cancelable: true, - }), - ); -}; diff --git a/spec/frontend/helpers/dom_shims/README.md b/spec/frontend/helpers/dom_shims/README.md deleted file mode 100644 index 1105e4b0c4c..00000000000 --- a/spec/frontend/helpers/dom_shims/README.md +++ /dev/null @@ -1,12 +0,0 @@ -## Jest DOM shims - -This is where we shim parts of JSDom. It is imported in our root `test_setup.js`. - -### Why do we need this? - -Since JSDom mocks a real DOM environment (which is a good thing), it -unfortunately does not support some jQuery matchers. - -### References - -- https://gitlab.com/gitlab-org/gitlab/merge_requests/17906#note_224448120 diff --git a/spec/frontend/helpers/dom_shims/create_object_url.js b/spec/frontend/helpers/dom_shims/create_object_url.js deleted file mode 100644 index 94d060cab08..00000000000 --- a/spec/frontend/helpers/dom_shims/create_object_url.js +++ /dev/null @@ -1,3 +0,0 @@ -URL.createObjectURL = function createObjectURL() { - return 'blob:https://gitlab.com/048c7ac1-98de-4a37-ab1b-0206d0ea7e1b'; -}; diff --git a/spec/frontend/helpers/dom_shims/element_scroll_by.js b/spec/frontend/helpers/dom_shims/element_scroll_by.js deleted file mode 100644 index 7d91279e4aa..00000000000 --- a/spec/frontend/helpers/dom_shims/element_scroll_by.js +++ /dev/null @@ -1 +0,0 @@ -Element.prototype.scrollBy = jest.fn(); diff --git a/spec/frontend/helpers/dom_shims/element_scroll_into_view.js b/spec/frontend/helpers/dom_shims/element_scroll_into_view.js deleted file mode 100644 index a7262d04db0..00000000000 --- a/spec/frontend/helpers/dom_shims/element_scroll_into_view.js +++ /dev/null @@ -1 +0,0 @@ -Element.prototype.scrollIntoView = jest.fn(); diff --git a/spec/frontend/helpers/dom_shims/element_scroll_to.js b/spec/frontend/helpers/dom_shims/element_scroll_to.js deleted file mode 100644 index 68f8a115865..00000000000 --- a/spec/frontend/helpers/dom_shims/element_scroll_to.js +++ /dev/null @@ -1,6 +0,0 @@ -Element.prototype.scrollTo = jest.fn().mockImplementation(function scrollTo(x, y) { - this.scrollLeft = x; - this.scrollTop = y; - - this.dispatchEvent(new Event('scroll')); -}); diff --git a/spec/frontend/helpers/dom_shims/form_element.js b/spec/frontend/helpers/dom_shims/form_element.js deleted file mode 100644 index 46ef0374848..00000000000 --- a/spec/frontend/helpers/dom_shims/form_element.js +++ /dev/null @@ -1 +0,0 @@ -HTMLFormElement.prototype.submit = jest.fn(); diff --git a/spec/frontend/helpers/dom_shims/get_client_rects.js b/spec/frontend/helpers/dom_shims/get_client_rects.js deleted file mode 100644 index 7ba60dd7936..00000000000 --- a/spec/frontend/helpers/dom_shims/get_client_rects.js +++ /dev/null @@ -1,52 +0,0 @@ -function hasHiddenStyle(node) { - if (!node.style) { - return false; - } else if (node.style.display === 'none' || node.style.visibility === 'hidden') { - return true; - } - - return false; -} - -function createDefaultClientRect(node) { - const { outerWidth: width, outerHeight: height } = node; - - return { - bottom: height, - height, - left: 0, - right: width, - top: 0, - width, - x: 0, - y: 0, - }; -} - -/** - * This is needed to get the `toBeVisible` matcher to work in `jsdom` - * - * Reference: - * - https://github.com/jsdom/jsdom/issues/1322 - * - https://github.com/unindented/custom-jquery-matchers/blob/v2.1.0/packages/custom-jquery-matchers/src/matchers.js#L157 - */ -window.Element.prototype.getClientRects = function getClientRects() { - let node = this; - - while (node) { - if (node === document) { - break; - } - - if (hasHiddenStyle(node)) { - return []; - } - node = node.parentNode; - } - - if (!node) { - return []; - } - - return [createDefaultClientRect(node)]; -}; diff --git a/spec/frontend/helpers/dom_shims/get_client_rects_spec.js b/spec/frontend/helpers/dom_shims/get_client_rects_spec.js deleted file mode 100644 index e7b8f1e235b..00000000000 --- a/spec/frontend/helpers/dom_shims/get_client_rects_spec.js +++ /dev/null @@ -1,71 +0,0 @@ -const createTestElement = () => { - const element = document.createElement('div'); - - element.textContent = 'Hello World!'; - - return element; -}; - -describe('DOM patch for getClientRects', () => { - let origHtml; - let el; - - beforeEach(() => { - origHtml = document.body.innerHTML; - el = createTestElement(); - }); - - afterEach(() => { - document.body.innerHTML = origHtml; - }); - - describe('toBeVisible matcher', () => { - describe('when not attached to document', () => { - it('does not match', () => { - expect(el).not.toBeVisible(); - }); - }); - - describe('when attached to document', () => { - beforeEach(() => { - document.body.appendChild(el); - }); - - it('matches', () => { - expect(el).toBeVisible(); - }); - }); - - describe('with parent and attached to document', () => { - let parentEl; - - beforeEach(() => { - parentEl = createTestElement(); - parentEl.appendChild(el); - document.body.appendChild(parentEl); - }); - - it('matches', () => { - expect(el).toBeVisible(); - }); - - describe.each` - style - ${{ display: 'none' }} - ${{ visibility: 'hidden' }} - `('with style $style', ({ style }) => { - it('does not match when applied to element', () => { - Object.assign(el.style, style); - - expect(el).not.toBeVisible(); - }); - - it('does not match when applied to parent', () => { - Object.assign(parentEl.style, style); - - expect(el).not.toBeVisible(); - }); - }); - }); - }); -}); diff --git a/spec/frontend/helpers/dom_shims/image_element_properties.js b/spec/frontend/helpers/dom_shims/image_element_properties.js deleted file mode 100644 index d94c157e44d..00000000000 --- a/spec/frontend/helpers/dom_shims/image_element_properties.js +++ /dev/null @@ -1,12 +0,0 @@ -Object.defineProperty(global.HTMLImageElement.prototype, 'src', { - get() { - return this.$_jest_src || this.getAttribute('src'); - }, - set(val) { - this.$_jest_src = val; - - if (this.onload) { - this.onload(); - } - }, -}); diff --git a/spec/frontend/helpers/dom_shims/index.js b/spec/frontend/helpers/dom_shims/index.js deleted file mode 100644 index 9b70cb86b8b..00000000000 --- a/spec/frontend/helpers/dom_shims/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import './create_object_url'; -import './element_scroll_into_view'; -import './element_scroll_by'; -import './element_scroll_to'; -import './form_element'; -import './get_client_rects'; -import './inner_text'; -import './range'; -import './window_scroll_to'; -import './scroll_by'; -import './size_properties'; -import './image_element_properties'; diff --git a/spec/frontend/helpers/dom_shims/inner_text.js b/spec/frontend/helpers/dom_shims/inner_text.js deleted file mode 100644 index 2b8201eed31..00000000000 --- a/spec/frontend/helpers/dom_shims/inner_text.js +++ /dev/null @@ -1,11 +0,0 @@ -// workaround for JSDOM not supporting innerText -// see https://github.com/jsdom/jsdom/issues/1245 -Object.defineProperty(global.Element.prototype, 'innerText', { - get() { - return this.textContent; - }, - set(value) { - this.textContext = value; - }, - configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch -}); diff --git a/spec/frontend/helpers/dom_shims/range.js b/spec/frontend/helpers/dom_shims/range.js deleted file mode 100644 index 4ffdf3280ad..00000000000 --- a/spec/frontend/helpers/dom_shims/range.js +++ /dev/null @@ -1,13 +0,0 @@ -if (window.Range.prototype.getBoundingClientRect) { - throw new Error('window.Range.prototype.getBoundingClientRect already exists. Remove this stub!'); -} -window.Range.prototype.getBoundingClientRect = function getBoundingClientRect() { - return { x: 0, y: 0, width: 0, height: 0, top: 0, right: 0, bottom: 0, left: 0 }; -}; - -if (window.Range.prototype.getClientRects) { - throw new Error('window.Range.prototype.getClientRects already exists. Remove this stub!'); -} -window.Range.prototype.getClientRects = function getClientRects() { - return [this.getBoundingClientRect()]; -}; diff --git a/spec/frontend/helpers/dom_shims/scroll_by.js b/spec/frontend/helpers/dom_shims/scroll_by.js deleted file mode 100644 index 90387e51765..00000000000 --- a/spec/frontend/helpers/dom_shims/scroll_by.js +++ /dev/null @@ -1,7 +0,0 @@ -window.scrollX = 0; -window.scrollY = 0; - -window.scrollBy = (x, y) => { - window.scrollX += x; - window.scrollY += y; -}; diff --git a/spec/frontend/helpers/dom_shims/size_properties.js b/spec/frontend/helpers/dom_shims/size_properties.js deleted file mode 100644 index a2d5940bd1e..00000000000 --- a/spec/frontend/helpers/dom_shims/size_properties.js +++ /dev/null @@ -1,19 +0,0 @@ -const convertFromStyle = style => { - if (style.match(/[0-9](px|rem)/g)) { - return Number(style.replace(/[^0-9]/g, '')); - } - - return 0; -}; - -Object.defineProperty(global.HTMLElement.prototype, 'offsetWidth', { - get() { - return convertFromStyle(this.style.width || '0px'); - }, -}); - -Object.defineProperty(global.HTMLElement.prototype, 'offsetHeight', { - get() { - return convertFromStyle(this.style.height || '0px'); - }, -}); diff --git a/spec/frontend/helpers/dom_shims/window_scroll_to.js b/spec/frontend/helpers/dom_shims/window_scroll_to.js deleted file mode 100644 index 20ae1910bf3..00000000000 --- a/spec/frontend/helpers/dom_shims/window_scroll_to.js +++ /dev/null @@ -1 +0,0 @@ -window.scrollTo = jest.fn(); diff --git a/spec/frontend/helpers/emoji.js b/spec/frontend/helpers/emoji.js deleted file mode 100644 index e8a93e21818..00000000000 --- a/spec/frontend/helpers/emoji.js +++ /dev/null @@ -1,88 +0,0 @@ -import MockAdapter from 'axios-mock-adapter'; -import axios from '~/lib/utils/axios_utils'; -import { initEmojiMap, EMOJI_VERSION } from '~/emoji'; - -export const emojiFixtureMap = { - atom: { - moji: '⚛', - description: 'atom symbol', - unicodeVersion: '4.1', - aliases: ['atom_symbol'], - }, - bomb: { - moji: '💣', - unicodeVersion: '6.0', - description: 'bomb', - }, - construction_worker_tone5: { - moji: '👷🏿', - unicodeVersion: '8.0', - description: 'construction worker tone 5', - }, - five: { - moji: '5️⃣', - unicodeVersion: '3.0', - description: 'keycap digit five', - }, - grey_question: { - moji: '❔', - unicodeVersion: '6.0', - description: 'white question mark ornament', - }, - - // used for regression tests - // black_heart MUST come before heart - // custard MUST come before star - black_heart: { - moji: '🖤', - unicodeVersion: '1.1', - description: 'black heart', - }, - heart: { - moji: '❤', - unicodeVersion: '1.1', - description: 'heavy black heart', - }, - custard: { - moji: '🍮', - unicodeVersion: '6.0', - description: 'custard', - }, - star: { - moji: '⭐', - unicodeVersion: '5.1', - description: 'white medium star', - }, -}; - -Object.keys(emojiFixtureMap).forEach(k => { - emojiFixtureMap[k].name = k; - if (!emojiFixtureMap[k].aliases) { - emojiFixtureMap[k].aliases = []; - } -}); - -export async function initEmojiMock() { - const emojiData = Object.fromEntries( - Object.values(emojiFixtureMap).map(m => { - const { name: n, moji: e, unicodeVersion: u, category: c, description: d } = m; - return [n, { c, e, d, u }]; - }), - ); - - const mock = new MockAdapter(axios); - mock.onGet(`/-/emojis/${EMOJI_VERSION}/emojis.json`).reply(200, JSON.stringify(emojiData)); - - await initEmojiMap(); - - return mock; -} - -export function describeEmojiFields(label, tests) { - describe.each` - field | accessor - ${'name'} | ${e => e.name} - ${'alias'} | ${e => e.aliases[0]} - ${'description'} | ${e => e.description} - `(label, tests); -} diff --git a/spec/frontend/helpers/event_hub_factory_spec.js b/spec/frontend/helpers/event_hub_factory_spec.js index c4f63ff6049..2491e8d5dda 100644 --- a/spec/frontend/helpers/event_hub_factory_spec.js +++ b/spec/frontend/helpers/event_hub_factory_spec.js @@ -93,7 +93,7 @@ describe('event bus factory', () => { describe('$off', () => { beforeEach(() => { - otherHandlers.forEach(x => eventBus.$on(TEST_EVENT, x)); + otherHandlers.forEach((x) => eventBus.$on(TEST_EVENT, x)); eventBus.$on(TEST_EVENT, handler); }); @@ -115,7 +115,7 @@ describe('event bus factory', () => { eventBus.$emit(TEST_EVENT); expect(handler).not.toHaveBeenCalled(); - expect(otherHandlers.map(x => x.mock.calls.length)).toEqual(otherHandlers.map(() => 1)); + expect(otherHandlers.map((x) => x.mock.calls.length)).toEqual(otherHandlers.map(() => 1)); }); it('without a handler, will no longer call any handlers', () => { @@ -124,13 +124,13 @@ describe('event bus factory', () => { eventBus.$emit(TEST_EVENT); expect(handler).not.toHaveBeenCalled(); - expect(otherHandlers.map(x => x.mock.calls.length)).toEqual(otherHandlers.map(() => 0)); + expect(otherHandlers.map((x) => x.mock.calls.length)).toEqual(otherHandlers.map(() => 0)); }); }); describe('$emit', () => { beforeEach(() => { - otherHandlers.forEach(x => eventBus.$on(TEST_EVENT_2, x)); + otherHandlers.forEach((x) => eventBus.$on(TEST_EVENT_2, x)); eventBus.$on(TEST_EVENT, handler); }); @@ -138,7 +138,7 @@ describe('event bus factory', () => { eventBus.$emit(TEST_EVENT, 'arg1'); expect(handler).toHaveBeenCalledWith('arg1'); - expect(otherHandlers.map(x => x.mock.calls.length)).toEqual(otherHandlers.map(() => 0)); + expect(otherHandlers.map((x) => x.mock.calls.length)).toEqual(otherHandlers.map(() => 0)); }); }); }); diff --git a/spec/frontend/helpers/experimentation_helper.js b/spec/frontend/helpers/experimentation_helper.js deleted file mode 100644 index c08c25155e8..00000000000 --- a/spec/frontend/helpers/experimentation_helper.js +++ /dev/null @@ -1,14 +0,0 @@ -import { merge } from 'lodash'; - -export function withGonExperiment(experimentKey, value = true) { - let origGon; - - beforeEach(() => { - origGon = window.gon; - window.gon = merge({}, window.gon || {}, { experiments: { [experimentKey]: value } }); - }); - - afterEach(() => { - window.gon = origGon; - }); -} diff --git a/spec/frontend/helpers/fake_date.js b/spec/frontend/helpers/fake_date.js deleted file mode 100644 index 387747ab5bd..00000000000 --- a/spec/frontend/helpers/fake_date.js +++ /dev/null @@ -1,49 +0,0 @@ -// Frida Kahlo's birthday (6 = July) -export const DEFAULT_ARGS = [2020, 6, 6]; - -const RealDate = Date; - -const isMocked = val => Boolean(val.mock); - -export const createFakeDateClass = ctorDefault => { - const FakeDate = new Proxy(RealDate, { - construct: (target, argArray) => { - const ctorArgs = argArray.length ? argArray : ctorDefault; - - return new RealDate(...ctorArgs); - }, - apply: (target, thisArg, argArray) => { - const ctorArgs = argArray.length ? argArray : ctorDefault; - - return new RealDate(...ctorArgs).toString(); - }, - // We want to overwrite the default 'now', but only if it's not already mocked - get: (target, prop) => { - if (prop === 'now' && !isMocked(target[prop])) { - return () => new RealDate(...ctorDefault).getTime(); - } - - return target[prop]; - }, - getPrototypeOf: target => { - return target.prototype; - }, - // We need to be able to set props so that `jest.spyOn` will work. - set: (target, prop, value) => { - // eslint-disable-next-line no-param-reassign - target[prop] = value; - return true; - }, - }); - - return FakeDate; -}; - -export const useFakeDate = (...args) => { - const FakeDate = createFakeDateClass(args.length ? args : DEFAULT_ARGS); - global.Date = FakeDate; -}; - -export const useRealDate = () => { - global.Date = RealDate; -}; diff --git a/spec/frontend/helpers/fake_date_spec.js b/spec/frontend/helpers/fake_date_spec.js deleted file mode 100644 index b3ed13e238a..00000000000 --- a/spec/frontend/helpers/fake_date_spec.js +++ /dev/null @@ -1,37 +0,0 @@ -import { createFakeDateClass, DEFAULT_ARGS, useRealDate } from './fake_date'; - -describe('spec/helpers/fake_date', () => { - describe('createFakeDateClass', () => { - let FakeDate; - - beforeAll(() => { - useRealDate(); - }); - - beforeEach(() => { - FakeDate = createFakeDateClass(DEFAULT_ARGS); - }); - - it('should use default args', () => { - expect(new FakeDate()).toMatchInlineSnapshot(`2020-07-06T00:00:00.000Z`); - }); - - it('should use default args when called as a function', () => { - expect(FakeDate()).toMatchInlineSnapshot( - `"Mon Jul 06 2020 00:00:00 GMT+0000 (Greenwich Mean Time)"`, - ); - }); - - it('should have deterministic now()', () => { - expect(FakeDate.now()).toMatchInlineSnapshot(`1593993600000`); - }); - - it('should be instanceof Date', () => { - expect(new FakeDate()).toBeInstanceOf(Date); - }); - - it('should be instanceof self', () => { - expect(new FakeDate()).toBeInstanceOf(FakeDate); - }); - }); -}); diff --git a/spec/frontend/helpers/fake_request_animation_frame.js b/spec/frontend/helpers/fake_request_animation_frame.js deleted file mode 100644 index f6fc29df4dc..00000000000 --- a/spec/frontend/helpers/fake_request_animation_frame.js +++ /dev/null @@ -1,12 +0,0 @@ -export const useFakeRequestAnimationFrame = () => { - let orig; - - beforeEach(() => { - orig = global.requestAnimationFrame; - global.requestAnimationFrame = cb => cb(); - }); - - afterEach(() => { - global.requestAnimationFrame = orig; - }); -}; diff --git a/spec/frontend/helpers/filtered_search_spec_helper.js b/spec/frontend/helpers/filtered_search_spec_helper.js deleted file mode 100644 index ecf10694a16..00000000000 --- a/spec/frontend/helpers/filtered_search_spec_helper.js +++ /dev/null @@ -1,69 +0,0 @@ -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"> - <svg class="s16 close-icon"></svg> - </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 deleted file mode 100644 index a89ceab3f8e..00000000000 --- a/spec/frontend/helpers/fixtures.js +++ /dev/null @@ -1,38 +0,0 @@ -import fs from 'fs'; -import path from 'path'; - -import { ErrorWithStack } from 'jest-util'; - -export function getFixture(relativePath) { - const basePath = relativePath.startsWith('static/') - ? global.staticFixturesBasePath - : global.fixturesBasePath; - const absolutePath = path.join(basePath, relativePath); - if (!fs.existsSync(absolutePath)) { - throw new ErrorWithStack( - `Fixture file ${relativePath} does not exist. - -Did you run bin/rake frontend:fixtures?`, - getFixture, - ); - } - - return fs.readFileSync(absolutePath, 'utf8'); -} - -export const getJSONFixture = relativePath => JSON.parse(getFixture(relativePath)); - -export const resetHTMLFixture = () => { - document.head.innerHTML = ''; - document.body.innerHTML = ''; -}; - -export const setHTMLFixture = (htmlContent, resetHook = afterEach) => { - document.body.innerHTML = htmlContent; - resetHook(resetHTMLFixture); -}; - -export const loadHTMLFixture = (relativePath, resetHook = afterEach) => { - const fileContent = getFixture(relativePath); - setHTMLFixture(fileContent, resetHook); -}; diff --git a/spec/frontend/helpers/help_page_helper_spec.js b/spec/frontend/helpers/help_page_helper_spec.js new file mode 100644 index 00000000000..09c1a113a96 --- /dev/null +++ b/spec/frontend/helpers/help_page_helper_spec.js @@ -0,0 +1,29 @@ +import { helpPagePath } from '~/helpers/help_page_helper'; + +describe('help page helper', () => { + it.each` + relative_url_root | path | anchor | expected + ${undefined} | ${'administration/index'} | ${undefined} | ${'/help/administration/index'} + ${''} | ${'administration/index'} | ${undefined} | ${'/help/administration/index'} + ${'/'} | ${'administration/index'} | ${undefined} | ${'/help/administration/index'} + ${'/gitlab'} | ${'administration/index'} | ${undefined} | ${'/gitlab/help/administration/index'} + ${'/gitlab/'} | ${'administration/index'} | ${undefined} | ${'/gitlab/help/administration/index'} + ${undefined} | ${'administration/index'} | ${undefined} | ${'/help/administration/index'} + ${'/'} | ${'administration/index'} | ${undefined} | ${'/help/administration/index'} + ${''} | ${'administration/index.md'} | ${undefined} | ${'/help/administration/index.md'} + ${''} | ${'administration/index.md'} | ${'installing-gitlab'} | ${'/help/administration/index.md#installing-gitlab'} + ${''} | ${'administration/index'} | ${'installing-gitlab'} | ${'/help/administration/index#installing-gitlab'} + ${''} | ${'administration/index'} | ${'#installing-gitlab'} | ${'/help/administration/index#installing-gitlab'} + ${''} | ${'/administration/index'} | ${undefined} | ${'/help/administration/index'} + ${''} | ${'administration/index/'} | ${undefined} | ${'/help/administration/index/'} + ${''} | ${'/administration/index/'} | ${undefined} | ${'/help/administration/index/'} + ${'/'} | ${'/administration/index'} | ${undefined} | ${'/help/administration/index'} + `( + 'generates correct URL when path is `$path`, relative url is `$relative_url_root` and anchor is `$anchor`', + ({ relative_url_root, anchor, path, expected }) => { + window.gon = { relative_url_root }; + + expect(helpPagePath(path, { anchor })).toBe(expected); + }, + ); +}); diff --git a/spec/frontend/helpers/init_vue_mr_page_helper.js b/spec/frontend/helpers/init_vue_mr_page_helper.js deleted file mode 100644 index b9aed63d0f6..00000000000 --- a/spec/frontend/helpers/init_vue_mr_page_helper.js +++ /dev/null @@ -1,47 +0,0 @@ -import MockAdapter from 'axios-mock-adapter'; -import initMRPage from '~/mr_notes'; -import axios from '~/lib/utils/axios_utils'; -import { userDataMock, notesDataMock, noteableDataMock } from '../notes/mock_data'; -import diffFileMockData from '../diffs/mock_data/diff_file'; - -export default function initVueMRPage() { - const mrTestEl = document.createElement('div'); - mrTestEl.className = 'js-merge-request-test'; - document.body.appendChild(mrTestEl); - - const diffsAppEndpoint = '/diffs/app/endpoint'; - const diffsAppProjectPath = 'testproject'; - const mrEl = document.createElement('div'); - mrEl.className = 'merge-request fixture-mr'; - mrEl.setAttribute('data-mr-action', 'diffs'); - mrTestEl.appendChild(mrEl); - - const mrDiscussionsEl = document.createElement('div'); - mrDiscussionsEl.id = 'js-vue-mr-discussions'; - mrDiscussionsEl.setAttribute('data-current-user-data', JSON.stringify(userDataMock)); - mrDiscussionsEl.setAttribute('data-noteable-data', JSON.stringify(noteableDataMock)); - mrDiscussionsEl.setAttribute('data-notes-data', JSON.stringify(notesDataMock)); - mrDiscussionsEl.setAttribute('data-noteable-type', 'merge-request'); - mrDiscussionsEl.setAttribute('data-is-locked', 'false'); - mrTestEl.appendChild(mrDiscussionsEl); - - const discussionCounterEl = document.createElement('div'); - discussionCounterEl.id = 'js-vue-discussion-counter'; - mrTestEl.appendChild(discussionCounterEl); - - const diffsAppEl = document.createElement('div'); - diffsAppEl.id = 'js-diffs-app'; - diffsAppEl.setAttribute('data-endpoint', diffsAppEndpoint); - diffsAppEl.setAttribute('data-project-path', diffsAppProjectPath); - diffsAppEl.setAttribute('data-current-user-data', JSON.stringify(userDataMock)); - mrTestEl.appendChild(diffsAppEl); - - const mock = new MockAdapter(axios); - mock.onGet(diffsAppEndpoint).reply(200, { - branch_name: 'foo', - diff_files: [diffFileMockData], - }); - - initMRPage(); - return mock; -} diff --git a/spec/frontend/helpers/jest_helpers.js b/spec/frontend/helpers/jest_helpers.js deleted file mode 100644 index 0b623e0a59b..00000000000 --- a/spec/frontend/helpers/jest_helpers.js +++ /dev/null @@ -1,22 +0,0 @@ -/* -@module - -This method provides convenience functions to help migrating from Karma/Jasmine to Jest. - -Try not to use these in new tests - this module is provided primarily for convenience of migrating tests. - */ - -/** - * Creates a plain JS object pre-populated with Jest spy functions. Useful for making simple mocks classes. - * - * @see https://jasmine.github.io/2.0/introduction.html#section-Spies:_%3Ccode%3EcreateSpyObj%3C/code%3E - * @param {string} baseName Human-readable name of the object. This is used for reporting purposes. - * @param methods {string[]} List of method names that will be added to the spy object. - */ -export function createSpyObj(baseName, methods) { - const obj = {}; - methods.forEach(method => { - obj[method] = jest.fn().mockName(`${baseName}#${method}`); - }); - return obj; -} diff --git a/spec/frontend/helpers/jquery.js b/spec/frontend/helpers/jquery.js deleted file mode 100644 index 4af5f904394..00000000000 --- a/spec/frontend/helpers/jquery.js +++ /dev/null @@ -1,18 +0,0 @@ -import $ from 'jquery'; - -// Expose jQuery so specs using jQuery plugins can be imported nicely. -// Here is an issue to explore better alternatives: -// https://gitlab.com/gitlab-org/gitlab/issues/12448 -global.$ = $; -global.jQuery = $; - -// Fail tests for unmocked requests -$.ajax = () => { - const err = new Error( - 'Unexpected unmocked jQuery.ajax() call! Make sure to mock jQuery.ajax() in tests.', - ); - global.fail(err); - throw err; -}; - -export default $; diff --git a/spec/frontend/helpers/keep_alive_component_helper.js b/spec/frontend/helpers/keep_alive_component_helper.js deleted file mode 100644 index 54f40bf9093..00000000000 --- a/spec/frontend/helpers/keep_alive_component_helper.js +++ /dev/null @@ -1,29 +0,0 @@ -import Vue from 'vue'; - -export function keepAlive(KeptAliveComponent) { - return Vue.extend({ - components: { - KeptAliveComponent, - }, - data() { - return { - view: 'KeptAliveComponent', - }; - }, - methods: { - async activate() { - this.view = 'KeptAliveComponent'; - await this.$nextTick(); - }, - async deactivate() { - this.view = 'div'; - await this.$nextTick(); - }, - async reactivate() { - await this.deactivate(); - await this.activate(); - }, - }, - template: `<keep-alive><component :is="view"></component></keep-alive>`, - }); -} diff --git a/spec/frontend/helpers/keep_alive_component_helper_spec.js b/spec/frontend/helpers/keep_alive_component_helper_spec.js deleted file mode 100644 index dcccc14f396..00000000000 --- a/spec/frontend/helpers/keep_alive_component_helper_spec.js +++ /dev/null @@ -1,32 +0,0 @@ -import { mount } from '@vue/test-utils'; -import { keepAlive } from './keep_alive_component_helper'; - -const component = { - template: '<div>Test Component</div>', -}; - -describe('keepAlive', () => { - let wrapper; - - beforeEach(() => { - wrapper = mount(keepAlive(component)); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it('converts a component to a keep-alive component', async () => { - const { element } = wrapper.find(component); - - await wrapper.vm.deactivate(); - expect(wrapper.find(component).exists()).toBe(false); - - await wrapper.vm.activate(); - - // assert that when the component is destroyed and re-rendered, the - // newly rendered component has the reference to the old component - // (i.e. the old component was deactivated and activated) - expect(wrapper.find(component).element).toBe(element); - }); -}); diff --git a/spec/frontend/helpers/local_storage_helper.js b/spec/frontend/helpers/local_storage_helper.js deleted file mode 100644 index 0318b80aaef..00000000000 --- a/spec/frontend/helpers/local_storage_helper.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Manage the instance of a custom `window.localStorage` - * - * This only encapsulates the setup / teardown logic so that it can easily be - * reused with different implementations (i.e. a spy or a [fake][1]) - * - * [1]: https://stackoverflow.com/a/41434763/1708147 - * - * @param {() => any} fn Function that returns the object to use for localStorage - */ -const useLocalStorage = fn => { - const origLocalStorage = window.localStorage; - let currentLocalStorage = origLocalStorage; - - Object.defineProperty(window, 'localStorage', { - get: () => currentLocalStorage, - }); - - beforeEach(() => { - currentLocalStorage = fn(); - }); - - afterEach(() => { - currentLocalStorage = origLocalStorage; - }); -}; - -/** - * Create an object with the localStorage interface but `jest.fn()` implementations. - */ -export const createLocalStorageSpy = () => { - let storage = {}; - - return { - clear: jest.fn(() => { - storage = {}; - }), - getItem: jest.fn(key => (key in storage ? storage[key] : null)), - setItem: jest.fn((key, value) => { - storage[key] = value; - }), - removeItem: jest.fn(key => delete storage[key]), - }; -}; - -/** - * Before each test, overwrite `window.localStorage` with a spy implementation. - */ -export const useLocalStorageSpy = () => useLocalStorage(createLocalStorageSpy); diff --git a/spec/frontend/helpers/local_storage_helper_spec.js b/spec/frontend/helpers/local_storage_helper_spec.js deleted file mode 100644 index 5d9961e7631..00000000000 --- a/spec/frontend/helpers/local_storage_helper_spec.js +++ /dev/null @@ -1,28 +0,0 @@ -import { useLocalStorageSpy } from './local_storage_helper'; - -describe('block before helper is installed', () => { - it('should leave original localStorage intact', () => { - expect(localStorage.getItem).toEqual(expect.any(Function)); - expect(jest.isMockFunction(localStorage.getItem)).toBe(false); - }); -}); - -describe('localStorage helper', () => { - useLocalStorageSpy(); - - it('mocks localStorage but works exactly like original localStorage', () => { - localStorage.setItem('test', 'testing'); - localStorage.setItem('test2', 'testing'); - - expect(localStorage.getItem('test')).toBe('testing'); - - localStorage.removeItem('test', 'testing'); - - expect(localStorage.getItem('test')).toBe(null); - expect(localStorage.getItem('test2')).toBe('testing'); - - localStorage.clear(); - - expect(localStorage.getItem('test2')).toBe(null); - }); -}); diff --git a/spec/frontend/helpers/locale_helper.js b/spec/frontend/helpers/locale_helper.js deleted file mode 100644 index 283d9bc14c9..00000000000 --- a/spec/frontend/helpers/locale_helper.js +++ /dev/null @@ -1,9 +0,0 @@ -export const setLanguage = languageCode => { - const htmlElement = document.querySelector('html'); - - if (languageCode) { - htmlElement.setAttribute('lang', languageCode); - } else { - htmlElement.removeAttribute('lang'); - } -}; diff --git a/spec/frontend/helpers/mock_apollo_helper.js b/spec/frontend/helpers/mock_apollo_helper.js deleted file mode 100644 index 914cce1d662..00000000000 --- a/spec/frontend/helpers/mock_apollo_helper.js +++ /dev/null @@ -1,23 +0,0 @@ -import { InMemoryCache } from 'apollo-cache-inmemory'; -import { createMockClient } from 'mock-apollo-client'; -import VueApollo from 'vue-apollo'; - -export default (handlers = [], resolvers = {}) => { - const fragmentMatcher = { match: () => true }; - const cache = new InMemoryCache({ - fragmentMatcher, - addTypename: false, - }); - - const mockClient = createMockClient({ cache, resolvers }); - - if (Array.isArray(handlers)) { - handlers.forEach(([query, value]) => mockClient.setRequestHandler(query, value)); - } else { - throw new Error('You should pass an array of handlers to mock Apollo client'); - } - - const apolloProvider = new VueApollo({ defaultClient: mockClient }); - - return apolloProvider; -}; diff --git a/spec/frontend/helpers/mock_dom_observer.js b/spec/frontend/helpers/mock_dom_observer.js deleted file mode 100644 index 1b93b81535d..00000000000 --- a/spec/frontend/helpers/mock_dom_observer.js +++ /dev/null @@ -1,96 +0,0 @@ -/* eslint-disable class-methods-use-this, max-classes-per-file */ -import { isMatch } from 'lodash'; - -/** - * This class gives us a JSDom friendly DOM observer which we can manually trigger in tests - * - * Use this in place of MutationObserver or IntersectionObserver - */ -class MockObserver { - constructor(cb) { - this.$_cb = cb; - this.$_observers = []; - } - - observe(node, options = {}) { - this.$_observers.push([node, options]); - } - - disconnect() { - this.$_observers = []; - } - - takeRecords() {} - - // eslint-disable-next-line babel/camelcase - $_triggerObserve(node, { entry = {}, options = {} } = {}) { - if (this.$_hasObserver(node, options)) { - this.$_cb([{ target: node, ...entry }]); - } - } - - // eslint-disable-next-line babel/camelcase - $_hasObserver(node, options = {}) { - return this.$_observers.some( - ([obvNode, obvOptions]) => node === obvNode && isMatch(options, obvOptions), - ); - } -} - -class MockIntersectionObserver extends MockObserver { - unobserve(node) { - this.$_observers = this.$_observers.filter(([obvNode]) => node === obvNode); - } -} - -/** - * Use this function to setup a mock observer instance in place of the given DOM Observer - * - * Example: - * ``` - * describe('', () => { - * const { trigger: triggerMutate } = useMockMutationObserver(); - * - * it('test', () => { - * trigger(el, { options: { childList: true }, entry: { } }); - * }); - * }) - * ``` - * - * @param {String} key - */ -const useMockObserver = (key, createMock) => { - let mockObserver; - let origObserver; - - beforeEach(() => { - origObserver = global[key]; - global[key] = jest.fn().mockImplementation((...args) => { - mockObserver = createMock(...args); - return mockObserver; - }); - }); - - afterEach(() => { - mockObserver = null; - global[key] = origObserver; - }); - - const trigger = (...args) => { - if (!mockObserver) { - return; - } - - mockObserver.$_triggerObserve(...args); - }; - - const observersCount = () => mockObserver.$_observers.length; - - return { trigger, observersCount }; -}; - -export const useMockIntersectionObserver = () => - useMockObserver('IntersectionObserver', (...args) => new MockIntersectionObserver(...args)); - -export const useMockMutationObserver = () => - useMockObserver('MutationObserver', (...args) => new MockObserver(...args)); diff --git a/spec/frontend/helpers/mock_window_location_helper.js b/spec/frontend/helpers/mock_window_location_helper.js deleted file mode 100644 index 175044d1fce..00000000000 --- a/spec/frontend/helpers/mock_window_location_helper.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Manage the instance of a custom `window.location` - * - * This only encapsulates the setup / teardown logic so that it can easily be - * reused with different implementations (i.e. a spy or a [fake][1]) - * - * [1]: https://stackoverflow.com/a/41434763/1708147 - * - * @param {() => any} fn Function that returns the object to use for window.location - */ -const useMockLocation = fn => { - const origWindowLocation = window.location; - let currentWindowLocation; - - Object.defineProperty(window, 'location', { - get: () => currentWindowLocation, - }); - - beforeEach(() => { - currentWindowLocation = fn(); - }); - - afterEach(() => { - currentWindowLocation = origWindowLocation; - }); -}; - -/** - * Create an object with the location interface but `jest.fn()` implementations. - */ -export const createWindowLocationSpy = () => { - return { - assign: jest.fn(), - reload: jest.fn(), - replace: jest.fn(), - toString: jest.fn(), - }; -}; - -/** - * Before each test, overwrite `window.location` with a spy implementation. - */ -export const useMockLocationHelper = () => useMockLocation(createWindowLocationSpy); diff --git a/spec/frontend/helpers/monitor_helper_spec.js b/spec/frontend/helpers/monitor_helper_spec.js index 219b05e312b..ef2a9fb0665 100644 --- a/spec/frontend/helpers/monitor_helper_spec.js +++ b/spec/frontend/helpers/monitor_helper_spec.js @@ -3,7 +3,11 @@ import { getSeriesLabel, makeDataSeries } from '~/helpers/monitor_helper'; describe('monitor helper', () => { const defaultConfig = { default: true, name: 'default name' }; const name = 'data name'; - const series = [[1, 1], [2, 2], [3, 3]]; + const series = [ + [1, 1], + [2, 2], + [3, 3], + ]; describe('getSeriesLabel', () => { const metricAttributes = { __name__: 'up', app: 'prometheus' }; diff --git a/spec/frontend/helpers/set_timeout_promise_helper.js b/spec/frontend/helpers/set_timeout_promise_helper.js deleted file mode 100644 index 47087619187..00000000000 --- a/spec/frontend/helpers/set_timeout_promise_helper.js +++ /dev/null @@ -1,4 +0,0 @@ -export default (time = 0) => - new Promise(resolve => { - setTimeout(resolve, time); - }); diff --git a/spec/frontend/helpers/set_window_location_helper.js b/spec/frontend/helpers/set_window_location_helper.js deleted file mode 100644 index a94e73762c9..00000000000 --- a/spec/frontend/helpers/set_window_location_helper.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * 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 deleted file mode 100644 index da609b6bbf0..00000000000 --- a/spec/frontend/helpers/set_window_location_helper_spec.js +++ /dev/null @@ -1,40 +0,0 @@ -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(/Invalid URL/); - expect(window.location).toBe(originalLocation); - }, - ); -}); diff --git a/spec/frontend/helpers/startup_css_helper_spec.js b/spec/frontend/helpers/startup_css_helper_spec.js index 2d560c43fa5..703bdbd342f 100644 --- a/spec/frontend/helpers/startup_css_helper_spec.js +++ b/spec/frontend/helpers/startup_css_helper_spec.js @@ -39,24 +39,7 @@ describe('waitForCSSLoaded', () => { }); }); - describe('with startup css disabled', () => { - gon.features = { - startupCss: false, - }; - - it('should invoke the action right away', async () => { - const events = waitForCSSLoaded(mockedCallback); - await events; - - expect(mockedCallback).toHaveBeenCalledTimes(1); - }); - }); - describe('with startup css enabled', () => { - gon.features = { - startupCss: true, - }; - it('should dispatch CSSLoaded when the assets are cached or already loaded', async () => { setFixtures(` <link href="one.css" data-startupcss="loaded"> @@ -75,7 +58,7 @@ describe('waitForCSSLoaded', () => { const events = waitForCSSLoaded(mockedCallback); document .querySelectorAll('[data-startupcss="loading"]') - .forEach(elem => elem.setAttribute('data-startupcss', 'loaded')); + .forEach((elem) => elem.setAttribute('data-startupcss', 'loaded')); document.dispatchEvent(new CustomEvent('CSSStartupLinkLoaded')); await events; diff --git a/spec/frontend/helpers/stub_children.js b/spec/frontend/helpers/stub_children.js deleted file mode 100644 index 91171eb3d8c..00000000000 --- a/spec/frontend/helpers/stub_children.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function stubChildren(Component) { - return Object.fromEntries(Object.keys(Component.components).map(c => [c, true])); -} diff --git a/spec/frontend/helpers/stub_component.js b/spec/frontend/helpers/stub_component.js deleted file mode 100644 index 45550450517..00000000000 --- a/spec/frontend/helpers/stub_component.js +++ /dev/null @@ -1,12 +0,0 @@ -export function stubComponent(Component, options = {}) { - return { - props: Component.props, - model: Component.model, - // Do not render any slots/scoped slots except default - // This differs from VTU behavior which renders all slots - template: '<div><slot></slot></div>', - // allows wrapper.find(Component) to work for stub - $_vueTestUtils_original: Component, - ...options, - }; -} diff --git a/spec/frontend/helpers/test_constants.js b/spec/frontend/helpers/test_constants.js deleted file mode 100644 index 69b78f556aa..00000000000 --- a/spec/frontend/helpers/test_constants.js +++ /dev/null @@ -1,19 +0,0 @@ -const FIXTURES_PATH = `/fixtures`; -const TEST_HOST = 'http://test.host'; - -const DUMMY_IMAGE_URL = `${FIXTURES_PATH}/static/images/one_white_pixel.png`; - -const GREEN_BOX_IMAGE_URL = `${FIXTURES_PATH}/static/images/green_box.png`; -const RED_BOX_IMAGE_URL = `${FIXTURES_PATH}/static/images/red_box.png`; - -// NOTE: module.exports is needed so that this file can be used -// by environment.js -// -// eslint-disable-next-line import/no-commonjs -module.exports = { - FIXTURES_PATH, - TEST_HOST, - DUMMY_IMAGE_URL, - GREEN_BOX_IMAGE_URL, - RED_BOX_IMAGE_URL, -}; diff --git a/spec/frontend/helpers/text_helper.js b/spec/frontend/helpers/text_helper.js deleted file mode 100644 index e0fe18e5560..00000000000 --- a/spec/frontend/helpers/text_helper.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Replaces line break with an empty space - * @param {*} data - */ -export const removeBreakLine = data => data.replace(/\r?\n|\r/g, ' '); - -/** - * Removes line breaks, spaces and trims the given text - * @param {String} str - * @returns {String} - */ -export const trimText = str => - str - .replace(/\r?\n|\r/g, '') - .replace(/\s\s+/g, ' ') - .trim(); - -export const removeWhitespace = str => str.replace(/\s\s+/g, ' '); diff --git a/spec/frontend/helpers/timeout.js b/spec/frontend/helpers/timeout.js deleted file mode 100644 index 702ef0be5aa..00000000000 --- a/spec/frontend/helpers/timeout.js +++ /dev/null @@ -1,59 +0,0 @@ -const NS_PER_SEC = 1e9; -const NS_PER_MS = 1e6; -const IS_DEBUGGING = process.execArgv.join(' ').includes('--inspect-brk'); - -let testTimeoutNS; - -export const setTestTimeout = newTimeoutMS => { - const newTimeoutNS = newTimeoutMS * NS_PER_MS; - // never accept a smaller timeout than the default - if (newTimeoutNS < testTimeoutNS) { - return; - } - - testTimeoutNS = newTimeoutNS; - jest.setTimeout(newTimeoutMS); -}; - -// Allows slow tests to set their own timeout. -// Useful for tests with jQuery, which is very slow in big DOMs. -let temporaryTimeoutNS = null; -export const setTestTimeoutOnce = newTimeoutMS => { - const newTimeoutNS = newTimeoutMS * NS_PER_MS; - // never accept a smaller timeout than the default - if (newTimeoutNS < testTimeoutNS) { - return; - } - - temporaryTimeoutNS = newTimeoutNS; -}; - -export const initializeTestTimeout = defaultTimeoutMS => { - setTestTimeout(defaultTimeoutMS); - - let testStartTime; - - // https://github.com/facebook/jest/issues/6947 - beforeEach(() => { - testStartTime = process.hrtime(); - }); - - afterEach(() => { - let timeoutNS = testTimeoutNS; - if (Number.isFinite(temporaryTimeoutNS)) { - timeoutNS = temporaryTimeoutNS; - temporaryTimeoutNS = null; - } - - const [seconds, remainingNs] = process.hrtime(testStartTime); - const elapsedNS = seconds * NS_PER_SEC + remainingNs; - - // Disable the timeout error when debugging. It is meaningless because - // debugging always takes longer than the test timeout. - if (elapsedNS > timeoutNS && !IS_DEBUGGING) { - throw new Error( - `Test took too long (${elapsedNS / NS_PER_MS}ms > ${timeoutNS / NS_PER_MS}ms)!`, - ); - } - }); -}; diff --git a/spec/frontend/helpers/tracking_helper.js b/spec/frontend/helpers/tracking_helper.js deleted file mode 100644 index bd3bd24028c..00000000000 --- a/spec/frontend/helpers/tracking_helper.js +++ /dev/null @@ -1,25 +0,0 @@ -import Tracking from '~/tracking'; - -export default Tracking; - -let document; -let handlers; - -export function mockTracking(category = '_category_', documentOverride, spyMethod) { - document = documentOverride || window.document; - window.snowplow = () => {}; - handlers = Tracking.bindDocument(category, document); - return spyMethod ? spyMethod(Tracking, 'event') : null; -} - -export function unmockTracking() { - window.snowplow = undefined; - handlers.forEach(event => document.removeEventListener(event.name, event.func)); -} - -export function triggerEvent(selectorOrEl, eventName = 'click') { - const event = new Event(eventName, { bubbles: true }); - const el = typeof selectorOrEl === 'string' ? document.querySelector(selectorOrEl) : selectorOrEl; - - el.dispatchEvent(event); -} diff --git a/spec/frontend/helpers/user_mock_data_helper.js b/spec/frontend/helpers/user_mock_data_helper.js deleted file mode 100644 index a6adc9dc3a0..00000000000 --- a/spec/frontend/helpers/user_mock_data_helper.js +++ /dev/null @@ -1,34 +0,0 @@ -let id = 1; - -// Code taken from: https://gist.github.com/6174/6062387 -const getRandomString = () => - Math.random() - .toString(36) - .substring(2, 15) + - Math.random() - .toString(36) - .substring(2, 15); - -const getRandomUrl = () => `https://${getRandomString()}.com/${getRandomString()}`; - -export default { - createNumberRandomUsers(numberUsers) { - const users = []; - for (let i = 0; i < numberUsers; i += 1) { - users.push({ - avatar_url: getRandomUrl(), - id: id + 1, - name: getRandomString(), - username: getRandomString(), - user_path: getRandomUrl(), - }); - - id += 1; - } - return users; - }, - - createRandomUser() { - return this.createNumberRandomUsers(1)[0]; - }, -}; diff --git a/spec/frontend/helpers/vue_mock_directive.js b/spec/frontend/helpers/vue_mock_directive.js deleted file mode 100644 index 28d4708835d..00000000000 --- a/spec/frontend/helpers/vue_mock_directive.js +++ /dev/null @@ -1,25 +0,0 @@ -export const getKey = name => `$_gl_jest_${name}`; - -export const getBinding = (el, name) => el[getKey(name)]; - -const writeBindingToElement = (el, { name, value, arg, modifiers }) => { - el[getKey(name)] = { - value, - arg, - modifiers, - }; -}; - -export const createMockDirective = () => ({ - bind(el, binding) { - writeBindingToElement(el, binding); - }, - - update(el, binding) { - writeBindingToElement(el, binding); - }, - - unbind(el, { name }) { - delete el[getKey(name)]; - }, -}); diff --git a/spec/frontend/helpers/vue_mount_component_helper.js b/spec/frontend/helpers/vue_mount_component_helper.js deleted file mode 100644 index 615ff69a01c..00000000000 --- a/spec/frontend/helpers/vue_mount_component_helper.js +++ /dev/null @@ -1,63 +0,0 @@ -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 || {}, - }); - - component.$slots = slots; - - return component.$mount(); -}; - -/** - * 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/vue_test_utils_helper.js b/spec/frontend/helpers/vue_test_utils_helper.js deleted file mode 100644 index 0e9127b5c65..00000000000 --- a/spec/frontend/helpers/vue_test_utils_helper.js +++ /dev/null @@ -1,53 +0,0 @@ -import { isArray } from 'lodash'; - -const vNodeContainsText = (vnode, text) => - (vnode.text && vnode.text.includes(text)) || - (vnode.children && vnode.children.filter(child => vNodeContainsText(child, text)).length); - -/** - * Determines whether a `shallowMount` Wrapper contains text - * within one of it's slots. This will also work on Wrappers - * acquired with `find()`, but only if it's parent Wrapper - * was shallowMounted. - * NOTE: Prefer checking the rendered output of a component - * wherever possible using something like `text()` instead. - * @param {Wrapper} shallowWrapper - Vue test utils wrapper (shallowMounted) - * @param {String} slotName - * @param {String} text - */ -export const shallowWrapperContainsSlotText = (shallowWrapper, slotName, text) => - Boolean( - shallowWrapper.vm.$slots[slotName].filter(vnode => vNodeContainsText(vnode, text)).length, - ); - -/** - * Returns a promise that waits for a mutation to be fired before resolving - * NOTE: There's no reject action here so it will hang if it waits for a mutation that won't happen. - * @param {Object} store - The Vue store that contains the mutations - * @param {String} expectedMutationType - The Mutation to wait for - */ -export const waitForMutation = (store, expectedMutationType) => - new Promise(resolve => { - const unsubscribe = store.subscribe(mutation => { - if (mutation.type === expectedMutationType) { - unsubscribe(); - resolve(); - } - }); - }); - -export const extendedWrapper = wrapper => { - if (isArray(wrapper) || !wrapper?.find) { - // eslint-disable-next-line no-console - console.warn( - '[vue-test-utils-helper]: you are trying to extend an object that is not a VueWrapper.', - ); - return wrapper; - } - - return Object.defineProperty(wrapper, 'findByTestId', { - value(id) { - return this.find(`[data-testid="${id}"]`); - }, - }); -}; diff --git a/spec/frontend/helpers/vue_test_utils_helper_spec.js b/spec/frontend/helpers/vue_test_utils_helper_spec.js deleted file mode 100644 index 31c4ccd5dbb..00000000000 --- a/spec/frontend/helpers/vue_test_utils_helper_spec.js +++ /dev/null @@ -1,92 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import { extendedWrapper, shallowWrapperContainsSlotText } from './vue_test_utils_helper'; - -describe('Vue test utils helpers', () => { - describe('shallowWrapperContainsSlotText', () => { - const mockText = 'text'; - const mockSlot = `<div>${mockText}</div>`; - let mockComponent; - - beforeEach(() => { - mockComponent = shallowMount( - { - render(h) { - h(`<div>mockedComponent</div>`); - }, - }, - { - slots: { - default: mockText, - namedSlot: mockSlot, - }, - }, - ); - }); - - it('finds text within shallowWrapper default slot', () => { - expect(shallowWrapperContainsSlotText(mockComponent, 'default', mockText)).toBe(true); - }); - - it('finds text within shallowWrapper named slot', () => { - expect(shallowWrapperContainsSlotText(mockComponent, 'namedSlot', mockText)).toBe(true); - }); - - it('returns false when text is not present', () => { - const searchText = 'absent'; - - expect(shallowWrapperContainsSlotText(mockComponent, 'default', searchText)).toBe(false); - expect(shallowWrapperContainsSlotText(mockComponent, 'namedSlot', searchText)).toBe(false); - }); - - it('searches with case-sensitivity', () => { - const searchText = mockText.toUpperCase(); - - expect(shallowWrapperContainsSlotText(mockComponent, 'default', searchText)).toBe(false); - expect(shallowWrapperContainsSlotText(mockComponent, 'namedSlot', searchText)).toBe(false); - }); - }); - - describe('extendedWrapper', () => { - describe('when an invalid wrapper is provided', () => { - beforeEach(() => { - // eslint-disable-next-line no-console - console.warn = jest.fn(); - }); - - it.each` - wrapper - ${{}} - ${[]} - ${null} - ${undefined} - ${1} - ${''} - `('should warn with an error when the wrapper is $wrapper', ({ wrapper }) => { - extendedWrapper(wrapper); - /* eslint-disable no-console */ - expect(console.warn).toHaveBeenCalled(); - expect(console.warn).toHaveBeenCalledWith( - '[vue-test-utils-helper]: you are trying to extend an object that is not a VueWrapper.', - ); - /* eslint-enable no-console */ - }); - }); - - describe('findByTestId', () => { - const testId = 'a-component'; - let mockComponent; - - beforeEach(() => { - mockComponent = extendedWrapper( - shallowMount({ - template: `<div data-testid="${testId}"></div>`, - }), - ); - }); - - it('should find the component by test id', () => { - expect(mockComponent.findByTestId(testId).exists()).toBe(true); - }); - }); - }); -}); diff --git a/spec/frontend/helpers/vuex_action_helper.js b/spec/frontend/helpers/vuex_action_helper.js deleted file mode 100644 index 64dd3888d47..00000000000 --- a/spec/frontend/helpers/vuex_action_helper.js +++ /dev/null @@ -1,128 +0,0 @@ -const noop = () => {}; - -/** - * Helper for testing action with expected mutations inspired in - * https://vuex.vuejs.org/en/testing.html - * - * @param {(Function|Object)} action to be tested, or object of named parameters - * @param {Object} payload will be provided to the action - * @param {Object} state will be provided to the action - * @param {Array} [expectedMutations=[]] mutations expected to be committed - * @param {Array} [expectedActions=[]] actions expected to be dispatched - * @param {Function} [done=noop] to be executed after the tests - * @return {Promise} - * - * @example - * testAction( - * actions.actionName, // action - * { }, // mocked payload - * state, //state - * // expected mutations - * [ - * { type: types.MUTATION} - * { type: types.MUTATION_1, payload: expect.any(Number)} - * ], - * // expected actions - * [ - * { type: 'actionName', payload: {param: 'foobar'}}, - * { type: 'actionName1'} - * ] - * done, - * ); - * - * @example - * testAction( - * actions.actionName, // action - * { }, // mocked payload - * state, //state - * [ { type: types.MUTATION} ], // expected mutations - * [], // expected actions - * ).then(done) - * .catch(done.fail); - * - * @example - * await testAction({ - * action: actions.actionName, - * payload: { deleteListId: 1 }, - * state: { lists: [1, 2, 3] }, - * expectedMutations: [ { type: types.MUTATION} ], - * expectedActions: [], - * }) - */ -export default ( - actionArg, - payloadArg, - stateArg, - expectedMutationsArg = [], - expectedActionsArg = [], - doneArg = noop, -) => { - let action = actionArg; - let payload = payloadArg; - let state = stateArg; - let expectedMutations = expectedMutationsArg; - let expectedActions = expectedActionsArg; - let done = doneArg; - - if (typeof actionArg !== 'function') { - ({ - action, - payload, - state, - expectedMutations = [], - expectedActions = [], - done = noop, - } = actionArg); - } - - const mutations = []; - const actions = []; - - // mock commit - const commit = (type, mutationPayload) => { - const mutation = { type }; - - if (typeof mutationPayload !== 'undefined') { - mutation.payload = mutationPayload; - } - - mutations.push(mutation); - }; - - // mock dispatch - const dispatch = (type, actionPayload) => { - const dispatchedAction = { type }; - - if (typeof actionPayload !== 'undefined') { - dispatchedAction.payload = actionPayload; - } - - actions.push(dispatchedAction); - }; - - const validateResults = () => { - expect({ - mutations, - actions, - }).toEqual({ - mutations: expectedMutations, - actions: expectedActions, - }); - done(); - }; - - const result = action( - { commit, state, dispatch, rootState: state, rootGetters: state, getters: state }, - payload, - ); - - return (result || new Promise(resolve => setImmediate(resolve))) - .catch(error => { - validateResults(); - throw error; - }) - .then(data => { - validateResults(); - return data; - }); -}; diff --git a/spec/frontend/helpers/vuex_action_helper_spec.js b/spec/frontend/helpers/vuex_action_helper_spec.js deleted file mode 100644 index 4d7bf21820a..00000000000 --- a/spec/frontend/helpers/vuex_action_helper_spec.js +++ /dev/null @@ -1,174 +0,0 @@ -import MockAdapter from 'axios-mock-adapter'; -import { TEST_HOST } from 'helpers/test_constants'; -import axios from '~/lib/utils/axios_utils'; -import testActionFn from './vuex_action_helper'; - -const testActionFnWithOptionsArg = (...args) => { - const [action, payload, state, expectedMutations, expectedActions, done] = args; - return testActionFn({ action, payload, state, expectedMutations, expectedActions, done }); -}; - -describe.each([testActionFn, testActionFnWithOptionsArg])( - 'VueX test helper (testAction)', - testAction => { - let originalExpect; - let assertion; - let mock; - const noop = () => {}; - - beforeEach(() => { - mock = new MockAdapter(axios); - /** - * In order to test the helper properly, we need to overwrite the Jest - * `expect` helper. We test that the testAction helper properly passes the - * dispatched actions/committed mutations to the Jest helper. - */ - originalExpect = expect; - assertion = null; - global.expect = actual => ({ - toEqual: () => { - originalExpect(actual).toEqual(assertion); - }, - }); - }); - - afterEach(() => { - mock.restore(); - global.expect = originalExpect; - }); - - it('properly passes state and payload to action', () => { - const exampleState = { FOO: 12, BAR: 3 }; - const examplePayload = { BAZ: 73, BIZ: 55 }; - - const action = ({ state }, payload) => { - originalExpect(state).toEqual(exampleState); - originalExpect(payload).toEqual(examplePayload); - }; - - assertion = { mutations: [], actions: [] }; - - testAction(action, examplePayload, exampleState); - }); - - describe('given a sync action', () => { - it('mocks committing mutations', () => { - const action = ({ commit }) => { - commit('MUTATION'); - }; - - assertion = { mutations: [{ type: 'MUTATION' }], actions: [] }; - - testAction(action, null, {}, assertion.mutations, assertion.actions, noop); - }); - - it('mocks dispatching actions', () => { - const action = ({ dispatch }) => { - dispatch('ACTION'); - }; - - assertion = { actions: [{ type: 'ACTION' }], mutations: [] }; - - testAction(action, null, {}, assertion.mutations, assertion.actions, noop); - }); - - it('works with done callback once finished', done => { - assertion = { mutations: [], actions: [] }; - - testAction(noop, null, {}, assertion.mutations, assertion.actions, done); - }); - - it('returns a promise', done => { - assertion = { mutations: [], actions: [] }; - - testAction(noop, null, {}, assertion.mutations, assertion.actions) - .then(done) - .catch(done.fail); - }); - }); - - describe('given an async action (returning a promise)', () => { - let lastError; - const data = { FOO: 'BAR' }; - - const asyncAction = ({ commit, dispatch }) => { - dispatch('ACTION'); - - return axios - .get(TEST_HOST) - .catch(error => { - commit('ERROR'); - lastError = error; - throw error; - }) - .then(() => { - commit('SUCCESS'); - return data; - }); - }; - - beforeEach(() => { - lastError = null; - }); - - it('works with done callback once finished', done => { - mock.onGet(TEST_HOST).replyOnce(200, 42); - - assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] }; - - testAction(asyncAction, null, {}, assertion.mutations, assertion.actions, done); - }); - - it('returns original data of successful promise while checking actions/mutations', done => { - mock.onGet(TEST_HOST).replyOnce(200, 42); - - assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] }; - - testAction(asyncAction, null, {}, assertion.mutations, assertion.actions) - .then(res => { - originalExpect(res).toEqual(data); - done(); - }) - .catch(done.fail); - }); - - it('returns original error of rejected promise while checking actions/mutations', done => { - mock.onGet(TEST_HOST).replyOnce(500, ''); - - assertion = { mutations: [{ type: 'ERROR' }], actions: [{ type: 'ACTION' }] }; - - testAction(asyncAction, null, {}, assertion.mutations, assertion.actions) - .then(done.fail) - .catch(error => { - originalExpect(error).toBe(lastError); - done(); - }); - }); - }); - - it('works with async actions not returning promises', done => { - const data = { FOO: 'BAR' }; - - const asyncAction = ({ commit, dispatch }) => { - dispatch('ACTION'); - - axios - .get(TEST_HOST) - .then(() => { - commit('SUCCESS'); - return data; - }) - .catch(error => { - commit('ERROR'); - throw error; - }); - }; - - mock.onGet(TEST_HOST).replyOnce(200, 42); - - assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] }; - - testAction(asyncAction, null, {}, assertion.mutations, assertion.actions, done); - }); - }, -); diff --git a/spec/frontend/helpers/wait_for_promises.js b/spec/frontend/helpers/wait_for_promises.js deleted file mode 100644 index 1d2b53fc770..00000000000 --- a/spec/frontend/helpers/wait_for_promises.js +++ /dev/null @@ -1 +0,0 @@ -export default () => new Promise(resolve => requestAnimationFrame(resolve)); diff --git a/spec/frontend/helpers/wait_for_text.js b/spec/frontend/helpers/wait_for_text.js deleted file mode 100644 index 6bed8a90a98..00000000000 --- a/spec/frontend/helpers/wait_for_text.js +++ /dev/null @@ -1,3 +0,0 @@ -import { findByText } from '@testing-library/dom'; - -export const waitForText = async (text, container = document) => findByText(container, text); diff --git a/spec/frontend/helpers/wait_using_real_timer.js b/spec/frontend/helpers/wait_using_real_timer.js deleted file mode 100644 index ddf23cd97b4..00000000000 --- a/spec/frontend/helpers/wait_using_real_timer.js +++ /dev/null @@ -1,7 +0,0 @@ -/* useful for timing promises when jest fakeTimers are not reliable enough */ -export default timeout => - new Promise(resolve => { - jest.useRealTimers(); - setTimeout(resolve, timeout); - jest.useFakeTimers(); - }); diff --git a/spec/frontend/helpers/web_worker_mock.js b/spec/frontend/helpers/web_worker_mock.js deleted file mode 100644 index 2b4a391e1d2..00000000000 --- a/spec/frontend/helpers/web_worker_mock.js +++ /dev/null @@ -1,10 +0,0 @@ -/* eslint-disable class-methods-use-this */ -export default class WebWorkerMock { - addEventListener() {} - - removeEventListener() {} - - terminate() {} - - postMessage() {} -} |