diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-15 03:10:45 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-15 03:10:45 +0300 |
commit | 8b75948934667904196aba319aedda25b00f06ff (patch) | |
tree | 5f743f14301b5abe868a35fad87bfa0fc0581f04 /spec/frontend/__helpers__/dom_shims | |
parent | 8f534e1e960eef1f4cfcb7c6d723840523515ffb (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/__helpers__/dom_shims')
15 files changed, 222 insertions, 0 deletions
diff --git a/spec/frontend/__helpers__/dom_shims/README.md b/spec/frontend/__helpers__/dom_shims/README.md new file mode 100644 index 00000000000..1105e4b0c4c --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/README.md @@ -0,0 +1,12 @@ +## 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 new file mode 100644 index 00000000000..94d060cab08 --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/create_object_url.js @@ -0,0 +1,3 @@ +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 new file mode 100644 index 00000000000..7d91279e4aa --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/element_scroll_by.js @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000000..a7262d04db0 --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/element_scroll_into_view.js @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000000..68f8a115865 --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/element_scroll_to.js @@ -0,0 +1,6 @@ +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 new file mode 100644 index 00000000000..46ef0374848 --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/form_element.js @@ -0,0 +1 @@ +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 new file mode 100644 index 00000000000..7ba60dd7936 --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/get_client_rects.js @@ -0,0 +1,52 @@ +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 new file mode 100644 index 00000000000..e7b8f1e235b --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/get_client_rects_spec.js @@ -0,0 +1,71 @@ +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 new file mode 100644 index 00000000000..d94c157e44d --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/image_element_properties.js @@ -0,0 +1,12 @@ +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 new file mode 100644 index 00000000000..9b70cb86b8b --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/index.js @@ -0,0 +1,12 @@ +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 new file mode 100644 index 00000000000..2b8201eed31 --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/inner_text.js @@ -0,0 +1,11 @@ +// 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 new file mode 100644 index 00000000000..4ffdf3280ad --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/range.js @@ -0,0 +1,13 @@ +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 new file mode 100644 index 00000000000..90387e51765 --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/scroll_by.js @@ -0,0 +1,7 @@ +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 new file mode 100644 index 00000000000..fbb919868b1 --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/size_properties.js @@ -0,0 +1,19 @@ +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 new file mode 100644 index 00000000000..20ae1910bf3 --- /dev/null +++ b/spec/frontend/__helpers__/dom_shims/window_scroll_to.js @@ -0,0 +1 @@ +window.scrollTo = jest.fn(); |