From 47b22e1facacab2978ca6612c05104e28ff4c390 Mon Sep 17 00:00:00 2001 From: Yeon Vinzenz Varapragasam Date: Wed, 20 Mar 2024 14:34:46 +0100 Subject: [PATCH] Column-Row-Toggler, Scroll to first Change --- on-fail-handler.ts | 144 +++++++++++++++++++++++++++++++-------------- 1 file changed, 99 insertions(+), 45 deletions(-) diff --git a/on-fail-handler.ts b/on-fail-handler.ts index 521d37c..44436df 100644 --- a/on-fail-handler.ts +++ b/on-fail-handler.ts @@ -1,71 +1,125 @@ -import * as diff from 'diff'; +import * as diff from 'diff' -type CypressError = Cypress.CypressError & { actual: string; expected: string }; -type Runner = Mocha.Runnable & { commands: { message: string }[] }; +type CypressError = Cypress.CypressError & { actual: string; expected: string } +type Runner = Mocha.Runnable & { commands: { message: string }[] } const color = { actual: '#cc3333', expected: '#008000', -}; +} -const formatValue = (value: unknown) => (typeof value === 'object' ? JSON.stringify(value, null, 2) : value); +const formatValue = (value: unknown) => + typeof value === 'object' ? JSON.stringify(value, null, 2) : value const insertCodeBlock = (value: string) => - `
${value}
`; + `
${value}
` const formatDiff = (part: Diff.Change) => - `${part.value}`; + `${part.value}` export function onFailHandler(error: CypressError, runnable: Runner) { - if (!error.actual) throw error; - if (!error.expected) throw error; - if (typeof error.actual === 'number') throw error; + if (!error.actual) throw error + if (!error.expected) throw error + if (typeof error.actual === 'number') throw error // @ts-expect-error - TODO: improve types - if (typeof error.actual === 'object' && error.actual.constructor.name === 'jQuery') throw error; - if (error.message.includes(' to contain text ')) throw error; + if (typeof error.actual === 'object' && error.actual.constructor.name === 'jQuery') + throw error + if (error.message.includes(' to contain text ')) throw error if (error.name === 'AssertionError') { - window.top!.document.querySelectorAll('.command-info').forEach((element) => { - const methodSpan = element.querySelector('.command-method > span'); - const messageElement = element.querySelector('.command-message-text'); - const errorMessage = runnable.commands[runnable.commands.length - 1]!.message; - const unboldedErrorMessage = errorMessage.replaceAll('**', ''); - const unboldedExpectedValueErrorMessage = errorMessage.replace(/\*\*([^*]+)\*\*/, '$1'); - const includesErrorMessage = (message: string) => messageElement?.textContent?.includes(message); + window + .top!.document.querySelectorAll('.command-info') + .forEach((element) => { + const methodSpan = element.querySelector('.command-method > span') + const messageElement = element.querySelector('.command-message-text') + if (messageElement) (messageElement as any).style.display = 'flex' + if (messageElement) (messageElement as any).style.flexWrap = 'wrap' + const errorMessage = + runnable.commands[runnable.commands.length - 1]!.message + const unboldedErrorMessage = errorMessage.replaceAll('**', '') + const unboldedExpectedValueErrorMessage = errorMessage.replace( + /\*\*([^*]+)\*\*/, + '$1' + ) + const includesErrorMessage = (message: string) => + messageElement?.textContent?.includes(message) + + if (methodSpan && methodSpan.textContent === 'assert') { + if ( + includesErrorMessage(errorMessage) || + includesErrorMessage(unboldedErrorMessage) || + includesErrorMessage(unboldedExpectedValueErrorMessage) + ) { + if (messageElement) { + methodSpan?.parentElement?.remove() - if (methodSpan && methodSpan.textContent === 'assert') { - if ( - includesErrorMessage(errorMessage) || - includesErrorMessage(unboldedErrorMessage) || - includesErrorMessage(unboldedExpectedValueErrorMessage) - ) { - if (messageElement) { - methodSpan?.parentElement?.remove(); + const actual = formatValue(error.actual) as string + const expected = formatValue(error.expected) as string - const actual = formatValue(error.actual) as string; - const expected = formatValue(error.expected) as string; + const diffResult = diff.diffChars(actual, expected) - const diffResult = diff.diffChars(actual, expected); + let actualFormatted = '' + let expectedFormatted = '' - let actualFormatted = ''; - let expectedFormatted = ''; + diffResult.forEach((part: Diff.Change) => { + const span = formatDiff(part) + actualFormatted += part.removed || !part.added ? span : '' + expectedFormatted += part.added || !part.removed ? span : '' + }) - diffResult.forEach((part: Diff.Change) => { - const span = formatDiff(part); - actualFormatted += part.removed || !part.added ? span : ''; - expectedFormatted += part.added || !part.removed ? span : ''; - }); + messageElement.innerHTML = ` +
+ +
+
Expected:${insertCodeBlock(expectedFormatted)}
+
Actual:${insertCodeBlock(actualFormatted)}
` + const block1 = window.top!.document.querySelector('#expected pre') + const block2 = window.top!.document.querySelector('#actual pre') + const toggleView = window.top!.document.querySelector( + '#controls #toggleView' + ) + const hasChanges = + window.top!.document.querySelectorAll('.haschanges') - messageElement.innerHTML = ` -
Expected:${insertCodeBlock(expectedFormatted)}
-
Actual:${insertCodeBlock(actualFormatted)}
`; + if (block1 && block2) { + block1.addEventListener('scroll', function () { + block2.scrollTop = block1.scrollTop + }) + block2.addEventListener('scroll', function () { + block1.scrollTop = block2.scrollTop + }) + } + toggleView?.addEventListener('click', function (e) { + e.preventDefault() + e.stopImmediatePropagation() + if ((messageElement as any).style.flexDirection === 'column') { + ;(messageElement as any).style.flexDirection = 'row' + toggleView?.setAttribute('style', 'transform: rotate(90deg);') + } else { + ;(messageElement as any).style.flexDirection = 'column' + toggleView?.setAttribute('style', 'transform: rotate(0deg);') + } + }) + if (hasChanges && hasChanges.length > 0) { + hasChanges?.[0]?.scrollIntoView({ block: 'center' }) + } + } } } - } - }); + }) } - throw error; + throw error }