Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/core/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
**/*.stories.*
**/*.figma.ts
stencil.config.ts
src/utils/test/setup.ts
157 changes: 157 additions & 0 deletions libs/core/src/utils/test/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/**
* 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;
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 {};

9 changes: 9 additions & 0 deletions libs/core/stencil.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ export const config: Config = {
openBrowser: false,
port: 7300,
},
testing: {
setupFilesAfterEnv: ['<rootDir>/src/utils/test/setup.ts'],
coveragePathIgnorePatterns: [
'/node_modules/',
'/dist/',
'/www/',
'setup.ts'
],
},
outputTargets: [
{
type: 'dist',
Expand Down
3 changes: 2 additions & 1 deletion libs/core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"**/*.stories.ts",
"**/*.stories.tsx",
"**/*.figma.ts",
"scripts/custom-elements"
"scripts/custom-elements",
"src/utils/test/setup.ts"
]
}
Loading