diff --git a/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js b/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js index 8b380dd6c17..a2e8fd42a71 100644 --- a/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js +++ b/e2e/tests/functional/plugins/displayLayout/displayLayout.e2e.spec.js @@ -599,46 +599,33 @@ test.describe('Display Layout', () => { // Verify filtering is working correctly - // Create a promise that resolves when we've seen enough new rows added - const rowsMutationPromise = page.evaluate(() => { - return new Promise((resolve) => { - const targetTable = document.querySelector( - 'table[aria-label="Table Filter Off Value table content"]' - ); - const config = { childList: true, subtree: true }; - let changeCount = 0; - const requiredChanges = 20; // Number of changes to wait for - - const observer = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if (mutation.type === 'childList') { - // Count added nodes - changeCount += mutation.addedNodes.length; - } - }); - - // Check if the required number of changes has been met - if (changeCount >= requiredChanges) { - observer.disconnect(); // Disconnect observer after the required changes - resolve(); - } - }); - - observer.observe(targetTable, config); - }); - }); - - await rowsMutationPromise; - - // Check ON table doesn't have any OFF values - await expect(tableFilterOn.locator('td[title="OFF"]')).toHaveCount(0); - const onCount = await tableFilterOn.locator('td[title="ON"]').count(); - await expect(onCount).toBeGreaterThan(0); - - // Check OFF table doesn't have any ON values - await expect(tableFilterOff.locator('td[title="ON"]')).toHaveCount(0); - const offCount = await tableFilterOff.locator('td[title="OFF"]').count(); - await expect(offCount).toBeGreaterThan(0); + // Check that no filtered values appear for at least 2 seconds + const VERIFICATION_TIME = 2000; // 2 seconds + const CHECK_INTERVAL = 100; // Check every 100ms + + // Create a promise that will check for filtered values periodically + const checkForCorrectValues = new Promise((resolve, reject) => { + const interval = setInterval(async () => { + const offCount = await tableFilterOn.locator('td[title="OFF"]').count(); + const onCount = await tableFilterOff.locator('td[title="ON"]').count(); + if (offCount > 0 || onCount > 0) { + clearInterval(interval); + reject( + new Error( + `Found ${offCount} OFF and ${onCount} ON values when expecting 0 OFF and 0 ON` + ) + ); + } + }, CHECK_INTERVAL); + + // After VERIFICATION_TIME, if no filtered values were found, resolve successfully + setTimeout(() => { + clearInterval(interval); + resolve(); + }, VERIFICATION_TIME); + }); + + await expect(checkForCorrectValues).resolves.toBeUndefined(); }); }); diff --git a/src/api/telemetry/TelemetryAPI.js b/src/api/telemetry/TelemetryAPI.js index 2b23a6ab199..e5be70590f4 100644 --- a/src/api/telemetry/TelemetryAPI.js +++ b/src/api/telemetry/TelemetryAPI.js @@ -254,12 +254,6 @@ export default class TelemetryAPI { * Sanitizes objects for consistent serialization by: * 1. Removing non-plain objects (class instances) and functions * 2. Sorting object keys alphabetically to ensure consistent ordering - * 3. Recursively processing nested objects - * - * Note: When used as a JSON.stringify replacer, this function will process objects - * twice - once for the initial sorting and again when JSON.stringify processes the - * sorted result. This is acceptable for small options objects, which is the - * intended use case. */ sanitizeForSerialization(key, value) { // Handle null and primitives directly @@ -267,21 +261,27 @@ export default class TelemetryAPI { return value; } - // Remove functions and non-plain objects by returning undefined - if (typeof value === 'function' || Object.getPrototypeOf(value) !== Object.prototype) { + // Remove functions and non-plain objects (except arrays) + if ( + typeof value === 'function' || + (Object.getPrototypeOf(value) !== Object.prototype && !Array.isArray(value)) + ) { return undefined; } - // Handle plain objects - const sortedObject = {}; - const keys = Object.keys(value).sort(); - for (const objectKey of keys) { - const itemValue = value[objectKey]; - const sanitizedValue = this.sanitizeForSerialization(objectKey, itemValue); - sortedObject[objectKey] = sanitizedValue; + // For plain objects, just sort the keys + if (!Array.isArray(value)) { + const sortedObject = {}; + const sortedKeys = Object.keys(value).sort(); + + sortedKeys.forEach((objectKey) => { + sortedObject[objectKey] = value[objectKey]; + }); + + return sortedObject; } - return sortedObject; + return value; } /**