Skip to content

Commit 5af6631

Browse files
committed
Add custom TestError class, update test files to use it
1 parent c2d4e92 commit 5af6631

18 files changed

Lines changed: 63 additions & 48 deletions

File tree

scripts/build/__tests__/favicon.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest'
22
import sharp, { type Metadata } from 'sharp'
33
import toIco from 'to-ico'
44
import { writeFile } from 'fs/promises'
5-
import { UnitTestError } from '@test/errors'
5+
import { TestError } from '@test/errors'
66

77
// Mock external dependencies
88
vi.mock('sharp')
@@ -36,7 +36,7 @@ describe('favicon.ts', () => {
3636
// Since generateIcoFavicon is not exported, we'll create a local test
3737
const generateIcoFavicon = ({ width, height, density }: Partial<Metadata>) => {
3838
if (!width || !height || !density) {
39-
throw new UnitTestError(`Required option not passed to generateIcoFavicon`)
39+
throw new TestError(`Required option not passed to generateIcoFavicon`)
4040
}
4141
}
4242

@@ -48,7 +48,7 @@ describe('favicon.ts', () => {
4848
it('should throw error when height is missing', () => {
4949
const generateIcoFavicon = ({ width, height, density }: Partial<Metadata>) => {
5050
if (!width || !height || !density) {
51-
throw new UnitTestError(`Required option not passed to generateIcoFavicon`)
51+
throw new TestError(`Required option not passed to generateIcoFavicon`)
5252
}
5353
}
5454
const metadata: Partial<Metadata> = { width: 512, density: 72 }
@@ -61,7 +61,7 @@ describe('favicon.ts', () => {
6161
it('should throw error when density is missing', () => {
6262
const generateIcoFavicon = ({ width, height, density }: Partial<Metadata>) => {
6363
if (!width || !height || !density) {
64-
throw new UnitTestError(`Required option not passed to generateIcoFavicon`)
64+
throw new TestError(`Required option not passed to generateIcoFavicon`)
6565
}
6666
}
6767
const metadata: Partial<Metadata> = { width: 512, height: 512 }
@@ -112,7 +112,7 @@ describe('favicon.ts', () => {
112112
it('should throw error when required parameters are missing', () => {
113113
const generatePngFavicon = ({ width, height, density }: Partial<Metadata>) => {
114114
if (!width || !height || !density) {
115-
throw new UnitTestError(`Required option not passed to generatePngFavicon`)
115+
throw new TestError(`Required option not passed to generatePngFavicon`)
116116
}
117117
}
118118

src/components/CallToAction/Newsletter/__tests__/client.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { experimental_AstroContainer as AstroContainer } from 'astro/container'
77
import { NewsletterFormElement } from '@components/CallToAction/Newsletter/client'
88
import { getNewsletterElements } from '@components/CallToAction/Newsletter/selectors'
99
import NewsletterFixture from '@components/CallToAction/Newsletter/__fixtures__/client.fixture.astro'
10+
import { TestError } from '@test/errors'
1011

1112
/**
1213
* Helper function to get form elements after DOM setup
@@ -15,7 +16,7 @@ import NewsletterFixture from '@components/CallToAction/Newsletter/__fixtures__/
1516
function getFormElements() {
1617
const customElement = document.querySelector('newsletter-form')
1718
if (!customElement) {
18-
throw new Error('newsletter-form custom element not found')
19+
throw new TestError('newsletter-form custom element not found')
1920
}
2021
return getNewsletterElements(customElement)
2122
}

src/components/Carousel/__tests__/client.spec.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest'
44
import { experimental_AstroContainer as AstroContainer } from 'astro/container'
55
import TestCarousel from '@components/Carousel/__fixtures__/client.fixture.astro'
66
import { isButtonElement } from '@components/scripts/assertions/elements'
7+
import { TestError } from '@test/errors'
78

89
// Mock Embla Carousel and Autoplay plugin
910
const mockEmblaApi = {
@@ -115,23 +116,23 @@ describe('CarouselManager', () => {
115116

116117
it('should handle previous button click', () => {
117118
const prevButton = carousel.querySelector('.embla__button--prev')
118-
if (!isButtonElement(prevButton)) throw new Error('Prev button not found')
119+
if (!isButtonElement(prevButton)) throw new TestError('Prev button not found')
119120
prevButton.click()
120121

121122
expect(mockEmblaApi.scrollPrev).toHaveBeenCalled()
122123
})
123124

124125
it('should handle next button click', () => {
125126
const nextButton = carousel.querySelector('.embla__button--next')
126-
if (!isButtonElement(nextButton)) throw new Error('Next button not found')
127+
if (!isButtonElement(nextButton)) throw new TestError('Next button not found')
127128
nextButton.click()
128129

129130
expect(mockEmblaApi.scrollNext).toHaveBeenCalled()
130131
})
131132

132133
it('should handle dot navigation click', () => {
133134
const firstDot = carousel.querySelector('.embla__dot')
134-
if (!isButtonElement(firstDot)) throw new Error('First dot not found')
135+
if (!isButtonElement(firstDot)) throw new TestError('First dot not found')
135136
firstDot.click()
136137

137138
expect(mockEmblaApi.scrollTo).toHaveBeenCalledWith(0)
@@ -147,9 +148,9 @@ describe('CarouselManager', () => {
147148
onSelectCallback?.()
148149

149150
const prevButton = carousel.querySelector('.embla__button--prev')
150-
if (!isButtonElement(prevButton)) throw new Error('Prev button not found')
151+
if (!isButtonElement(prevButton)) throw new TestError('Prev button not found')
151152
const nextButton = carousel.querySelector('.embla__button--next')
152-
if (!isButtonElement(nextButton)) throw new Error('Next button not found')
153+
if (!isButtonElement(nextButton)) throw new TestError('Next button not found')
153154

154155
expect(prevButton.disabled).toBe(true)
155156
expect(prevButton.classList.contains('opacity-30')).toBe(true)
@@ -324,9 +325,9 @@ describe('CarouselManager', () => {
324325
CarouselManager.init()
325326

326327
const prevButton = carousel.querySelector('.embla__button--prev')
327-
if (!isButtonElement(prevButton)) throw new Error('Prev button not found')
328+
if (!isButtonElement(prevButton)) throw new TestError('Prev button not found')
328329
const nextButton = carousel.querySelector('.embla__button--next')
329-
if (!isButtonElement(nextButton)) throw new Error('Next button not found')
330+
if (!isButtonElement(nextButton)) throw new TestError('Next button not found')
330331

331332
expect(prevButton.type).toBe('button')
332333
expect(nextButton.type).toBe('button')

src/components/Forms/Download/__tests__/client.spec.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
isInputElement,
1111
} from '@components/scripts/assertions/elements'
1212
import DownloadFormComponent from '@components/Forms/Download/index.astro'
13+
import { TestError } from '@test/errors'
1314

1415
// Mock the logger to suppress error output in tests
1516
vi.mock('@lib/logger', () => ({
@@ -42,32 +43,32 @@ async function setupDownloadFormDOM() {
4243
function getDownloadFormElements() {
4344
const form = document.getElementById('downloadForm')
4445
if (!isFormElement(form)) {
45-
throw new Error('Download form element not found')
46+
throw new TestError('Download form element not found')
4647
}
4748

4849
const firstName = form.querySelector('#firstName')
4950
if (!isInputElement(firstName)) {
50-
throw new Error('firstName input not found')
51+
throw new TestError('firstName input not found')
5152
}
5253

5354
const lastName = form.querySelector('#lastName')
5455
if (!isInputElement(lastName)) {
55-
throw new Error('lastName input not found')
56+
throw new TestError('lastName input not found')
5657
}
5758

5859
const workEmail = form.querySelector('#workEmail')
5960
if (!isInputElement(workEmail)) {
60-
throw new Error('workEmail input not found')
61+
throw new TestError('workEmail input not found')
6162
}
6263

6364
const jobTitle = form.querySelector('#jobTitle')
6465
if (!isInputElement(jobTitle)) {
65-
throw new Error('jobTitle input not found')
66+
throw new TestError('jobTitle input not found')
6667
}
6768

6869
const companyName = form.querySelector('#companyName')
6970
if (!isInputElement(companyName)) {
70-
throw new Error('companyName input not found')
71+
throw new TestError('companyName input not found')
7172
}
7273

7374
return {
@@ -102,7 +103,7 @@ describe('DownloadForm class', () => {
102103
const formElement = document.getElementById('downloadForm')
103104

104105
if (!isFormElement(formElement)) {
105-
throw new Error('Form element not found')
106+
throw new TestError('Form element not found')
106107
}
107108

108109
const submitSpy = vi.fn((e) => e.preventDefault())
@@ -129,7 +130,7 @@ describe('DownloadForm class', () => {
129130
// Fill out the form
130131
const formElement = document.getElementById('downloadForm')
131132
if (!isFormElement(formElement)) {
132-
throw new Error('Form element not found')
133+
throw new TestError('Form element not found')
133134
}
134135

135136
const firstNameInput = formElement.querySelector('#firstName')
@@ -141,7 +142,7 @@ describe('DownloadForm class', () => {
141142
if (!isInputElement(firstNameInput) || !isInputElement(lastNameInput) ||
142143
!isInputElement(emailInput) || !isInputElement(jobTitleInput) ||
143144
!isInputElement(companyInput)) {
144-
throw new Error('Form inputs not found')
145+
throw new TestError('Form inputs not found')
145146
}
146147

147148
firstNameInput.value = 'John'
@@ -261,7 +262,7 @@ describe('DownloadForm class', () => {
261262
const { form: formElement, firstName, lastName, workEmail, jobTitle, companyName } = getDownloadFormElements()
262263
const submitBtn = document.getElementById('downloadSubmitBtn')
263264
if (!submitBtn || !(submitBtn instanceof HTMLButtonElement)) {
264-
throw new Error('Submit button not found')
265+
throw new TestError('Submit button not found')
265266
}
266267

267268
// Fill form

src/components/GDPR/Consent/__tests__/client.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from '@components/GDPR/Consent/client'
1111
import { $formConsent, clearFormConsent, type ConsentPurpose } from '@components/GDPR/Consent/state'
1212
import { isInputElement, isDivElement } from '@components/scripts/assertions/elements'
13+
import { TestError } from '@test/errors'
1314

1415
/**
1516
* Helper to create mock GDPR consent HTML structure in a form
@@ -38,12 +39,12 @@ function setupConsentForm(checkboxId = 'gdpr-consent'): HTMLFormElement {
3839
function getConsentElements(checkboxId = 'gdpr-consent') {
3940
const checkbox = document.getElementById(checkboxId)
4041
if (!isInputElement(checkbox)) {
41-
throw new Error(`Checkbox with id "${checkboxId}" not found`)
42+
throw new TestError(`Checkbox with id "${checkboxId}" not found`)
4243
}
4344

4445
const errorElement = document.getElementById(`${checkboxId}-error`)
4546
if (!isDivElement(errorElement)) {
46-
throw new Error(`Error element with id "${checkboxId}-error" not found`)
47+
throw new TestError(`Error element with id "${checkboxId}-error" not found`)
4748
}
4849

4950
return { checkbox, errorElement }

src/components/scripts/bootstrap/__tests__/index.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest'
77
import { AppBootstrap } from '@components/scripts/bootstrap'
88
import { ClientScriptError } from '@components/scripts/errors/ClientScriptError'
99
import { addScriptBreadcrumb } from '@components/scripts/errors'
10+
import { TestError } from '@test/errors'
1011

1112
// Mock the store initialization functions
1213
vi.mock('@components/scripts/store', () => ({
@@ -124,7 +125,7 @@ describe('AppBootstrap', () => {
124125
it('should not call side effects when initConsentFromCookies fails', () => {
125126
vi.mocked(addViewTransitionThemeInitListener).mockReturnValue(undefined)
126127
vi.mocked(initConsentFromCookies).mockImplementation(() => {
127-
throw new Error('Cookie initialization failed')
128+
throw new TestError('Cookie initialization failed')
128129
})
129130
vi.mocked(initConsentSideEffects).mockReturnValue(undefined)
130131

src/components/scripts/errors/__tests__/ClientScriptError.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
*/
44
import { describe, expect, test } from 'vitest'
55
import type { Constructor } from '@test/unit/matchers/assertions'
6+
import { TestError } from '@test/errors'
67
import { ClientScriptError, isClientScriptError } from '@components/scripts/errors'
78

89
describe(`ClientScriptError class is constructible`, () => {
910
test(`Class is properly constructed`, () => {
1011
try {
1112
throw new ClientScriptError(`It went bad!`)
1213
} catch (err) {
13-
if (!isClientScriptError(err)) throw new Error()
14+
if (!isClientScriptError(err)) throw new TestError(`Expected ClientScriptError to be thrown`)
1415
// The name property should be set to the error`s name
1516
expect(err.name).toBe(`ClientScriptError`)
1617

src/components/scripts/errors/__tests__/converters.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Tests for error converters to ClientScriptError
44
*/
55
import { describe, expect, test } from 'vitest'
6+
import { TestError } from '@test/errors'
67
import { ClientScriptError } from '@components/scripts/errors/ClientScriptError'
78
import {
89
convertFromError,
@@ -20,9 +21,9 @@ const voidFn = () => {}
2021

2122
describe(`extractMetadaFromStackTrace correctly pulls metadata from stack trace`, () => {
2223
test(`extractMetadaFromStackTrace gets correct metadata`, () => {
23-
const err = new Error(`test error`)
24+
const err = new TestError(`test error`)
2425
const stack = err.stack
25-
if (!isString(stack)) throw new Error()
26+
if (!isString(stack)) throw new TestError(`Expected stack to be a string`)
2627
const sut = extractMetadaFromStackTrace(stack)
2728
expect(sut).toEqual(
2829
expect.objectContaining({

src/integrations/PrivacyPolicyVersion/__tests__/index.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
22
import { execSync } from 'node:child_process'
3+
import { TestError } from '@test/errors'
34

45
// Mock child_process
56
vi.mock('node:child_process', () => ({
@@ -91,7 +92,7 @@ describe('PrivacyPolicyVersion Integration', () => {
9192
it('should use current date as fallback when git command fails', async () => {
9293
// Mock git command failure
9394
vi.mocked(execSync).mockImplementation(() => {
94-
throw new Error('Git command failed')
95+
throw new TestError('Git command failed')
9596
})
9697

9798
const { privacyPolicyVersion } = await import('../index')

src/lib/errors/__tests__/BuildError.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
* Tests for error handling routines and custom errors
33
*/
44
import { describe, expect, test } from 'vitest'
5+
import { TestError } from '@test/errors'
56
import { BuildError, isBuildError } from '@lib/errors/BuildError'
67

78
describe(`BuildError class is constructible`, () => {
89
test(`Class is properly constructed`, () => {
910
try {
1011
throw new BuildError(`Test error`)
1112
} catch (err) {
12-
if (!isBuildError(err)) throw new Error()
13+
if (!isBuildError(err)) throw new TestError(`Expected BuildError to be thrown`)
1314
// The name property should be set to the error`s name
1415
expect(err.name).toBe(`BuildError`)
1516

0 commit comments

Comments
 (0)