From 46e1dc2a47097797e01108166506ccc747a715c1 Mon Sep 17 00:00:00 2001 From: Linda Goldstein Date: Wed, 12 Nov 2025 12:54:45 -0800 Subject: [PATCH 1/2] wip claude js tests --- app/javascript/__tests__/case_contact.test.js | 44 +++- .../__tests__/case_emancipations.test.js | 2 +- app/javascript/__tests__/notifier.test.js | 186 +++++-------- app/javascript/__tests__/read_more.test.js | 110 ++++++++ app/javascript/__tests__/time_zone.test.js | 37 +++ ...two_minute_warning_session_timeout.test.js | 10 - app/javascript/__tests__/type_checker.test.js | 246 ++++++++++++++++++ .../__tests__/validated_form.test.js | 68 ++--- 8 files changed, 532 insertions(+), 171 deletions(-) create mode 100644 app/javascript/__tests__/read_more.test.js create mode 100644 app/javascript/__tests__/time_zone.test.js create mode 100644 app/javascript/__tests__/type_checker.test.js diff --git a/app/javascript/__tests__/case_contact.test.js b/app/javascript/__tests__/case_contact.test.js index ba10a0fb3e..0183881988 100644 --- a/app/javascript/__tests__/case_contact.test.js +++ b/app/javascript/__tests__/case_contact.test.js @@ -5,6 +5,46 @@ import { convertDateToSystemTimeZone } from '../src/case_contact' -test('utc date is correctly converted to system date', () => { - expect(convertDateToSystemTimeZone('2022-06-22 17:14:50 UTC')).toEqual(new Date('2022-06-22 17:14:50 UTC')) +describe('convertDateToSystemTimeZone', () => { + test('converts a UTC date string to a Date object', () => { + const dateString = '2022-06-22 17:14:50 UTC' + const result = convertDateToSystemTimeZone(dateString) + + expect(result).toBeInstanceOf(Date) + expect(result.getTime()).toBe(new Date(dateString).getTime()) + }) + + test('converts a date string without timezone to a Date object', () => { + const dateString = '2022-06-22T12:00:00' + const result = convertDateToSystemTimeZone(dateString) + + expect(result).toBeInstanceOf(Date) + expect(result.getFullYear()).toBe(2022) + expect(result.getMonth()).toBe(5) // June is month 5 (0-indexed) + expect(result.getDate()).toBe(22) + }) + + test('creates a copy of an existing Date object', () => { + const originalDate = new Date('2022-06-22 17:14:50 UTC') + const result = convertDateToSystemTimeZone(originalDate) + + expect(result).toBeInstanceOf(Date) + expect(result.getTime()).toBe(originalDate.getTime()) + expect(result).not.toBe(originalDate) // Should be a different object + }) + + test('handles ISO 8601 format', () => { + const dateString = '2022-06-22T17:14:50.000Z' + const result = convertDateToSystemTimeZone(dateString) + + expect(result).toBeInstanceOf(Date) + expect(result.toISOString()).toBe(dateString) + }) + + test('returns Invalid Date for invalid date strings', () => { + const result = convertDateToSystemTimeZone('not a valid date') + + expect(result).toBeInstanceOf(Date) + expect(isNaN(result.getTime())).toBe(true) + }) }) diff --git a/app/javascript/__tests__/case_emancipations.test.js b/app/javascript/__tests__/case_emancipations.test.js index 2cc2f9619f..9c5b9d9d9f 100644 --- a/app/javascript/__tests__/case_emancipations.test.js +++ b/app/javascript/__tests__/case_emancipations.test.js @@ -59,7 +59,7 @@ beforeEach(() => { }) describe('Function that changes the text of the Toggler based on the state of the parent', () => { - test('Changes the toggler text to -', () => { + test('Changes the toggler text to + when category is closed', () => { category.attr('data-is-open', 'false') toggler.manageTogglerText() diff --git a/app/javascript/__tests__/notifier.test.js b/app/javascript/__tests__/notifier.test.js index f4b2e96285..2a373ab28f 100644 --- a/app/javascript/__tests__/notifier.test.js +++ b/app/javascript/__tests__/notifier.test.js @@ -29,162 +29,120 @@ beforeEach(() => { ` - $(() => { // JQuery's callback for the DOM loading - notificationsElement = $('#notifications') - notifier = new Notifier(notificationsElement) - }) + notificationsElement = $('#notifications') + notifier = new Notifier(notificationsElement) }) describe('Notifier', () => { describe('clicking the minify button', () => { let minimizeButton - beforeEach(() => { // Create a notification so the minify button displays - $(() => { - notifier.notify('a notification', 'info') - minimizeButton = notificationsElement.find('#toggle-minimize-notifications') - }) + beforeEach(() => { + notifier.notify('a notification', 'info') + minimizeButton = notificationsElement.find('#toggle-minimize-notifications') }) - test('should toggle the notifier between the minified and expanded state', (done) => { - $(() => { - try { - const messageNotificationsContainer = notificationsElement.find('.messages') - const minimizeButtonIcon = minimizeButton.children('i') - const minimizeButtonText = minimizeButton.children('span').first() + test('should toggle the notifier between the minified and expanded state', () => { + const messageNotificationsContainer = notificationsElement.find('.messages') + const minimizeButtonIcon = minimizeButton.children('i') + const minimizeButtonText = minimizeButton.children('span').first() - expect(minimizeButton.css('display')).not.toBe('none') - expect(messageNotificationsContainer.css('display')).not.toBe('none') - expect(minimizeButtonIcon.hasClass('fa-minus')).toBeTruthy() - expect(minimizeButtonIcon.hasClass('fa-plus')).not.toBeTruthy() - expect(minimizeButtonText.css('display')).not.toBe('none') + expect(minimizeButton.css('display')).not.toBe('none') + expect(messageNotificationsContainer.css('display')).not.toBe('none') + expect(minimizeButtonIcon.hasClass('fa-minus')).toBe(true) + expect(minimizeButtonIcon.hasClass('fa-plus')).toBe(false) + expect(minimizeButtonText.css('display')).not.toBe('none') - minimizeButton.click() + minimizeButton.click() - expect(messageNotificationsContainer.css('display')).toBe('none') - expect(minimizeButtonIcon.hasClass('fa-minus')).not.toBeTruthy() - expect(minimizeButtonIcon.hasClass('fa-plus')).toBeTruthy() - expect(minimizeButtonText.css('display')).toBe('none') + expect(messageNotificationsContainer.css('display')).toBe('none') + expect(minimizeButtonIcon.hasClass('fa-minus')).toBe(false) + expect(minimizeButtonIcon.hasClass('fa-plus')).toBe(true) + expect(minimizeButtonText.css('display')).toBe('none') - minimizeButton.click() - - expect(messageNotificationsContainer.css('display')).not.toBe('none') - expect(minimizeButtonIcon.hasClass('fa-minus')).toBeTruthy() - expect(minimizeButtonIcon.hasClass('fa-plus')).not.toBeTruthy() - expect(minimizeButtonText.css('display')).not.toBe('none') + minimizeButton.click() - done() - } catch (error) { - done(error) - } - }) + expect(messageNotificationsContainer.css('display')).not.toBe('none') + expect(minimizeButtonIcon.hasClass('fa-minus')).toBe(true) + expect(minimizeButtonIcon.hasClass('fa-plus')).toBe(false) + expect(minimizeButtonText.css('display')).not.toBe('none') }) - test('should show only badges where there exists at least one notification matching the badge level when minimized', (done) => { - $(() => { - try { - const minimizeButtonBadgeError = minimizeButton.children('.bg-danger') - const minimizeButtonBadgeInfo = minimizeButton.children('.bg-success') - const minimizeButtonBadgeWarning = minimizeButton.children('.bg-warning') + test('should show only badges where there exists at least one notification matching the badge level when minimized', () => { + const minimizeButtonBadgeError = minimizeButton.children('.bg-danger') + const minimizeButtonBadgeInfo = minimizeButton.children('.bg-success') + const minimizeButtonBadgeWarning = minimizeButton.children('.bg-warning') - expect(minimizeButton.css('display')).not.toBe('none') + expect(minimizeButton.css('display')).not.toBe('none') - minimizeButton.click() + minimizeButton.click() - expect(minimizeButtonBadgeInfo.css('display')).not.toContain('none') - expect(minimizeButtonBadgeInfo.text()).toBe('1') - expect(minimizeButtonBadgeError.css('display')).toContain('none') - expect(minimizeButtonBadgeWarning.css('display')).toContain('none') + expect(minimizeButtonBadgeInfo.css('display')).not.toContain('none') + expect(minimizeButtonBadgeInfo.text()).toBe('1') + expect(minimizeButtonBadgeError.css('display')).toContain('none') + expect(minimizeButtonBadgeWarning.css('display')).toContain('none') - minimizeButton.click() - const notification2 = notifier.notify('msg', 'error') - notifier.notify('msg', 'warn') + minimizeButton.click() + const notification2 = notifier.notify('msg', 'error') + notifier.notify('msg', 'warn') - minimizeButton.click() - expect(minimizeButtonBadgeInfo.css('display')).not.toContain('none') - expect(minimizeButtonBadgeInfo.text()).toBe('1') - expect(minimizeButtonBadgeError.css('display')).not.toContain('none') - expect(minimizeButtonBadgeError.text()).toBe('1') - expect(minimizeButtonBadgeWarning.css('display')).not.toContain('none') - expect(minimizeButtonBadgeWarning.text()).toBe('1') + minimizeButton.click() + expect(minimizeButtonBadgeInfo.css('display')).not.toContain('none') + expect(minimizeButtonBadgeInfo.text()).toBe('1') + expect(minimizeButtonBadgeError.css('display')).not.toContain('none') + expect(minimizeButtonBadgeError.text()).toBe('1') + expect(minimizeButtonBadgeWarning.css('display')).not.toContain('none') + expect(minimizeButtonBadgeWarning.text()).toBe('1') - minimizeButton.click() - notification2.dismiss() + minimizeButton.click() + notification2.dismiss() - minimizeButton.click() - expect(minimizeButtonBadgeInfo.css('display')).not.toContain('none') - expect(minimizeButtonBadgeInfo.text()).toBe('1') - expect(minimizeButtonBadgeError.css('display')).toContain('none') - expect(minimizeButtonBadgeWarning.css('display')).not.toContain('none') - expect(minimizeButtonBadgeWarning.text()).toBe('1') - - done() - } catch (error) { - done(error) - } - }) + minimizeButton.click() + expect(minimizeButtonBadgeInfo.css('display')).not.toContain('none') + expect(minimizeButtonBadgeInfo.text()).toBe('1') + expect(minimizeButtonBadgeError.css('display')).toContain('none') + expect(minimizeButtonBadgeWarning.css('display')).not.toContain('none') + expect(minimizeButtonBadgeWarning.text()).toBe('1') }) }) describe('notify', () => { - test("displays a green notification when passed a message and level='info'", (done) => { + test("displays a green notification when passed a message and level='info'", () => { const notificationMessage = "'Y$deH[|%ROii]jy" - $(() => { - try { - // Clear any existing notifications from previous tests - notificationsElement.find('.messages').empty() + // Clear any existing notifications from previous tests + notificationsElement.find('.messages').empty() - notifier.notify(notificationMessage, 'info') + notifier.notify(notificationMessage, 'info') - const successMessages = notificationsElement.children('.messages').find('.success-notification') + const successMessages = notificationsElement.children('.messages').find('.success-notification') - expect(successMessages.length).toBe(1) - expect(successMessages[0].innerHTML).toContain(notificationMessage) - done() - } catch (error) { - done(error) - } - }) + expect(successMessages.length).toBe(1) + expect(successMessages[0].innerHTML).toContain(notificationMessage) }) - test("displays a red notification when passed a message and level='error'", (done) => { + test("displays a red notification when passed a message and level='error'", () => { const notificationMessage = '\\+!h0bbH"yN7dx9.' - $(() => { - try { - notifier.notify(notificationMessage, 'error') + notifier.notify(notificationMessage, 'error') - const failureMessages = notificationsElement.find('.danger-notification') + const failureMessages = notificationsElement.find('.danger-notification') - expect(failureMessages.length).toBe(1) - expect(failureMessages[0].innerHTML).toContain(notificationMessage) - done() - } catch (error) { - done(error) - } - }) + expect(failureMessages.length).toBe(1) + expect(failureMessages[0].innerHTML).toContain(notificationMessage) }) - test('displays the minimize button after no notifications were present before', (done) => { - $(() => { - try { - const messageNotificationsContainer = notificationsElement.find('.messages') - const minimizeButton = notificationsElement.find('#toggle-minimize-notifications') + test('displays the minimize button after no notifications were present before', () => { + const messageNotificationsContainer = notificationsElement.find('.messages') + const minimizeButton = notificationsElement.find('#toggle-minimize-notifications') - expect(minimizeButton.css('display')).toBe('none') - expect(messageNotificationsContainer.children().length).toBe(0) + expect(minimizeButton.css('display')).toBe('none') + expect(messageNotificationsContainer.children().length).toBe(0) - notifier.notify('msg', 'info') + notifier.notify('msg', 'info') - expect(minimizeButton.css('display')).not.toBe('none') - expect(messageNotificationsContainer.children().length).toBeGreaterThan(0) - - done() - } catch (error) { - done(error) - } - }) + expect(minimizeButton.css('display')).not.toBe('none') + expect(messageNotificationsContainer.children().length).toBeGreaterThan(0) }) describe('when the notifier is minimized', () => { diff --git a/app/javascript/__tests__/read_more.test.js b/app/javascript/__tests__/read_more.test.js new file mode 100644 index 0000000000..a171003046 --- /dev/null +++ b/app/javascript/__tests__/read_more.test.js @@ -0,0 +1,110 @@ +/* eslint-env jest */ +/** + * @jest-environment jsdom + */ + +describe('read_more', () => { + beforeEach(() => { + document.body.innerHTML = ` +
+
+ Short text... +
+ + + +
+ ` + + // Require the module after setting up the DOM + jest.isolateModules(() => { + require('../src/read_more') + }) + + // Trigger DOMContentLoaded + const event = new Event('DOMContentLoaded') + document.dispatchEvent(event) + }) + + test('shows full text and hides truncated text when Read More is clicked', () => { + const readMoreButton = document.querySelector('.js-read-more') + const truncatedText = document.querySelector('.js-truncated-text') + const fullText = document.querySelector('.js-full-text') + + expect(truncatedText.style.display).toBe('block') + expect(fullText.style.display).toBe('none') + + readMoreButton.click() + + expect(truncatedText.style.display).toBe('none') + expect(fullText.style.display).toBe('block') + }) + + test('shows truncated text and hides full text when Read Less is clicked', () => { + const readMoreButton = document.querySelector('.js-read-more') + const readLessButton = document.querySelector('.js-read-less') + const truncatedText = document.querySelector('.js-truncated-text') + const fullText = document.querySelector('.js-full-text') + + // First expand + readMoreButton.click() + expect(fullText.style.display).toBe('block') + + // Then collapse + readLessButton.click() + expect(truncatedText.style.display).toBe('block') + expect(fullText.style.display).toBe('none') + }) + + test('prevents default event behavior on Read More click', () => { + const readMoreButton = document.querySelector('.js-read-more') + const event = new MouseEvent('click', { bubbles: true, cancelable: true }) + const preventDefaultSpy = jest.spyOn(event, 'preventDefault') + + readMoreButton.dispatchEvent(event) + + expect(preventDefaultSpy).toHaveBeenCalled() + }) + + test('prevents default event behavior on Read Less click', () => { + const readLessButton = document.querySelector('.js-read-less') + const event = new MouseEvent('click', { bubbles: true, cancelable: true }) + const preventDefaultSpy = jest.spyOn(event, 'preventDefault') + + readLessButton.dispatchEvent(event) + + expect(preventDefaultSpy).toHaveBeenCalled() + }) + + test('handles multiple read more/less wrappers independently', () => { + document.body.innerHTML = ` +
+
Short 1
+ + +
+
+
Short 2
+ + +
+ ` + + jest.isolateModules(() => { + require('../src/read_more') + }) + document.dispatchEvent(new Event('DOMContentLoaded')) + + const wrapper1ReadMore = document.querySelector('#wrapper1 .js-read-more') + const wrapper1Full = document.querySelector('#wrapper1 .js-full-text') + const wrapper2Full = document.querySelector('#wrapper2 .js-full-text') + + wrapper1ReadMore.click() + + // Only wrapper1 should be expanded + expect(wrapper1Full.style.display).toBe('block') + expect(wrapper2Full.style.display).toBe('none') + }) +}) diff --git a/app/javascript/__tests__/time_zone.test.js b/app/javascript/__tests__/time_zone.test.js new file mode 100644 index 0000000000..6fca7ebbb2 --- /dev/null +++ b/app/javascript/__tests__/time_zone.test.js @@ -0,0 +1,37 @@ +/* eslint-env jest */ +/** + * @jest-environment jsdom + */ + +import { findTimeZone } from '../src/time_zone' + +describe('findTimeZone', () => { + test('returns a string timezone name', () => { + const timezone = findTimeZone() + + expect(typeof timezone).toBe('string') + expect(timezone.length).toBeGreaterThan(0) + }) + + test('returns a valid timezone string format', () => { + const timezone = findTimeZone() + + // Timezone should be in format like "America/New_York" or "Europe/London" + // Common formats: Continent/City or UTC + expect(timezone).toMatch(/^[A-Za-z_]+\/[A-Za-z_]+$|^UTC$|^[A-Z]{3,4}$/) + }) + + test('returns consistent result when called multiple times', () => { + const timezone1 = findTimeZone() + const timezone2 = findTimeZone() + + expect(timezone1).toBe(timezone2) + }) + + test('handles environments where Intl is available', () => { + // This test just verifies the function doesn't throw when Intl exists + expect(() => { + findTimeZone() + }).not.toThrow() + }) +}) diff --git a/app/javascript/__tests__/two_minute_warning_session_timeout.test.js b/app/javascript/__tests__/two_minute_warning_session_timeout.test.js index 69f1bb1948..e70f895235 100644 --- a/app/javascript/__tests__/two_minute_warning_session_timeout.test.js +++ b/app/javascript/__tests__/two_minute_warning_session_timeout.test.js @@ -45,14 +45,4 @@ describe('session_timeout_poller', () => { setIntervalSpy.mockRestore() }) - - test('demonstrates timeout logic is testable', () => { - // This test demonstrates the module loads and can be tested - // A full integration test would require complex timer manipulation - // due to how the module uses Date.getTime() and setInterval together - expect(() => { - jest.resetModules() - require('../src/session_timeout_poller') - }).not.toThrow() - }) }) diff --git a/app/javascript/__tests__/type_checker.test.js b/app/javascript/__tests__/type_checker.test.js new file mode 100644 index 0000000000..e7213b294f --- /dev/null +++ b/app/javascript/__tests__/type_checker.test.js @@ -0,0 +1,246 @@ +/* eslint-env jest */ +/** + * @jest-environment jsdom + */ + +const TypeChecker = require('../src/type_checker') + +describe('TypeChecker', () => { + describe('checkNonEmptyJQueryObject', () => { + beforeEach(() => { + document.body.innerHTML = '
' + }) + + test('accepts a non-empty jQuery object', () => { + const element = $('#test-element') + expect(() => { + TypeChecker.checkNonEmptyJQueryObject(element, 'element') + }).not.toThrow() + }) + + test('throws TypeError when passed a non-jQuery object', () => { + expect(() => { + TypeChecker.checkNonEmptyJQueryObject('string', 'element') + }).toThrow(TypeError) + expect(() => { + TypeChecker.checkNonEmptyJQueryObject('string', 'element') + }).toThrow('Param element must be a jQuery object') + }) + + test('throws TypeError when passed null', () => { + expect(() => { + TypeChecker.checkNonEmptyJQueryObject(null, 'element') + }).toThrow(TypeError) + }) + + test('throws TypeError when passed undefined', () => { + expect(() => { + TypeChecker.checkNonEmptyJQueryObject(undefined, 'element') + }).toThrow(TypeError) + }) + + test('throws TypeError when passed a plain object', () => { + expect(() => { + TypeChecker.checkNonEmptyJQueryObject({}, 'element') + }).toThrow(TypeError) + }) + + test('throws ReferenceError when jQuery object contains no elements', () => { + const emptyElement = $('#non-existent') + expect(() => { + TypeChecker.checkNonEmptyJQueryObject(emptyElement, 'element') + }).toThrow(ReferenceError) + expect(() => { + TypeChecker.checkNonEmptyJQueryObject(emptyElement, 'element') + }).toThrow('Param element contains no elements') + }) + }) + + describe('checkNonEmptyString', () => { + test('accepts a non-empty string', () => { + expect(() => { + TypeChecker.checkNonEmptyString('hello', 'myString') + }).not.toThrow() + }) + + test('throws TypeError when passed a non-string', () => { + expect(() => { + TypeChecker.checkNonEmptyString(123, 'myString') + }).toThrow(TypeError) + expect(() => { + TypeChecker.checkNonEmptyString(123, 'myString') + }).toThrow('Param myString must be a string') + }) + + test('throws TypeError when passed null', () => { + expect(() => { + TypeChecker.checkNonEmptyString(null, 'myString') + }).toThrow(TypeError) + }) + + test('throws TypeError when passed undefined', () => { + expect(() => { + TypeChecker.checkNonEmptyString(undefined, 'myString') + }).toThrow(TypeError) + }) + + test('throws RangeError when passed an empty string', () => { + expect(() => { + TypeChecker.checkNonEmptyString('', 'myString') + }).toThrow(RangeError) + expect(() => { + TypeChecker.checkNonEmptyString('', 'myString') + }).toThrow('Param myString cannot be empty string') + }) + }) + + describe('checkObject', () => { + test('accepts a plain object', () => { + expect(() => { + TypeChecker.checkObject({}, 'myObject') + }).not.toThrow() + }) + + test('accepts an object with properties', () => { + expect(() => { + TypeChecker.checkObject({ key: 'value' }, 'myObject') + }).not.toThrow() + }) + + test('throws TypeError when passed a string', () => { + expect(() => { + TypeChecker.checkObject('string', 'myObject') + }).toThrow(TypeError) + expect(() => { + TypeChecker.checkObject('string', 'myObject') + }).toThrow('Param myObject is not an object') + }) + + test('throws TypeError when passed a number', () => { + expect(() => { + TypeChecker.checkObject(123, 'myObject') + }).toThrow(TypeError) + }) + + test('throws TypeError when passed an array', () => { + expect(() => { + TypeChecker.checkObject([1, 2, 3], 'myObject') + }).toThrow(TypeError) + expect(() => { + TypeChecker.checkObject([1, 2, 3], 'myObject') + }).toThrow('Param myObject is not an object') + }) + + test('throws TypeError when passed null', () => { + expect(() => { + TypeChecker.checkObject(null, 'myObject') + }).toThrow(TypeError) + }) + + test('throws TypeError when passed undefined', () => { + expect(() => { + TypeChecker.checkObject(undefined, 'myObject') + }).toThrow(TypeError) + }) + }) + + describe('checkPositiveInteger', () => { + test('accepts zero', () => { + expect(() => { + TypeChecker.checkPositiveInteger(0, 'myNumber') + }).not.toThrow() + }) + + test('accepts positive integers', () => { + expect(() => { + TypeChecker.checkPositiveInteger(1, 'myNumber') + }).not.toThrow() + expect(() => { + TypeChecker.checkPositiveInteger(100, 'myNumber') + }).not.toThrow() + }) + + test('throws TypeError when passed a float', () => { + expect(() => { + TypeChecker.checkPositiveInteger(1.5, 'myNumber') + }).toThrow(TypeError) + expect(() => { + TypeChecker.checkPositiveInteger(1.5, 'myNumber') + }).toThrow('Param myNumber is not an integer') + }) + + test('throws TypeError when passed a string', () => { + expect(() => { + TypeChecker.checkPositiveInteger('123', 'myNumber') + }).toThrow(TypeError) + }) + + test('throws TypeError when passed NaN', () => { + expect(() => { + TypeChecker.checkPositiveInteger(NaN, 'myNumber') + }).toThrow(TypeError) + }) + + test('throws RangeError when passed a negative integer', () => { + expect(() => { + TypeChecker.checkPositiveInteger(-1, 'myNumber') + }).toThrow(RangeError) + expect(() => { + TypeChecker.checkPositiveInteger(-1, 'myNumber') + }).toThrow('Param myNumber cannot be negative') + }) + + test('throws RangeError when passed a large negative integer', () => { + expect(() => { + TypeChecker.checkPositiveInteger(-100, 'myNumber') + }).toThrow(RangeError) + }) + }) + + describe('checkString', () => { + test('accepts a string', () => { + expect(() => { + TypeChecker.checkString('hello', 'myString') + }).not.toThrow() + }) + + test('accepts an empty string', () => { + expect(() => { + TypeChecker.checkString('', 'myString') + }).not.toThrow() + }) + + test('throws TypeError when passed a number', () => { + expect(() => { + TypeChecker.checkString(123, 'myString') + }).toThrow(TypeError) + expect(() => { + TypeChecker.checkString(123, 'myString') + }).toThrow('Param myString must be a string') + }) + + test('throws TypeError when passed null', () => { + expect(() => { + TypeChecker.checkString(null, 'myString') + }).toThrow(TypeError) + }) + + test('throws TypeError when passed undefined', () => { + expect(() => { + TypeChecker.checkString(undefined, 'myString') + }).toThrow(TypeError) + }) + + test('throws TypeError when passed an object', () => { + expect(() => { + TypeChecker.checkString({}, 'myString') + }).toThrow(TypeError) + }) + + test('throws TypeError when passed an array', () => { + expect(() => { + TypeChecker.checkString([], 'myString') + }).toThrow(TypeError) + }) + }) +}) diff --git a/app/javascript/__tests__/validated_form.test.js b/app/javascript/__tests__/validated_form.test.js index ddc348932b..c82e667835 100644 --- a/app/javascript/__tests__/validated_form.test.js +++ b/app/javascript/__tests__/validated_form.test.js @@ -69,13 +69,11 @@ describe('NonDrivingContactMediumWarning', () => { ` - $(() => { // JQuery's callback for the DOM loading - checkboxes = $('.contact-medium.form-group input:not([type=hidden])') - drivingOption = checkboxes.filter('#case_contact_medium_type_in-person') - milesDrivenInput = $('#case_contact_miles_driven') - nonDrivingOptions = checkboxes.not(drivingOption) - notifier = new Notifier($('#notifications')) - }) + checkboxes = $('.contact-medium.form-group input:not([type=hidden])') + drivingOption = checkboxes.filter('#case_contact_medium_type_in-person') + milesDrivenInput = $('#case_contact_miles_driven') + nonDrivingOptions = checkboxes.not(drivingOption) + notifier = new Notifier($('#notifications')) }) describe('constructor', () => { @@ -96,58 +94,40 @@ describe('NonDrivingContactMediumWarning', () => { let component beforeEach(() => { - $(() => { - component = new NonDrivingContactMediumWarning($('.contact-medium.form-group input:not([type=hidden]), #case_contact_miles_driven'), notifier) - }) + component = new NonDrivingContactMediumWarning($('.contact-medium.form-group input:not([type=hidden]), #case_contact_miles_driven'), notifier) }) - test('returns the warning message if a non driving contact medium is selected and the miles driven count is > 0', (done) => { - $(() => { - try { - expect(nonDrivingOptions.length).toBeGreaterThan(0) - - milesDrivenInput.val(1) + test('returns the warning message if a non driving contact medium is selected and the miles driven count is > 0', () => { + expect(nonDrivingOptions.length).toBeGreaterThan(0) - nonDrivingOptions.each(function () { - const option = $(this) + milesDrivenInput.val(1) - option.trigger('click') + nonDrivingOptions.each(function () { + const option = $(this) - expect(component.getWarningState()).toBe('You requested driving reimbursement for a contact medium that typically does not involve driving. Are you sure that\'s right?') - }) + option.trigger('click') - done() - } catch (error) { - done(error) - } + expect(component.getWarningState()).toBe('You requested driving reimbursement for a contact medium that typically does not involve driving. Are you sure that\'s right?') }) }) - test('returns a falsy value if the driving contact medium is selected or the miles driven count is 0', (done) => { - $(() => { - try { - expect(nonDrivingOptions.length).toBeGreaterThan(0) + test('returns a falsy value if the driving contact medium is selected or the miles driven count is 0', () => { + expect(nonDrivingOptions.length).toBeGreaterThan(0) - milesDrivenInput.val(0) + milesDrivenInput.val(0) - nonDrivingOptions.each(function () { - const option = $(this) + nonDrivingOptions.each(function () { + const option = $(this) - option.trigger('click') + option.trigger('click') - expect(component.getWarningState()).toBeFalsy() - }) - - milesDrivenInput.val(1) - drivingOption.trigger('click') + expect(component.getWarningState()).toBeFalsy() + }) - expect(component.getWarningState()).toBeFalsy() + milesDrivenInput.val(1) + drivingOption.trigger('click') - done() - } catch (error) { - done(error) - } - }) + expect(component.getWarningState()).toBeFalsy() }) }) From 97d52f3f5d22142ba15efc638547e8c43fa5c3e9 Mon Sep 17 00:00:00 2001 From: Linda Goldstein Date: Fri, 28 Nov 2025 18:35:00 -0500 Subject: [PATCH 2/2] fix: Add browser environment to read_more test for MouseEvent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes StandardJS linting errors: - 'MouseEvent' is not defined at lines 63 and 73 Added browser to eslint-env since the test uses jsdom which simulates a browser environment where MouseEvent is available as a global. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/javascript/__tests__/read_more.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/__tests__/read_more.test.js b/app/javascript/__tests__/read_more.test.js index a171003046..7885eb8077 100644 --- a/app/javascript/__tests__/read_more.test.js +++ b/app/javascript/__tests__/read_more.test.js @@ -1,4 +1,4 @@ -/* eslint-env jest */ +/* eslint-env jest, browser */ /** * @jest-environment jsdom */