diff --git a/app/assets/javascripts/fileUpload.js b/app/assets/javascripts/fileUpload.js
index a246651e5..08218d0ca 100644
--- a/app/assets/javascripts/fileUpload.js
+++ b/app/assets/javascripts/fileUpload.js
@@ -11,20 +11,21 @@ function announceUploadStatusFromElement() {
srRegion.textContent = '';
setTimeout(() => {
srRegion.textContent = message;
- console.log(message);
}, 50);
}
}
-document.addEventListener('DOMContentLoaded', () => {
- announceUploadStatusFromElement();
-});
+// Exported for use in tests
+function initUploadStatusAnnouncer() {
+ document.addEventListener('DOMContentLoaded', () => {
+ announceUploadStatusFromElement();
+ });
+}
(function(Modules) {
"use strict";
Modules.FileUpload = function() {
-
this.submit = () => this.$form.trigger('submit');
this.showCancelButton = () => {
@@ -38,24 +39,25 @@ document.addEventListener('DOMContentLoaded', () => {
this.start = function(component) {
this.$form = $(component);
- // Handle "Upload your file" button click — CSP-safe version
this.$form.on('click', '[data-module="upload-trigger"]', function () {
const inputId = $(this).data('file-input-id');
const fileInput = document.getElementById(inputId);
if (fileInput) fileInput.click();
});
- // Clear the form if the user navigates back to the page
$(window).on("pageshow", () => this.$form[0].reset());
- // Watch for file input changes
this.$form.on('change', '.file-upload-field', () => {
this.submit();
this.showCancelButton();
});
-
};
-
};
-
})(window.GOVUK.Modules);
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = {
+ announceUploadStatusFromElement,
+ initUploadStatusAnnouncer
+ };
+}
diff --git a/tests/javascripts/fileUpload.domLoad.test.js b/tests/javascripts/fileUpload.domLoad.test.js
new file mode 100644
index 000000000..1fb641a8c
--- /dev/null
+++ b/tests/javascripts/fileUpload.domLoad.test.js
@@ -0,0 +1,26 @@
+// This will use the real function and listener
+const {
+ initUploadStatusAnnouncer
+} = require('../../app/assets/javascripts/fileUpload.js');
+
+jest.useFakeTimers();
+
+test('writes upload message to the live region on DOMContentLoaded', () => {
+ // Setup the DOM
+ document.body.innerHTML = `
+
Old message
+ File upload successful
+ `;
+
+ // Register the listener (same as page load does)
+ initUploadStatusAnnouncer();
+
+ // Simulate the page load event
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+
+ // Live region will be cleared first, then updated
+ jest.advanceTimersByTime(50);
+
+ const srRegion = document.getElementById('upload-status-live');
+ expect(srRegion.textContent).toBe('File upload successful');
+});
diff --git a/tests/javascripts/fileUpload.test.js b/tests/javascripts/fileUpload.test.js
index 29c8b711e..e45c45e7a 100644
--- a/tests/javascripts/fileUpload.test.js
+++ b/tests/javascripts/fileUpload.test.js
@@ -1,13 +1,12 @@
const helpers = require('./support/helpers.js');
-beforeAll(() => {
- require('../../app/assets/javascripts/fileUpload.js');
-});
+const { announceUploadStatusFromElement } = require('../../app/assets/javascripts/fileUpload.js');
afterAll(() => {
require('./support/teardown.js');
});
+
describe('File upload', () => {
let form;
@@ -82,3 +81,106 @@ describe('File upload', () => {
});
});
+
+describe('File upload "upload-trigger" click handler', () => {
+ let form;
+
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+ `;
+
+ form = document.querySelector('form');
+
+ // Register the module
+ window.GOVUK.modules.start();
+ });
+
+ afterEach(() => {
+ document.body.innerHTML = '';
+ });
+
+ test('clicking upload trigger simulates file input click', () => {
+ const uploadButton = form.querySelector('[data-module="upload-trigger"]');
+ const fileInput = document.getElementById('test-file-input');
+
+ // Spy on fileInput.click
+ const clickSpy = jest.spyOn(fileInput, 'click').mockImplementation(() => {});
+
+ // Trigger the click
+ helpers.triggerEvent(uploadButton, 'click');
+
+ expect(clickSpy).toHaveBeenCalled();
+
+ clickSpy.mockRestore();
+ });
+});
+
+describe('announceUploadStatusFromElement', () => {
+ beforeEach(() => {
+ jest.useFakeTimers();
+ document.body.innerHTML = `
+
+ `;
+ });
+
+ afterEach(() => {
+ jest.useRealTimers();
+ document.body.innerHTML = '';
+ });
+
+ test('announces error message from #upload-error', () => {
+ document.body.innerHTML += `
+ File upload failed
+ `;
+
+ const srRegion = document.getElementById('upload-status-live');
+
+ // Call the function
+ announceUploadStatusFromElement();
+
+ // Confirm it clears first
+ expect(srRegion.textContent).toBe('');
+
+ // Fast-forward the timer
+ jest.advanceTimersByTime(50);
+
+ // Confirm it updates after delay
+ expect(srRegion.textContent).toBe('File upload failed');
+ });
+
+ test('announces success message from #upload-success if no error is present', () => {
+ document.body.innerHTML += `
+ File upload successful
+ `;
+
+ const srRegion = document.getElementById('upload-status-live');
+
+ announceUploadStatusFromElement();
+
+ expect(srRegion.textContent).toBe('');
+
+ jest.advanceTimersByTime(50);
+
+ expect(srRegion.textContent).toBe('File upload successful');
+ });
+
+ test('does nothing if neither success nor error is present', () => {
+ const srRegion = document.getElementById('upload-status-live');
+
+ srRegion.textContent = 'Old message';
+
+ announceUploadStatusFromElement();
+
+ // Should not clear or update if no message element is found
+ expect(srRegion.textContent).toBe('Old message');
+
+ jest.advanceTimersByTime(50);
+
+ // Still unchanged
+ expect(srRegion.textContent).toBe('Old message');
+ });
+});