From 97aeea3515cf0254dab71594d68a6aa85648ac65 Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Fri, 24 Oct 2025 10:29:53 -0500 Subject: [PATCH 1/5] fix: resolve element internals testing support issue --- libs/core/src/utils/test/setup.ts | 138 ++++++++++++++++++++++++++++++ libs/core/stencil.config.ts | 9 ++ libs/core/tsconfig.json | 3 +- 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 libs/core/src/utils/test/setup.ts diff --git a/libs/core/src/utils/test/setup.ts b/libs/core/src/utils/test/setup.ts new file mode 100644 index 000000000..90803c88b --- /dev/null +++ b/libs/core/src/utils/test/setup.ts @@ -0,0 +1,138 @@ +/** + * Global test setup file + * This file is loaded before all tests to provide mocks and polyfills + */ + +/** + * Mock ElementInternals API for testing + * The ElementInternals API is used for form-associated custom elements + * but is not fully supported in Stencil's unit test environment + */ +class MockElementInternals { + // @ts-expect-error - Stored for mock completeness + private _formValue: FormData | string | null = null; + // @ts-expect-error - Stored for mock completeness + private _formState: FormData | string | null = null; + private validationMessage = ''; + private validity: ValidityState = { + badInput: false, + customError: false, + patternMismatch: false, + rangeOverflow: false, + rangeUnderflow: false, + stepMismatch: false, + tooLong: false, + tooShort: false, + typeMismatch: false, + valid: true, + valueMissing: false, + }; + + /** + * Sets the form value and state for the associated custom element + */ + setFormValue( + value: File | string | FormData | null, + state?: File | string | FormData | null, + ): void { + this._formValue = value as FormData | string | null; + this._formState = state !== undefined ? (state as FormData | string | null) : value as FormData | string | null; + } + + /** + * Sets the validity state and validation message + */ + setValidity( + flags?: ValidityStateFlags, + message?: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _anchor?: HTMLElement, + ): void { + if (flags) { + this.validity = { ...this.validity, ...flags, valid: !Object.values(flags).some(Boolean) }; + } + this.validationMessage = message || ''; + } + + /** + * Checks if the element will pass validation + */ + checkValidity(): boolean { + return this.validity.valid; + } + + /** + * Checks validity and fires invalid event if not valid + */ + reportValidity(): boolean { + return this.validity.valid; + } + + /** + * Returns the form associated with this element + */ + get form(): HTMLFormElement | null { + return null; + } + + /** + * Returns the validation message + */ + get validationMessage_(): string { + return this.validationMessage; + } + + /** + * Returns the validity state + */ + get validity_(): ValidityState { + return this.validity; + } + + /** + * Returns whether the element will be validated + */ + get willValidate(): boolean { + return true; + } + + /** + * Returns the labels associated with this element + */ + get labels(): NodeList { + return { + length: 0, + item: () => null, + // eslint-disable-next-line @typescript-eslint/no-empty-function + [Symbol.iterator]: function* () {}, + } as unknown as NodeList; + } +} + +/** + * Mock attachInternals method on HTMLElement + */ +if (typeof HTMLElement !== 'undefined' && typeof HTMLElement.prototype.attachInternals === 'undefined') { + HTMLElement.prototype.attachInternals = function () { + return new MockElementInternals() as unknown as ElementInternals; + }; +} + +/** + * Suppress specific console warnings that are expected in test environment + */ +const originalConsoleError = console.error; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +console.error = (...args: any[]) => { + // Filter out the ElementInternals warning since we're mocking it + if ( + typeof args[0] === 'string' && + args[0].includes('Property setFormValue was accessed on ElementInternals') + ) { + return; + } + originalConsoleError.apply(console, args); +}; + +export {}; + diff --git a/libs/core/stencil.config.ts b/libs/core/stencil.config.ts index e4c7e21e3..adde4dbf0 100644 --- a/libs/core/stencil.config.ts +++ b/libs/core/stencil.config.ts @@ -11,6 +11,15 @@ export const config: Config = { openBrowser: false, port: 7300, }, + testing: { + setupFilesAfterEnv: ['/src/utils/test/setup.ts'], + coveragePathIgnorePatterns: [ + '/node_modules/', + '/dist/', + '/www/', + 'setup.ts' + ], + }, outputTargets: [ { type: 'dist', diff --git a/libs/core/tsconfig.json b/libs/core/tsconfig.json index 67a50d611..fd861679b 100644 --- a/libs/core/tsconfig.json +++ b/libs/core/tsconfig.json @@ -30,6 +30,7 @@ "**/*.stories.ts", "**/*.stories.tsx", "**/*.figma.ts", - "scripts/custom-elements" + "scripts/custom-elements", + "src/utils/test/setup.ts" ] } From cbff17b590b9ffd1c298a2d0604bccbf6bf9a218 Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Fri, 24 Oct 2025 10:52:12 -0500 Subject: [PATCH 2/5] chore: update eslint --- libs/core/.eslintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/core/.eslintignore b/libs/core/.eslintignore index 17f207a89..7f6bfd2b3 100644 --- a/libs/core/.eslintignore +++ b/libs/core/.eslintignore @@ -4,3 +4,4 @@ **/*.stories.* **/*.figma.ts stencil.config.ts +src/utils/test/setup.ts From addf775861525877b366d914ff7c08b3c0567ac0 Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Fri, 24 Oct 2025 11:29:27 -0500 Subject: [PATCH 3/5] chore: update func names --- libs/core/src/utils/test/setup.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/core/src/utils/test/setup.ts b/libs/core/src/utils/test/setup.ts index 90803c88b..b7019866c 100644 --- a/libs/core/src/utils/test/setup.ts +++ b/libs/core/src/utils/test/setup.ts @@ -13,8 +13,8 @@ class MockElementInternals { private _formValue: FormData | string | null = null; // @ts-expect-error - Stored for mock completeness private _formState: FormData | string | null = null; - private validationMessage = ''; - private validity: ValidityState = { + private _validationMessage = ''; + private _validity: ValidityState = { badInput: false, customError: false, patternMismatch: false, @@ -49,23 +49,23 @@ class MockElementInternals { _anchor?: HTMLElement, ): void { if (flags) { - this.validity = { ...this.validity, ...flags, valid: !Object.values(flags).some(Boolean) }; + this._validity = { ...this._validity, ...flags, valid: !Object.values(flags).some(Boolean) }; } - this.validationMessage = message || ''; + this._validationMessage = message || ''; } /** * Checks if the element will pass validation */ checkValidity(): boolean { - return this.validity.valid; + return this._validity.valid; } /** * Checks validity and fires invalid event if not valid */ reportValidity(): boolean { - return this.validity.valid; + return this._validity.valid; } /** @@ -78,15 +78,15 @@ class MockElementInternals { /** * Returns the validation message */ - get validationMessage_(): string { - return this.validationMessage; + get validationMessage(): string { + return this._validationMessage; } /** * Returns the validity state */ - get validity_(): ValidityState { - return this.validity; + get validity(): ValidityState { + return this._validity; } /** From 376bc08e74a6286d60dca687684e1972e21368c8 Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Mon, 27 Oct 2025 08:36:33 -0500 Subject: [PATCH 4/5] fix: filter out svg 404 errors --- libs/core/src/utils/test/setup.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libs/core/src/utils/test/setup.ts b/libs/core/src/utils/test/setup.ts index b7019866c..f58a80eb7 100644 --- a/libs/core/src/utils/test/setup.ts +++ b/libs/core/src/utils/test/setup.ts @@ -124,13 +124,18 @@ if (typeof HTMLElement !== 'undefined' && typeof HTMLElement.prototype.attachInt const originalConsoleError = console.error; // eslint-disable-next-line @typescript-eslint/no-explicit-any console.error = (...args: any[]) => { + const message = typeof args[0] === 'string' ? args[0] : ''; + // Filter out the ElementInternals warning since we're mocking it - if ( - typeof args[0] === 'string' && - args[0].includes('Property setFormValue was accessed on ElementInternals') - ) { + if (message.includes('Property setFormValue was accessed on ElementInternals')) { return; } + + // Filter out SVG icon 404 errors in e2e tests (icons aren't available on test server) + if (message.includes('Failed to load resource') && message.includes('pds-icons/svg')) { + return; + } + originalConsoleError.apply(console, args); }; From 861503f0ae9036c2d4f4f870f398bea0751c07ea Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Mon, 27 Oct 2025 10:37:55 -0500 Subject: [PATCH 5/5] chore: add svg console warnings --- libs/core/src/utils/test/setup.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/libs/core/src/utils/test/setup.ts b/libs/core/src/utils/test/setup.ts index f58a80eb7..9b3efe27c 100644 --- a/libs/core/src/utils/test/setup.ts +++ b/libs/core/src/utils/test/setup.ts @@ -122,22 +122,36 @@ if (typeof HTMLElement !== 'undefined' && typeof HTMLElement.prototype.attachInt * Suppress specific console warnings that are expected in test environment */ const originalConsoleError = console.error; +const originalConsoleWarn = console.warn; + // eslint-disable-next-line @typescript-eslint/no-explicit-any console.error = (...args: any[]) => { const message = typeof args[0] === 'string' ? args[0] : ''; - + // Filter out the ElementInternals warning since we're mocking it if (message.includes('Property setFormValue was accessed on ElementInternals')) { return; } - + // Filter out SVG icon 404 errors in e2e tests (icons aren't available on test server) if (message.includes('Failed to load resource') && message.includes('pds-icons/svg')) { return; } - + originalConsoleError.apply(console, args); }; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +console.warn = (...args: any[]) => { + const message = typeof args[0] === 'string' ? args[0] : ''; + + // Filter out SVG icon loading warnings in e2e tests (icons aren't available on test server) + if (message.includes('Failed to load SVG') && message.includes('pds-icons/svg')) { + return; + } + + originalConsoleWarn.apply(console, args); +}; + export {};