From 487866d81c026a164c17916cc8cf6d26db5aa39e Mon Sep 17 00:00:00 2001 From: Jonathan Bobel Date: Wed, 9 Apr 2025 14:52:56 -0400 Subject: [PATCH] Updating tests for the table --- app/assets/javascripts/fullscreenTable.js | 7 +- app/assets/sass/uswds/_legacy-styles.scss | 1 + .../uswds/_uswds-theme-custom-styles.scss | 1 - app/templates/views/check/column-errors.html | 11 +- app/templates/views/check/row-errors.html | 2 +- app/templates/views/send.html | 2 +- tests/javascripts/fullscreenTable.test.js | 412 +++--------------- 7 files changed, 78 insertions(+), 358 deletions(-) diff --git a/app/assets/javascripts/fullscreenTable.js b/app/assets/javascripts/fullscreenTable.js index 4fb36a726..15d9a8e2c 100644 --- a/app/assets/javascripts/fullscreenTable.js +++ b/app/assets/javascripts/fullscreenTable.js @@ -27,10 +27,15 @@ }); } - // Run once DOM is ready + // Auto-init on page load in browser if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initFullscreenTables); } else { initFullscreenTables(); } + + // Expose it globally in test environments + if (typeof window !== 'undefined') { + window.initFullscreenTables = initFullscreenTables; + } })(); diff --git a/app/assets/sass/uswds/_legacy-styles.scss b/app/assets/sass/uswds/_legacy-styles.scss index d291d644f..57bf45d92 100644 --- a/app/assets/sass/uswds/_legacy-styles.scss +++ b/app/assets/sass/uswds/_legacy-styles.scss @@ -216,6 +216,7 @@ h2.recipient-list { z-index: 10; background: white; text-align: center; + width: units(2); &::before { content: ""; diff --git a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss index ef50b9394..d58f185b2 100644 --- a/app/assets/sass/uswds/_uswds-theme-custom-styles.scss +++ b/app/assets/sass/uswds/_uswds-theme-custom-styles.scss @@ -722,7 +722,6 @@ details form { .placeholder, .placeholder-conditional { background-color: #face00; - border: 1px solid #face00; border-radius: 7px; } diff --git a/app/templates/views/check/column-errors.html b/app/templates/views/check/column-errors.html index bcb518892..4192cc259 100644 --- a/app/templates/views/check/column-errors.html +++ b/app/templates/views/check/column-errors.html @@ -1,7 +1,7 @@ {% extends "withnav_template.html" %} {% from "components/banner.html" import banner_wrapper %} {% from "components/radios.html" import radio_select %} -{% from "components/table.html" import list_table, field, text_field, index_field, hidden_field_heading %} +{% from "components/table.html" import list_table, field, text_field, index_field, index_field_heading %} {% from "components/file-upload.html" import file_upload %} {% from "components/components/back-link/macro.njk" import usaBackLink %} @@ -161,18 +161,15 @@ recipients.column_headers %}

{{ original_file_name }}

