-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
misc: Ensure cypress tab is active before any command runs #28334
Merged
Merged
Changes from 7 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
32f86e9
misc: ensure cypress tab is active before any command runs
chrisbreiding 21aa986
Merge remote-tracking branch 'origin/develop' into crb/cy-puppeteer-r…
chrisbreiding d12192f
add changelog entry
chrisbreiding 44c6b0d
update changelog
chrisbreiding 997afc0
fix using Cypress.isBrowser with non-string value
chrisbreiding 2bdf094
update extension descriptions
chrisbreiding b970b3a
extract tab activation handling and skip if browser is headless
chrisbreiding c60f34e
Merge remote-tracking branch 'origin/develop' into crb/cy-puppeteer-r…
chrisbreiding 4846848
apply feedback
chrisbreiding 639b6d0
scope activated message
chrisbreiding 86f7f06
don't await tab activation for cy-in-cy tests
chrisbreiding 6a2c979
fix test
chrisbreiding 590cb20
fix tests
chrisbreiding a6542ab
Merge remote-tracking branch 'origin/develop' into crb/cy-puppeteer-r…
chrisbreiding 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 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 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 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 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 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 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 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 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,43 @@ | ||
import type { ICypress } from '../cypress' | ||
|
||
function activateMainTab () { | ||
// Don't need to activate the main tab if it already has focus | ||
if (document.hasFocus()) return | ||
|
||
return new Promise<void>((resolve) => { | ||
const url = `${window.location.origin}${window.location.pathname}` | ||
|
||
// This sends a message on the window that the extension content script | ||
// listens for in order to carry out activating the main tab | ||
window.postMessage({ message: 'extension:activate:main:tab', url }, '*') | ||
mschile marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
function onMessage ({ data, source }) { | ||
// only accept messages from ourself | ||
if (source !== window) return | ||
|
||
if (data.message === 'main:tab:activated') { | ||
mschile marked this conversation as resolved.
Show resolved
Hide resolved
|
||
window.removeEventListener('message', onMessage) | ||
|
||
resolve() | ||
} | ||
} | ||
|
||
// The reply from the extension comes back via the same means, a message | ||
// sent on the window | ||
window.addEventListener('message', onMessage) | ||
}) | ||
} | ||
|
||
// Ensures the main Cypress tab has focus before every command | ||
// and at the end of the test run | ||
export function handleTabActivation (Cypress: ICypress) { | ||
// - Only implemented for Chromium right now. Support for Firefox/webkit | ||
// could be added later | ||
// - Electron doesn't have tabs | ||
// - Focus doesn't matter for headless browsers and old headless Chrome | ||
// doesn't run the extension | ||
if (!Cypress.isBrowser({ family: 'chromium', name: '!electron', isHeadless: false })) return | ||
|
||
Cypress.on('command:start:async', activateMainTab) | ||
Cypress.on('test:after:run:async', activateMainTab) | ||
} |
This file contains 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 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 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,32 @@ | ||
/* global chrome, window */ | ||
|
||
// this content script has access to the DOM, but is otherwise isolated from | ||
// the page running Cypress, so we have to use postMessage to communicate. it | ||
// also doesn't have direct access to the extension API, so we use the | ||
// messaging API it can access to communicate with the background service | ||
// worker script. so essentially, it's an intermediary between Cypress and | ||
// the extension background script | ||
const port = chrome.runtime.connect() | ||
|
||
// this listens for messages from the main window that Cypress runs on. it's | ||
// a very global message bus, so messages could come from a variety of sources | ||
window.addEventListener('message', ({ data, source }) => { | ||
// only accept messages from ourself | ||
if (source !== window) return | ||
|
||
// this is the only message we're currently interested in, which tells us | ||
// to activate the main tab | ||
if (data.message === 'extension:activate:main:tab') { | ||
port.postMessage({ message: 'activate:main:tab', url: data.url }) | ||
} | ||
}) | ||
|
||
// this listens for messages from the background service worker script | ||
port.onMessage.addListener(({ message }) => { | ||
// this lets us know the message we sent to the background script to activate | ||
// the main tab was successful, so we in turn send it on to Cypress | ||
// via postMessage | ||
if (message === 'main:tab:activated') { | ||
window.postMessage({ message }, '*') | ||
} | ||
}) |
This file contains 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 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,45 @@ | ||
/* global chrome */ | ||
|
||
// this background script runs in a service worker. it has access to the | ||
// extension API, but not direct access the web page or anything else | ||
// running in the browser | ||
|
||
// to debug this script, go to `chrome://inspect` in a new Chrome tab, | ||
// select Service Workers on the left and click `inspect`. to reload changes | ||
// go to `chrome://extensions` and hit the reload button under the Cypress | ||
// extension. sometimes that doesn't work and requires re-launching Chrome | ||
// and then reloading the extension via `chrome://extensions` | ||
|
||
async function activateMainTab (url) { | ||
try { | ||
const tabs = await chrome.tabs.query({}) | ||
|
||
const cypressTab = tabs.find((tab) => tab.url.includes(url)) | ||
|
||
if (!cypressTab) return | ||
|
||
// this brings the main Cypress tab to the front of any other tabs | ||
// without Chrome stealing focus from other running apps | ||
await chrome.tabs.update(cypressTab.id, { active: true }) | ||
} catch (err) { | ||
// ignore the error but log it. these logs only appear if you inspect | ||
// the service worker, so it won't clutter up the console for users | ||
|
||
// eslint-disable-next-line no-console | ||
console.log('Activating main tab errored:', err) | ||
mschile marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
// here we connect to the content script, which has access to the web page | ||
// running Cypress, but not the extension API | ||
chrome.runtime.onConnect.addListener((port) => { | ||
port.onMessage.addListener(async ({ message, url }) => { | ||
if (message === 'activate:main:tab') { | ||
await activateMainTab(url) | ||
|
||
// send an ack back to let the content script know we successfully | ||
// activated the main tab | ||
port.postMessage({ message: 'main:tab:activated' }) | ||
mschile marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
}) | ||
}) |
This file contains 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 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.
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.
This is a bit of a drive-by fix that I needed for the browser check. I didn't see any open issues about this, but it does seem like it wasn't working as documented, where
Cypress.isBrowser({ isHeadless: true })
would fail with "startsWith is not a function".