diff --git a/app/main/views/organizations.py b/app/main/views/organizations.py
index 6b769a91f..6e3496a7f 100644
--- a/app/main/views/organizations.py
+++ b/app/main/views/organizations.py
@@ -210,9 +210,7 @@ def _handle_delete_service(org_id, service_id):
cached_service_user_ids = [user.id for user in service.active_users]
service_api_client.archive_service(service_id, cached_service_user_ids)
- create_archive_service_event(
- service_id=service_id, archived_by_id=current_user.id
- )
+ create_archive_service_event(service_id=service_id, archived_by_id=current_user.id)
cache.redis_client.delete("organizations")
diff --git a/tests/app/main/views/test_jobs_activity.py b/tests/app/main/views/test_jobs_activity.py
index 09fcbbf31..8d14a1add 100644
--- a/tests/app/main/views/test_jobs_activity.py
+++ b/tests/app/main/views/test_jobs_activity.py
@@ -52,6 +52,9 @@ def test_all_activity(
"app.job_api_client.get_page_of_jobs", return_value=MOCK_JOBS
)
mocker.patch("app.job_api_client.get_immediate_jobs", return_value=[])
+ mock_s3_obj = mocker.Mock()
+ mock_s3_obj.content_length = 0
+ mocker.patch("app.s3_client.get_s3_object", return_value=mock_s3_obj)
mocker.patch("app.s3_client.check_s3_file_exists", return_value=False)
mocker.patch("app.s3_client.s3_csv_client.get_csv_upload", return_value=None)
@@ -140,6 +143,9 @@ def test_all_activity_no_jobs(client_request, mocker):
},
)
mocker.patch("app.job_api_client.get_immediate_jobs", return_value=[])
+ mock_s3_obj = mocker.Mock()
+ mock_s3_obj.content_length = 0
+ mocker.patch("app.s3_client.get_s3_object", return_value=mock_s3_obj)
mocker.patch("app.s3_client.check_s3_file_exists", return_value=False)
mocker.patch("app.s3_client.s3_csv_client.get_csv_upload", return_value=None)
response = client_request.get_response(
@@ -195,6 +201,9 @@ def test_all_activity_pagination(client_request, mocker):
},
)
mocker.patch("app.job_api_client.get_immediate_jobs", return_value=[])
+ mock_s3_obj = mocker.Mock()
+ mock_s3_obj.content_length = 0
+ mocker.patch("app.s3_client.get_s3_object", return_value=mock_s3_obj)
mocker.patch("app.s3_client.check_s3_file_exists", return_value=False)
mocker.patch("app.s3_client.s3_csv_client.get_csv_upload", return_value=None)
@@ -234,6 +243,9 @@ def test_all_activity_filters(client_request, mocker, filter_type, expected_limi
"app.job_api_client.get_page_of_jobs", return_value=MOCK_JOBS
)
mocker.patch("app.job_api_client.get_immediate_jobs", return_value=[])
+ mock_s3_obj = mocker.Mock()
+ mock_s3_obj.content_length = 0
+ mocker.patch("app.s3_client.get_s3_object", return_value=mock_s3_obj)
mocker.patch("app.s3_client.check_s3_file_exists", return_value=False)
mocker.patch("app.s3_client.s3_csv_client.get_csv_upload", return_value=None)
diff --git a/tests/javascripts/organizationDashboard.test.js b/tests/javascripts/organizationDashboard.test.js
new file mode 100644
index 000000000..70e0cd620
--- /dev/null
+++ b/tests/javascripts/organizationDashboard.test.js
@@ -0,0 +1,223 @@
+/**
+ * @jest-environment jsdom
+ */
+
+describe('organizationDashboard.js', () => {
+ let originalLocation;
+
+ beforeEach(() => {
+ jest.resetModules();
+ jest.useFakeTimers();
+
+ originalLocation = window.location;
+ Element.prototype.scrollIntoView = jest.fn();
+ window.requestAnimationFrame = jest.fn((cb) => setTimeout(cb, 0));
+ });
+
+ afterEach(() => {
+ jest.useRealTimers();
+ document.body.innerHTML = '';
+ });
+
+ describe('Delete Service Confirmation', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+
+
+
+ `;
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+ });
+
+ test('sets service name when delete button clicked', () => {
+ const deleteButton = document.querySelector('[data-service-id="service-123"]');
+ const nameDisplay = document.getElementById('delete-service-name-display');
+
+ deleteButton.click();
+
+ expect(nameDisplay.textContent).toBe('Test Service');
+ });
+
+ test('does not update name display if missing', () => {
+ document.getElementById('delete-service-name-display').remove();
+
+ const deleteButton = document.querySelector('[data-service-id="service-123"]');
+
+ expect(() => deleteButton.click()).not.toThrow();
+ });
+
+ test('does nothing if required elements missing', () => {
+ document.body.innerHTML = 'No delete elements
';
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+
+ expect(() => document.dispatchEvent(new Event('DOMContentLoaded'))).not.toThrow();
+ });
+ });
+
+ describe('Edit Service Confirmation', () => {
+ beforeEach(() => {
+ document.body.innerHTML = `
+
+
+ `;
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+ });
+
+ test('submits edit form when confirm button clicked', () => {
+ const confirmButton = document.getElementById('edit-service-confirm-btn');
+ const editForm = document.getElementById('edit-service-form');
+ editForm.submit = jest.fn();
+
+ confirmButton.click();
+
+ expect(editForm.submit).toHaveBeenCalled();
+ });
+
+ test('does not throw if form missing when confirm clicked', () => {
+ document.getElementById('edit-service-form').remove();
+ const confirmButton = document.getElementById('edit-service-confirm-btn');
+
+ expect(() => confirmButton.click()).not.toThrow();
+ });
+
+ test('does nothing if confirm button missing', () => {
+ document.body.innerHTML = '';
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+
+ expect(() => document.dispatchEvent(new Event('DOMContentLoaded'))).not.toThrow();
+ });
+ });
+
+ describe('Form Initialization', () => {
+ test('scrolls to and focuses create service form', () => {
+ document.body.innerHTML = `
+
+ `;
+
+ const form = document.getElementById('create-service-form');
+ const input = form.querySelector('input[type="text"]');
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+
+ jest.runAllTimers();
+
+ expect(form.scrollIntoView).toHaveBeenCalled();
+ expect(document.activeElement).toBe(input);
+ });
+
+ test('scrolls to and focuses invite user form', () => {
+ document.body.innerHTML = `
+
+ `;
+
+ const form = document.getElementById('invite-user-form');
+ const input = form.querySelector('input[type="email"]');
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+
+ jest.runAllTimers();
+
+ expect(form.scrollIntoView).toHaveBeenCalled();
+ expect(document.activeElement).toBe(input);
+ });
+
+ test('scrolls to and focuses edit service form', () => {
+ document.body.innerHTML = `
+
+ `;
+
+ const form = document.getElementById('edit-service-form');
+ const input = form.querySelector('input[type="text"]');
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+
+ jest.runAllTimers();
+
+ expect(form.scrollIntoView).toHaveBeenCalled();
+ expect(document.activeElement).toBe(input);
+ });
+
+ test('does nothing when no relevant forms present', () => {
+ document.body.innerHTML = 'No forms here
';
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+
+ jest.runAllTimers();
+
+ expect(Element.prototype.scrollIntoView).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('Service Highlighting', () => {
+ test('scrolls to and removes highlight from service', () => {
+ document.body.innerHTML = `
+
+ `;
+
+ const serviceRow = document.getElementById('service-test-123');
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+
+ window.OrganizationDashboard.highlightAndScrollToService('test-123');
+
+ jest.advanceTimersByTime(300);
+ expect(serviceRow.scrollIntoView).toHaveBeenCalled();
+
+ expect(serviceRow.classList.contains('is-highlighted')).toBe(true);
+
+ jest.advanceTimersByTime(3100);
+ expect(serviceRow.classList.contains('is-highlighted')).toBe(false);
+ });
+
+ test('removes class attribute when empty after highlight removal', () => {
+ document.body.innerHTML = `
+
+ `;
+
+ const serviceRow = document.getElementById('service-test-123');
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+
+ window.OrganizationDashboard.highlightAndScrollToService('test-123');
+
+ jest.advanceTimersByTime(3400);
+ expect(serviceRow.hasAttribute('class')).toBe(false);
+ });
+
+ test('handles missing service element gracefully', () => {
+ document.body.innerHTML = 'No service here
';
+
+ require('../../app/assets/javascripts/organizationDashboard.js');
+ document.dispatchEvent(new Event('DOMContentLoaded'));
+
+ expect(() => {
+ window.OrganizationDashboard.highlightAndScrollToService('nonexistent');
+ jest.runAllTimers();
+ }).not.toThrow();
+ });
+ });
+});