-
+
{% call(item, row_number) list_table( recipients.displayed_rows, caption=original_file_name, caption_visible=False, - field_headings=[ - 'Row in file'|safe - ] + column_headers - ) %} + field_headings=[''] + column_headers )%} {% call index_field() %} - {% set displayed_index = item.index + 2 %} + {% set displayed_index = item.index + 1 %} {{ displayed_index }} {% endcall %} diff --git a/app/templates/views/check/row-errors.html b/app/templates/views/check/row-errors.html index 9d9a2edc1..738c3385c 100644 --- a/app/templates/views/check/row-errors.html +++ b/app/templates/views/check/row-errors.html @@ -55,7 +55,7 @@
-
+
{% call(item, row_number) mapping_table( caption="Errors in " + original_file_name, caption_visible=False, diff --git a/app/templates/views/send.html b/app/templates/views/send.html index 96a3decd6..c820c01ab 100644 --- a/app/templates/views/send.html +++ b/app/templates/views/send.html @@ -31,7 +31,7 @@ import { FullscreenTable } from './fullscreenTable.js';

Your file needs to look like this example

-
+
{% call(item, row_number) list_table( example, caption="Example", diff --git a/tests/javascripts/fullscreenTable.test.js b/tests/javascripts/fullscreenTable.test.js index c8d89d962..45b76d4ee 100644 --- a/tests/javascripts/fullscreenTable.test.js +++ b/tests/javascripts/fullscreenTable.test.js @@ -1,370 +1,88 @@ -const helpers = require('./support/helpers'); +require('../../app/assets/javascripts/fullscreenTable.js'); -beforeAll(() => { - // TODO: remove this when tests for sticky JS are written - require('../../app/assets/javascripts/stick-to-window-when-scrolling.js'); +describe('fullscreenTable', () => { + let wrapper, rightShadow; - require('../../app/assets/javascripts/fullscreenTable.js'); -}); - -afterAll(() => { - require('./support/teardown.js'); -}); - -describe('FullscreenTable', () => { - let screenMock; - let container; - let tableFrame; - let table; - let numberColumnFrame; - - beforeEach(() => { - - const tableHeadings = () => { - let result = ''; - const headings = ['1', 'name', 'email address', 'age', 'building number', 'address line 1', 'address line 2', 'postcode']; - - headings.forEach((heading, idx) => { - if (idx === 0) { - result += ` - Row in file - `; - } else { - result += ` - ${heading} - `; - } - }); - - return result; - } - - const rowCells = (cells) => { - let result = ''; - - Object.keys(cells).forEach((key, idx) => { - if (idx === 0) { - result += ` - - ${key} - - `; - } else { - result += ` -
- ${key} -
- `; - } - }); - - return result; - }; - - const tableRows = () => { - let result = ''; - - const rows = [ - ['John Logie Baird', 'johnlbaird@gmail.com', '37', '22', 'Frith Street', 'Soho, London', 'W1D 4RF'], - ['Guglielmo Marconi', 'gmarconi@hotmail.com', '21', 'Pontecchio Marconi', 'Via Celestini 1', 'Bologna', ''], - ['Louis Braille', 'louisbraille@yahoo.co.uk', '', '56', 'Boulevard des Invalides', 'Paris', '75007'], - ['Ray Tomlinson', 'hedy.lamarr@msn.com', '25', '870', '870 Winter Street', 'Waltham', 'MA 02451'] - ]; - - rows.forEach(row => { - result += `${rowCells(row)}`; - }); - - return result; - - } - - screenMock = new helpers.ScreenMock(jest); - screenMock.setWindow({ - width: 1990, - height: 940, - scrollTop: 0 - }); - - // set up DOM - document.body.innerHTML = - `
-
- - - - - ${tableHeadings()} - - - - ${tableRows()} - + const setupDOM = (scrollLeft = 0, scrollWidth = 1000, clientWidth = 500) => { + document.body.innerHTML = ` +
+
+
- people.csv -
+
Test
-
`; +
+
+ `; - container = document.querySelector('.fullscreen-content'); + wrapper = document.querySelector('.table-wrapper'); + rightShadow = document.querySelector('.fullscreen-right-shadow'); - }); + // Mock scroll values + Object.defineProperty(wrapper, 'scrollLeft', { + get: () => scrollLeft, + configurable: true + }); + Object.defineProperty(wrapper, 'scrollWidth', { + get: () => scrollWidth, + configurable: true + }); + Object.defineProperty(wrapper, 'clientWidth', { + get: () => clientWidth, + configurable: true + }); + + // 👇 Now that DOM is ready, initialize the logic + window.initFullscreenTables(); + + // Force trigger scroll event if needed + wrapper.dispatchEvent(new Event('scroll')); + }; afterEach(() => { - document.body.innerHTML = ''; - }); - describe("when it loads", () => { - - test("it fixes the number column for each row without changing the semantics", () => { - - // start module - window.GOVUK.modules.start(); - - tableFrame = document.querySelector('.fullscreen-scrollable-table'); - numberColumnFrame = document.querySelector('.fullscreen-fixed-table'); - - expect(tableFrame).not.toBeNull(); - expect(numberColumnFrame).not.toBeNull(); - expect(numberColumnFrame.getAttribute('aria-hidden')).toEqual('true'); - - }); - - test("it calls the sticky JS to update any cached dimensions", () => { - - const stickyJSSpy = jest.spyOn(window.GOVUK.stickAtBottomWhenScrolling, 'recalculate'); - - // start module - window.GOVUK.modules.start(); - - expect(stickyJSSpy.mock.calls.length).toBe(1); - - stickyJSSpy.mockClear(); - - }); - - test("the scrolling section is focusable and has an accessible name matching the table caption", () => { - - // start module - window.GOVUK.modules.start(); - - tableFrame = document.querySelector('.fullscreen-scrollable-table'); - caption = tableFrame.querySelector('caption'); - - expect(tableFrame.hasAttribute('role')).toBe(true); - expect(tableFrame.getAttribute('role')).toEqual('region'); - expect(tableFrame.hasAttribute('aria-labelledby')).toBe(true); - expect(tableFrame.getAttribute('aria-labelledby')).toEqual(caption.getAttribute('id')); - - }); - - test("the section providing the fixed row headers is not focusable and is hidden from assistive tech'", () => { - - // start module - window.GOVUK.modules.start(); - - fixedRowHeaders = document.querySelector('.fullscreen-fixed-table'); - - expect(fixedRowHeaders.hasAttribute('role')).toBe(false); - expect(fixedRowHeaders.hasAttribute('aria-labelledby')).toBe(false); - expect(fixedRowHeaders.hasAttribute('tabindex')).toBe(false); - expect(fixedRowHeaders.hasAttribute('aria-hidden')).toBe(true); - expect(fixedRowHeaders.getAttribute('aria-hidden')).toEqual('true'); - - }); - + test('adds right shadow on initial load if scrollable', () => { + setupDOM(0, 1000, 500); + expect(wrapper.classList.contains('scrolled')).toBe(false); + expect(rightShadow.classList.contains('visible')).toBe(true); }); - describe("the height of the table should fit the vertical space available to it", () => { - - let containerBoundingClientRectSpy; - let containerClientRectsSpy; - - beforeEach(() => { - - // set the height and offset of the window and table container from the top of the document - // so just the top 268px of it appears on-screen - screenMock.window.setHeightTo(768); - screenMock.mockPositionAndDimension('container', container, { - 'offsetHeight': 1000, - 'offsetWidth': 641, - 'offsetTop': 500 - }); - - // start module - window.GOVUK.modules.start(); - - tableFrame = document.querySelector('.fullscreen-scrollable-table'); - numberColumnFrame = document.querySelector('.fullscreen-fixed-table'); - - }); - - afterEach(() => { - - screenMock.reset(); - - }); - - test("when the page has loaded", () => { - - // the frames should crop to the top 268px of the table that is visible - expect(window.getComputedStyle(tableFrame)['height']).toEqual('268px'); - expect(window.getComputedStyle(numberColumnFrame)['height']).toEqual('268px'); - - }); - - test("when the page has scrolled", () => { - - // scroll the window so the table fills the height of the window (768px) - screenMock.window.scrollTo(500); - - // the frames should crop to the window height - expect(window.getComputedStyle(tableFrame)['height']).toEqual('768px'); - expect(window.getComputedStyle(numberColumnFrame)['height']).toEqual('768px'); - - }); - - test("when the page has resized", () => { - - // resize the window by 232px (from 768px to 1000px) - screenMock.window.resizeTo({ height: 1000, width: 1024 }); - - // the frames should crop to the top 500px of the table now visible - expect(window.getComputedStyle(tableFrame)['height']).toEqual('500px'); - expect(window.getComputedStyle(numberColumnFrame)['height']).toEqual('500px'); - - }); - + test('hides right shadow when scrolled to max', () => { + setupDOM(500, 1000, 500); + expect(wrapper.classList.contains('scrolled')).toBe(true); + expect(rightShadow.classList.contains('visible')).toBe(false); }); - describe("the width of the table should fit the horizontal space available to it", () => { - let rowNumberColumnCell; - - beforeEach(() => { - - rowNumberColumnCell = container.querySelector('.table-field-index'); - - // set main content column width (used as module as gauge for table width) - screenMock.window.setWidthTo(1024); - document.querySelector('main').setAttribute('style', 'width: 742px'); - - // set total width of column for row numbers in table to 40px - rowNumberColumnCell.setAttribute('style', 'width: 40px'); - - // start module - window.GOVUK.modules.start(); - - tableFrame = document.querySelector('.fullscreen-scrollable-table'); - numberColumnFrame = document.querySelector('.fullscreen-fixed-table'); - - }); - - afterEach(() => { - - screenMock.reset(); - - }); - - test("when the page has loaded", () => { - - // table should set its width to be that of `
`, minus margin-left for the row numbers column - expect(window.getComputedStyle(tableFrame)['width']).toEqual('702px'); // width of content column - numbers column - expect(window.getComputedStyle(tableFrame)['margin-left']).toEqual('40px'); // width of numbers column - - // table for number column has 4px extra to allow space for drop shadow - expect(window.getComputedStyle(numberColumnFrame)['width']).toEqual('44px'); - - }); - - test("when the page has resized", () => { - - // resize window and content column - document.querySelector('main').setAttribute('style', 'width: 720px'); - screenMock.window.resizeTo({ height: 768, width: 960 }); - - // table should set its width to be that of `
`, minus margin-left for the row numbers column - expect(window.getComputedStyle(tableFrame)['width']).toEqual('680px'); // width of content column - numbers column - expect(window.getComputedStyle(tableFrame)['margin-left']).toEqual('40px'); // width of numbers column - - // table for number column has 4px extra to allow space for drop shadow - expect(window.getComputedStyle(numberColumnFrame)['width']).toEqual('44px'); - - }); - + test('handles mid-scroll: left + right shadows active', () => { + setupDOM(250, 1000, 500); + expect(wrapper.classList.contains('scrolled')).toBe(true); + expect(rightShadow.classList.contains('visible')).toBe(true); }); - describe("when the table scrolls horizontally", () => { - let rightEdgeShadow; + test('gracefully handles missing right shadow', () => { + document.body.innerHTML = ` +
+
+ + +
Only content
+
+
+ `; - beforeEach(() => { + wrapper = document.querySelector('.table-wrapper'); - // start module - window.GOVUK.modules.start(); + Object.defineProperty(wrapper, 'scrollLeft', { get: () => 100, configurable: true }); + Object.defineProperty(wrapper, 'scrollWidth', { get: () => 500, configurable: true }); + Object.defineProperty(wrapper, 'clientWidth', { get: () => 200, configurable: true }); - tableFrame = document.querySelector('.fullscreen-scrollable-table'); - table = tableFrame.querySelector('table'); - numberColumnFrame = document.querySelector('.fullscreen-fixed-table'); - rightEdgeShadow = container.querySelector('.fullscreen-right-shadow'); - - tableFrame.setAttribute('style', 'width: 742px'); - table.setAttribute('style', 'width: 1000px'); - - }); - - test("the right edge of the table scroll area should have a drop-shadow if it isn't scrolled", () => { - - tableFrame.scrollLeft = 0; - helpers.triggerEvent(tableFrame, 'scroll'); - - expect(numberColumnFrame.classList.contains('fullscreen-scrolled-table')).toBe(false); - expect(rightEdgeShadow.classList.contains('visible')).toBe(true); - - }); - - test("the left edge of the table scroll area should have a drop-shadow if the table is scrolled to 100%", () => { - - // scroll to end of table - tableFrame.scrollLeft = 258; - helpers.triggerEvent(tableFrame, 'scroll'); - - expect(numberColumnFrame.classList.contains('fullscreen-scrolled-table')).toBe(true); - expect(rightEdgeShadow.classList.contains('visible')).toBe(false); - - }); - - test("both edges of the table scroll area should have a drop-shadow if the table is scrolled between 0% and 100%", () => { - - // scroll to middle of table - tableFrame.scrollLeft = 129; - helpers.triggerEvent(tableFrame, 'scroll'); - - expect(numberColumnFrame.classList.contains('fullscreen-scrolled-table')).toBe(true); - expect(rightEdgeShadow.classList.contains('visible')).toBe(true); - - }); + // 👇 Call after building DOM + window.initFullscreenTables(); + wrapper.dispatchEvent(new Event('scroll')); + expect(wrapper.classList.contains('scrolled')).toBe(true); + // No error thrown for missing .fullscreen-right-shadow }); - - describe("when the table is focused", () => { - - beforeEach(() => { - - // start module - window.GOVUK.modules.start(); - - tableFrame = document.querySelector('.fullscreen-scrollable-table'); - tableFrame.focus(); - - }); - - test("it should make the parent frame a focus style", () => { - - expect(container.classList.contains('js-focus-style')).toBe(true); - - }); - - }); - });