UNPKG

@funnelenvy-npm/fe-dev-utils

Version:

Helper function to build client side A/B tests

81 lines (70 loc) 3.28 kB
import onError from '../on-error'; /** * Get elements matching a CSS selector. Waits for the elements to exist and returns a promise. * @param {Object} options - Options object to configure the function. * @param {Array|string} options.condition - The CSS selector to match elements. * @param {string} [options.activity] - (Optional) Name of the activity the function is being called from, if onError is not set this will be used in the * @param {number} [options.outTimer=10000] - (Optional) The maximum time in milliseconds to wait for the elements to exist. Default is 10000ms. * @param {function} [errorHandler=null] - (Optional) A callback function to handle errors during the waiting process. If not provided, errors will be logged to the console. * @returns {Promise} A promise that resolves with an object containing the selector and matching elements once they are found. * @throws {TypeError} If the timeout is reached and the elements are not found. */ type GetElementOptions = { condition: string | string[]; activity?: string; errorHandler?: ((params: { activity: string; error: Error }) => void) | null; outTimer?: number; }; const getElement = ({ condition, activity = "", errorHandler = null, outTimer = 10000, }: GetElementOptions): Promise<Record<string, NodeListOf<Element>>> => { let selectors: string[] = Array.isArray(condition) ? condition : [condition]; let results: Record<string, NodeListOf<Element>> = {}; return new Promise((resolve, reject) => { const observer = new MutationObserver(() => { selectors = selectors.filter((selector) => { const els = document.querySelectorAll(selector); if (els.length > 0) { results[selector] = els; return false; // Remove from selectors to check } return true; }); if (selectors.length === 0) { observer.disconnect(); resolve(results); } }); // Initial check in case elements are already present selectors.forEach((selector) => { const els = document.querySelectorAll(selector); if (els.length > 0) { results[selector] = els; selectors = selectors.filter((s) => s !== selector); // Remove found selector } }); if (selectors.length === 0) { resolve(results); return; } // Observe mutations in the document observer.observe(document.body, { childList: true, subtree: true }); // Set a timeout to reject the promise if elements are not found within the given time setTimeout(() => { observer.disconnect(); if (selectors.length > 0) { const error = new Error(`Timeout while waiting for selectors: ${selectors.join(', ')}`); if (errorHandler && typeof errorHandler === 'function') { errorHandler({ activity, error }); } else { onError({ activity, error }); } reject(error); } }, outTimer); }); }; export default getElement;