const ErrorType = { NO_ELEMENTS_WITH_SELECTOR: 'no-elements-with-selector', MULTIPLE_ELEMENTS_WITH_SELECTOR: 'multiple-elements-with-selector', } as const; export class NoElementWithSelectorError extends Error { type = ErrorType.NO_ELEMENTS_WITH_SELECTOR; failedPath?: string[]; fullPath?: string[]; private static convertSelectorPathToString = (selectorsPath: string[]): string => { return selectorsPath .reduce((acc, item) => { if (item.startsWith(':')) { acc[acc.length - 1] = `${String(acc.at(-1))}${item}`; } else { acc.push(item); } return acc; }, []) .join(' > '); }; constructor(params: {selector: string; failedPath?: string[]; fullPath?: string[]}) { const {selector, failedPath, fullPath} = params; const finalMessage = (() => { let message = `Cannot find element with selector: ${selector}`; if (failedPath) { message += `\r\nFailed path: ${NoElementWithSelectorError.convertSelectorPathToString(failedPath)}`; } if (fullPath) { message += `\r\nFull path: ${NoElementWithSelectorError.convertSelectorPathToString(fullPath)}`; } return message; })(); super(finalMessage); this.failedPath = failedPath ?? fullPath; this.fullPath = fullPath; } } export class MultipleElementsWithSelectorError extends Error { type = ErrorType.MULTIPLE_ELEMENTS_WITH_SELECTOR; constructor(count: number, selector: string) { super( `Found ${String(count)} elements with selector [${selector}]. Only 1 is expected. This is either a bug or not-specific-enough selector`, ); } } const assertType = (error: unknown, errorType: (typeof ErrorType)[keyof typeof ErrorType]) => { const type = error instanceof Error ? (error as NoElementWithSelectorError | MultipleElementsWithSelectorError).type : ''; return type === errorType; }; export const isNoElementWithSelectorError = (error: unknown): error is NoElementWithSelectorError => { return assertType(error, ErrorType.NO_ELEMENTS_WITH_SELECTOR); }; export const isMultipleElementsWithSelectorError = (error: unknown): error is MultipleElementsWithSelectorError => { return assertType(error, ErrorType.MULTIPLE_ELEMENTS_WITH_SELECTOR); };