-
Notifications
You must be signed in to change notification settings - Fork 1
Bring master up to develop: retry-poisoning fix and the Cypress 15 toolchain #124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| /** | ||
| * Records what the application under test copies, without depending on the OS clipboard. | ||
| * | ||
| * Chromium 138 (the Electron bundled with Cypress 15) requires transient user activation for both | ||
| * `navigator.clipboard.writeText()` and `document.execCommand('copy')`, and a Cypress-synthesized | ||
| * click provides none. So Kibana's copy buttons no longer reach the real clipboard and | ||
| * `readText()` resolves to an empty string. Both copy paths are therefore intercepted here, and | ||
| * `cy.getValueFromClipboard()` reads what was captured. | ||
| * | ||
| * Kibana's share panel copies through EUI's `copyToClipboard`, which never calls `writeText`: it | ||
| * stages the text in a hidden element, selects it, and calls `execCommand('copy')`. When Chromium | ||
| * suppresses that command it also stops dispatching the `copy` event — and that event is where | ||
| * ROR's own ClipboardInterception (proxy/preKibanaProxy/injection/scripts/tenancyContext) appends | ||
| * the tenancy parameter. Simply reading the staged selection would therefore bypass the very | ||
| * feature the tenancy specs assert on, so a synthetic copy event is dispatched instead: it bubbles | ||
| * through ROR's genuine handler, which enriches onto it, and the enriched value is what we record. | ||
| */ | ||
|
|
||
| /** | ||
| * Holds the text most recently copied by the application under test. | ||
| * | ||
| * Exported as a live object rather than a value on purpose: `cy.wrap(capture).its('text')` re-reads | ||
| * the property on every retry, so an assertion still passes when the copy lands a moment after the | ||
| * command was queued. Wrapping a plain string would freeze it at queue time. | ||
| */ | ||
| export const capture = { text: '' }; | ||
|
|
||
| /** A test must never pass on a value some earlier test copied. */ | ||
| export const resetClipboardCapture = (): void => { | ||
| capture.text = ''; | ||
| }; | ||
|
|
||
| /** Records every `navigator.clipboard.writeText`, whether or not the real write is permitted. */ | ||
| const wrapWriteText = (win: Cypress.AUTWindow): void => { | ||
| const { clipboard } = win.navigator; | ||
| const originalWriteText = clipboard.writeText.bind(clipboard); | ||
|
|
||
| clipboard.writeText = (text: string) => { | ||
| capture.text = String(text); | ||
| return originalWriteText(text).catch(() => undefined); | ||
| }; | ||
| }; | ||
|
|
||
| /** The text an `execCommand('copy')` would have put on the clipboard, had it been permitted. */ | ||
| const stagedSelection = (win: Cypress.AUTWindow): string => { | ||
| const active = win.document.activeElement as HTMLInputElement | HTMLTextAreaElement | null; | ||
| const isTextEntry = active !== null && (active.tagName === 'TEXTAREA' || active.tagName === 'INPUT'); | ||
| const inputSelection = isTextEntry | ||
| ? (active.value ?? '').substring(active.selectionStart ?? 0, active.selectionEnd ?? active.value.length) | ||
| : ''; | ||
|
|
||
| return inputSelection || (win.getSelection()?.toString() ?? ''); | ||
| }; | ||
|
|
||
| /** Runs the page's own `copy` handlers, and returns whatever they wrote to the event. */ | ||
| const enrichedByPageHandlers = (win: Cypress.AUTWindow): string => { | ||
| const dataTransfer = new win.DataTransfer(); | ||
| const syntheticCopy = new win.ClipboardEvent('copy', { | ||
| clipboardData: dataTransfer, | ||
| bubbles: true, | ||
| cancelable: true | ||
| }); | ||
|
|
||
| (win.document.activeElement ?? win.document).dispatchEvent(syntheticCopy); | ||
|
|
||
| return dataTransfer.getData('text/plain'); | ||
| }; | ||
|
|
||
| /** Records every `execCommand('copy')`, preferring what the page's own handlers produced. */ | ||
| const wrapExecCommandCopy = (win: Cypress.AUTWindow): void => { | ||
| const doc = win.document; | ||
| const originalExecCommand = doc.execCommand.bind(doc); | ||
|
|
||
| doc.execCommand = (commandId: string, showUI?: boolean, value?: string) => { | ||
| const result = originalExecCommand(commandId, showUI, value); | ||
|
|
||
| if (commandId === 'copy') { | ||
| const copied = enrichedByPageHandlers(win) || stagedSelection(win); | ||
| if (copied) { | ||
| capture.text = copied; | ||
| } | ||
| } | ||
|
|
||
| return result; | ||
| }; | ||
| }; | ||
|
|
||
| export const installClipboardCapture = (win: Cypress.AUTWindow): void => { | ||
| wrapWriteText(win); | ||
| wrapExecCommandCopy(win); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🌐 Web query:
For Cypress 15.20.1, what supported API can an uncaught:exception handler use to distinguish an afterEach teardown hook from normal test execution?💡 Result:
In Cypress 15.20.1, the
uncaught:exceptionevent provides arunnableobject as the second argument to its handler callback [1]. To distinguish whether an error occurred during normal test execution versus anafterEach(or any other) hook, you can inspect thisrunnableobject [1]. Therunnableobject is a Mocha object that represents the current unit of execution [2][1]. You can inspect the properties of therunnableinstance to determine the context: 1. runnable.type: This property generally identifies the type of execution block (e.g., 'test' or 'hook'). 2. runnable.title: This property contains the name of the test or the hook (e.g., 'after each hook'). By checking these properties, you can conditionally handle the exception: cy.on('uncaught:exception', (err, runnable) => { if (runnable.type === 'hook' && runnable.title.includes('after each')) { // Logic specifically for afterEach teardown hooks return false; // Prevent Cypress from failing the test } // Normal test execution or other hook logic return true; // Default Cypress behavior (fail the test) }); This approach leverages the standard Mocharunnableobject provided by Cypress [1], allowing for granular control over how uncaught exceptions are managed based on the specific phase of the test lifecycle [3].Citations:
🤖 get_repo_knowledge executed:
get_repo_knowledge beshu-tech/readonlyrest-e2e-tests /tmp/coderabbit-repo-knowledge/beshu-tech-readonlyrest-e2e-tests-e54ace1aLength of output: 422
🏁 Script executed:
Repository: beshu-tech/readonlyrest-e2e-tests
Length of output: 30626
🌐 Web query:
site:docs.cypress.io/api/cypress-api/catalog-of-events uncaught:exception promise runnable Cypress💡 Result:
In Cypress, the uncaught:exception event is triggered when an uncaught exception (or an unhandled promise rejection) occurs within your application [1]. By default, Cypress fails the test when this event fires [1]. To prevent a test from failing due to an uncaught exception, you can listen to this event and return false from the callback function [1]. Event Signature The event callback receives three arguments: 1. err: The error object [1]. 2. runnable: The Mocha runnable object (the test or suite currently running) [1]. 3. promise: The promise that rejected, if the exception originated from an unhandled promise rejection [1]. Implementation Example To ignore specific uncaught exceptions or handle unhandled promise rejections, you can use the following pattern in your support file or test: Cypress.on('uncaught:exception', (err, runnable, promise) => { // Check if the error originated from an unhandled promise rejection if (promise) { // Return false to prevent Cypress from failing the test return false; } // Optionally, perform custom logic or return false for specific error messages if (err.message.includes('expected error message')) { return false; } // Returning nothing (or anything other than false) will allow // Cypress to continue failing the test for other unexpected errors }) Important Considerations - Global Scope: If you define this listener in your support file, it will apply globally to all tests [1]. - cy.origin: If an uncaught exception occurs within a cy.origin command, the exception handler must be defined inside that cy.origin block to take effect [1]. - Debugging: While returning false prevents test failure, it is generally recommended to only suppress exceptions you explicitly expect, as this helps maintain the reliability of your test suite [1].
Citations:
Limit gateway rejection suppression to teardown.
The global
Cypress.on('uncaught:exception')handler returnsfalsefor any unhandled rejection with these messages. An unrelated rejection during normal test execution can therefore pass without failing the test. Use the suppliedrunnablecontext, an explicit teardown state, or a stable request-source check.🤖 Prompt for AI Agents