mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-07-24 09:58:43 -04:00
Add tests for handling overlap of activeElement
If an element receives focus when underneath a stick element, the window should scroll so the focused element is revealed. Includes some changes to the WindowMock API to allow access to data from Jest spies.
This commit is contained in:
@@ -6,6 +6,29 @@ function getScreenItemBottomPosition (screenItem) {
|
||||
return screenItem.offsetTop + screenItem.offsetHeight;
|
||||
};
|
||||
|
||||
function getStickyGroupPosition (screenMock, opts) {
|
||||
|
||||
const edgePosition = screenMock.window[opts.edge];
|
||||
const height = opts.stickyEls
|
||||
.map(el => el.offsetHeight)
|
||||
.reduce((accumulator, height) => accumulator + height);
|
||||
|
||||
if (opts.edge === 'top') {
|
||||
return {
|
||||
top: screenMock.window.top,
|
||||
bottom: edgePosition + height,
|
||||
height: height
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
top: edgePosition - height,
|
||||
bottom: screenMock.window.bottom,
|
||||
height: height
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
require('../../app/assets/javascripts/stick-to-window-when-scrolling.js');
|
||||
});
|
||||
@@ -227,6 +250,62 @@ describe("Stick to top/bottom of window when scrolling", () => {
|
||||
|
||||
});
|
||||
|
||||
describe("if element is made sticky and another element underneath it is focused", () => {
|
||||
|
||||
let checkbox;
|
||||
let checkboxBottom;
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
const inputFormBottom = getScreenItemBottomPosition(inputForm);
|
||||
|
||||
inputForm.insertAdjacentHTML('afterEnd', '<input type="checkbox" name="confirm" value="yes" />');
|
||||
checkbox = document.querySelector('input[type=checkbox]');
|
||||
|
||||
screenMock.mockPositionAndDimension('checkbox', checkbox, {
|
||||
offsetHeight: 50, // 118px smaller than the sticky
|
||||
offsetWidth: 727,
|
||||
offsetTop: inputFormBottom
|
||||
});
|
||||
|
||||
checkboxBottom = getScreenItemBottomPosition(checkbox);
|
||||
|
||||
// move the sticky over the checkbox. It's 168px high so this position will cause it to overlap.
|
||||
screenMock.scrollTo(checkbox.offsetTop - 10);
|
||||
|
||||
window.GOVUK.stickAtTopWhenScrolling.init();
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
screenMock.window.spies.window.scrollTo.mockClear();
|
||||
|
||||
});
|
||||
|
||||
test("the window should scroll so the focused element is revealed", () => {
|
||||
|
||||
// update inputForm position as DOM normally would
|
||||
inputForm.offsetTop = screenMock.window.top;
|
||||
|
||||
let stickyPosition = getStickyGroupPosition(screenMock, { stickyEls: [inputForm], edge: 'top' });
|
||||
|
||||
// sticky position should overlap checkbox position
|
||||
expect(stickyPosition.top).toBeLessThanOrEqual(checkbox.offsetTop);
|
||||
expect(stickyPosition.bottom).toBeGreaterThanOrEqual(checkboxBottom);
|
||||
|
||||
// the sticky element (page footer) is 50 high so should cover the last of the radios if the bottom edge of the viewport is at its bottom
|
||||
checkbox.focus();
|
||||
|
||||
stickyPosition = getStickyGroupPosition(screenMock, { stickyEls: [inputForm], edge: 'top' });
|
||||
|
||||
// the bottom of the sticky element should be at the top of the checkbox
|
||||
expect(screenMock.window.spies.window.scrollTo.mock.calls[0]).toEqual([0, checkbox.offsetTop - stickyPosition.height]);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("if mode is set to 'dialog' and multiple sticky elements share the same scroll area", () => {
|
||||
|
||||
let radios;
|
||||
@@ -664,6 +743,62 @@ describe("Stick to top/bottom of window when scrolling", () => {
|
||||
|
||||
});
|
||||
|
||||
describe("if element is made sticky and another element underneath it is focused", () => {
|
||||
|
||||
let checkbox;
|
||||
let checkboxBottom;
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
const contentBottom = getScreenItemBottomPosition(content);
|
||||
|
||||
content.insertAdjacentHTML('afterEnd', '<input type="checkbox" name="confirm" value="yes" />');
|
||||
checkbox = document.querySelector('input[type=checkbox]');
|
||||
|
||||
screenMock.mockPositionAndDimension('checkbox', checkbox, {
|
||||
offsetHeight: 40, // 10px smaller than the sticky
|
||||
offsetWidth: 727,
|
||||
offsetTop: contentBottom
|
||||
});
|
||||
|
||||
checkboxBottom = getScreenItemBottomPosition(checkbox);
|
||||
|
||||
// move the sticky over the checkbox. It's 50px high so this position will cause it to overlap.
|
||||
screenMock.scrollTo((checkboxBottom - windowHeight) + 5);
|
||||
|
||||
window.GOVUK.stickAtBottomWhenScrolling.init();
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
screenMock.window.spies.window.scrollTo.mockClear();
|
||||
|
||||
});
|
||||
|
||||
test("the window should scroll so the focused element is revealed", () => {
|
||||
|
||||
// update inputForm position as DOM normally would
|
||||
pageFooter.offsetTop = screenMock.window.bottom - pageFooter.offsetHeight;
|
||||
|
||||
let stickyPosition = getStickyGroupPosition(screenMock, { stickyEls: [pageFooter], edge: 'bottom' });
|
||||
|
||||
// sticky position should overlap checkbox position
|
||||
expect(stickyPosition.top).toBeLessThanOrEqual(checkbox.offsetTop);
|
||||
expect(stickyPosition.bottom).toBeGreaterThanOrEqual(checkboxBottom);
|
||||
|
||||
// the sticky element (page footer) is 50 high so should cover the last of the radios if the bottom edge of the viewport is at its bottom
|
||||
checkbox.focus();
|
||||
|
||||
stickyPosition = getStickyGroupPosition(screenMock, { stickyEls: [pageFooter], edge: 'bottom' });
|
||||
|
||||
// the top of the sticky element should be at the bottom of the checkbox
|
||||
expect(screenMock.window.spies.window.scrollTo.mock.calls[0]).toEqual([0, (checkboxBottom + pageFooter.offsetHeight) - windowHeight]);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("if mode is set to 'dialog' and multiple sticky elements have the same scroll area", () => {
|
||||
|
||||
let radios;
|
||||
|
||||
@@ -224,7 +224,8 @@ class WindowMock {
|
||||
width: window.innerWidth
|
||||
};
|
||||
this.spies = {
|
||||
document: {}
|
||||
document: {},
|
||||
window: {}
|
||||
};
|
||||
this._jest = jest;
|
||||
this._setSpies();
|
||||
@@ -266,7 +267,7 @@ class WindowMock {
|
||||
const self = this;
|
||||
|
||||
// JSDOM doesn't support .scrollTo
|
||||
window.scrollTo = function () {
|
||||
this.spies.window.scrollTo = this._jest.fn(function () {
|
||||
let y;
|
||||
|
||||
// data sent as props in an object
|
||||
@@ -278,7 +279,9 @@ class WindowMock {
|
||||
|
||||
self.scrollTo(y);
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
window.scrollTo = this.spies.window.scrollTo;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user