-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: move main tab activation to puppeteer plugin (#28898)
* fix: move main tab activation to puppeteer plugin * tests for new url functionality in v3 extension * tests for activateMainTab * tests * cleanup * add troubleshooting to puppeteer plugin readme re: chrome extension * changelog * no longer attempts to activate main tab in run mode * Update npm/puppeteer/README.md Co-authored-by: Jennifer Shehane <[email protected]> * Update cli/CHANGELOG.md Co-authored-by: Jennifer Shehane <[email protected]> --------- Co-authored-by: Jennifer Shehane <[email protected]>
- Loading branch information
1 parent
1f0a9d5
commit ed2fc13
Showing
19 changed files
with
639 additions
and
359 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/// <reference lib="browser"> | ||
import type { Browser } from 'puppeteer-core' | ||
|
||
export const ACTIVATION_TIMEOUT = 2000 | ||
|
||
const sendActivationMessage = (activationTimeout: number) => { | ||
// don't need to worry about tabs for Cy in Cy tests | ||
if (document.defaultView !== top) { | ||
return | ||
} | ||
|
||
let timeout: NodeJS.Timeout | ||
let onMessage: (ev: MessageEvent) => void | ||
|
||
// promise must resolve with a value for chai as promised to test resolution | ||
return new Promise<void>((resolve, reject) => { | ||
onMessage = (ev) => { | ||
if (ev.data.message === 'cypress:extension:main:tab:activated') { | ||
window.removeEventListener('message', onMessage) | ||
clearTimeout(timeout) | ||
resolve() | ||
} | ||
} | ||
|
||
window.addEventListener('message', onMessage) | ||
window.postMessage({ message: 'cypress:extension:activate:main:tab' }) | ||
|
||
timeout = setTimeout(() => { | ||
window.removeEventListener('message', onMessage) | ||
reject() | ||
}, activationTimeout) | ||
}) | ||
} | ||
|
||
export const activateMainTab = async (browser: Browser) => { | ||
// - 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 | ||
const [page] = await browser.pages() | ||
|
||
if (page) { | ||
return page.evaluate(sendActivationMessage, ACTIVATION_TIMEOUT) | ||
} | ||
} |
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,118 @@ | ||
import { expect, use } from 'chai' | ||
import chaiAsPromised from 'chai-as-promised' | ||
import sinon from 'sinon' | ||
import sinonChai from 'sinon-chai' | ||
import type { Browser, Page } from 'puppeteer-core' | ||
import { activateMainTab, ACTIVATION_TIMEOUT } from '../../src/plugin/activateMainTab' | ||
|
||
use(chaiAsPromised) | ||
use(sinonChai) | ||
|
||
describe('activateMainTab', () => { | ||
let clock: sinon.SinonFakeTimers | ||
let prevWin: Window | ||
let prevDoc: Document | ||
let prevTop: Window & typeof globalThis | ||
let window: Partial<Window> | ||
let mockDocument: Partial<Document> & { | ||
defaultView: Window & typeof globalThis | ||
} | ||
let mockTop: Partial<Window & typeof globalThis> | ||
let mockBrowser: Partial<Browser> | ||
let mockPage: Partial<Page> | ||
|
||
beforeEach(() => { | ||
clock = sinon.useFakeTimers() | ||
|
||
window = { | ||
addEventListener: sinon.stub(), | ||
removeEventListener: sinon.stub(), | ||
|
||
// @ts-ignore sinon gets confused about postMessage type declaration | ||
postMessage: sinon.stub(), | ||
} | ||
|
||
mockDocument = { | ||
defaultView: window as Window & typeof globalThis, | ||
} | ||
|
||
mockTop = mockDocument.defaultView | ||
|
||
// activateMainTab is eval'd in browser context, but the tests exec in a | ||
// node context. We don't necessarily need to do this swap, but it makes the | ||
// tests more portable. | ||
// @ts-ignore | ||
prevWin = global.window | ||
prevDoc = global.document | ||
// @ts-ignore | ||
prevTop = global.top | ||
//@ts-ignore | ||
global.window = window | ||
global.document = mockDocument as Document | ||
//@ts-ignore | ||
global.top = mockTop | ||
|
||
mockPage = { | ||
evaluate: sinon.stub().callsFake((fn, ...args) => fn(...args)), | ||
} | ||
|
||
mockBrowser = { | ||
pages: sinon.stub(), | ||
} | ||
}) | ||
|
||
afterEach(() => { | ||
clock.restore() | ||
// @ts-ignore | ||
global.window = prevWin | ||
// @ts-ignore | ||
global.top = prevTop | ||
global.document = prevDoc | ||
}) | ||
|
||
it('sends a tab activation request to the plugin, and resolves when the ack event is received', async () => { | ||
const pagePromise = Promise.resolve([mockPage]) | ||
|
||
;(mockBrowser.pages as sinon.SinonStub).returns(pagePromise) | ||
const p = activateMainTab(mockBrowser as Browser) | ||
|
||
await pagePromise | ||
// @ts-ignore | ||
window.addEventListener.withArgs('message').yield({ data: { message: 'cypress:extension:main:tab:activated' } }) | ||
expect(window.postMessage).to.be.calledWith({ message: 'cypress:extension:activate:main:tab' }) | ||
|
||
expect(p).to.eventually.be.true | ||
}) | ||
|
||
it('sends a tab activation request to the plugin, and rejects if it times out', async () => { | ||
const pagePromise = Promise.resolve([mockPage]) | ||
|
||
;(mockBrowser.pages as sinon.SinonStub).returns(pagePromise) | ||
await pagePromise | ||
|
||
const p = activateMainTab(mockBrowser as Browser) | ||
|
||
clock.tick(ACTIVATION_TIMEOUT + 1) | ||
|
||
expect(p).to.be.rejected | ||
}) | ||
|
||
describe('when cy in cy', () => { | ||
beforeEach(() => { | ||
mockDocument.defaultView = {} as Window & typeof globalThis | ||
}) | ||
|
||
it('does not try to send tab activation message', async () => { | ||
const pagePromise = Promise.resolve([mockPage]) | ||
|
||
;(mockBrowser.pages as sinon.SinonStub).returns(pagePromise) | ||
|
||
const p = activateMainTab(mockBrowser as Browser) | ||
|
||
await pagePromise | ||
expect(window.postMessage).not.to.be.called | ||
expect(window.addEventListener).not.to.be.called | ||
await p | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.
ed2fc13
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.
Circle has built the
linux arm64
version of the Test Runner.Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version
Run this command to install the pre-release locally:
ed2fc13
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.
Circle has built the
linux x64
version of the Test Runner.Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version
Run this command to install the pre-release locally:
ed2fc13
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.
Circle has built the
darwin x64
version of the Test Runner.Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version
Run this command to install the pre-release locally:
ed2fc13
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.
Circle has built the
darwin arm64
version of the Test Runner.Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version
Run this command to install the pre-release locally:
ed2fc13
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.
Circle has built the
win32 x64
version of the Test Runner.Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version
Run this command to install the pre-release locally: