diff --git a/README.md b/README.md index d03a8fd..e97e861 100644 --- a/README.md +++ b/README.md @@ -123,16 +123,22 @@ You can also specify a different destination folder for the generated HAR file b Alternatively, you can pass the `hars_folders` variable in the CLI using the `--env` option: ```bash -cypress run --browser chrome --env hars_folders=cypress/hars +$ cypress run --browser chrome --env hars_folders=cypress/hars ``` Finally, to start running your tests, use the following command: ```bash -cypress run --browser chrome +$ cypress run --browser chrome ``` -> ✴ Currently, only Chrome family browsers are supported. +> 🚧 Currently, only Chrome family browsers are supported. But this plugin also works with Electron, you just need to set the remote-debugging-port option when you launch Cypress as follows: +> +> ```bash +> $ ELECTRON_EXTRA_LAUNCH_ARGS=--remote-debugging-port=9222 cypress run --browser electron +> ``` +> +> Please refer to the [Electron documentation](https://www.electronjs.org/docs/latest/api/command-line-switches#--remote-debugging-portport) and the [Cypress documentation](https://docs.cypress.io/api/plugins/browser-launch-api#Modify-Electron-app-switches) for more information on how to properly configure this switch. ## Commands @@ -182,7 +188,7 @@ For example, to only include requests that have a status code of 400 or greater, cy.recordHar({ minStatusCodeToInclude: 400 }); ``` -> As of version 6, this option will be removed. Use `excludeStatusCodes` instead. +> ✴ As of version 6, this option will be removed. Use `excludeStatusCodes` instead. Alternatively, you can have more granular control over the requests to exclude by passing an array of status codes you want to exclude from the recorded HAR file. @@ -190,7 +196,7 @@ Alternatively, you can have more granular control over the requests to exclude b cy.recordHar({ excludeStatusCodes: [200, 201, 204] }); ``` -> Please note that both options `minStatusCodeToInclude` and `excludeStatusCodes` are mutually exclusive. +> ⚠ Please note that both options `minStatusCodeToInclude` and `excludeStatusCodes` are mutually exclusive. By default, when you use `recordHar` command, it will include the blob requests in the recorded HAR file. However, those requests only make sense when they are used on the same page they were created. To exclude the blob requests from the recorded HAR file, set the `includeBlobs` to false as follows: @@ -309,7 +315,7 @@ module.exports = defineConfig({ }); ``` -> Please note, to utilize this experimental mechanism for setting up lifecycle, you must either disable the interactive mode or enable the "experimentalInteractiveRunEvents" feature. For more details, see the documentation: https://docs.cypress.io/guides/references/experiments#Configuration +> ⚠ Please note, to utilize this experimental mechanism for setting up lifecycle, you must either disable the interactive mode or enable the "experimentalInteractiveRunEvents" feature. For more details, see the documentation: https://docs.cypress.io/guides/references/experiments#Configuration ## License diff --git a/package.json b/package.json index e195bbc..7e9a38f 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "keywords": [ "cypress", "har", + "electron", "cypress-plugin", "chrome", "http-archive", diff --git a/src/Plugin.spec.ts b/src/Plugin.spec.ts index 0875895..eac066a 100644 --- a/src/Plugin.spec.ts +++ b/src/Plugin.spec.ts @@ -11,6 +11,7 @@ import { match, mock, reset, + spy, verify, when } from 'ts-mockito'; @@ -99,11 +100,21 @@ describe('Plugin', () => { const connectionFactoryMock = mock(); const connectionMock = mock(); const writableStreamMock = mock(); + const processEnv = process.env; let plugin!: Plugin; + let processSpy!: NodeJS.Process; beforeEach(() => { + processSpy = spy(process); + + when(processSpy.env).thenReturn({ + ...processEnv, + ELECTRON_EXTRA_LAUNCH_ARGS: '' + }); + useFakeTimers(); + plugin = new Plugin( instance(loggerMock), instance(fileManagerMock), @@ -115,6 +126,7 @@ describe('Plugin', () => { afterEach(() => { jest.useRealTimers(); reset< + | NodeJS.Process | Logger | FileManager | Connection @@ -123,6 +135,7 @@ describe('Plugin', () => { | ObserverFactory | Observer >( + processSpy, loggerMock, fileManagerMock, connectionMock, @@ -173,6 +186,38 @@ describe('Plugin', () => { `An unsupported browser family was used: ${browser.name}` ); }); + + it('should throw an error when Electron is used and switches are missed', () => { + // arrange + const browser = { + family: 'chromium', + name: 'electron' + } as Cypress.Browser; + const args: string[] = []; + // act + const act = () => plugin.ensureBrowserFlags(browser, args); + // assert + expect(act).toThrowError( + `Missing '--remote-debugging-port' command line switch for Electron browser` + ); + }); + + it('should extract --remote-debugging-port from ELECTRON_EXTRA_LAUNCH_ARGS env variable', () => { + // arrange + const browser = { + family: 'chromium', + name: 'electron' + } as Cypress.Browser; + const args: string[] = []; + when(processSpy.env).thenReturn({ + ...processEnv, + ELECTRON_EXTRA_LAUNCH_ARGS: '--remote-debugging-port=9090' + }); + // act + const result = plugin.ensureBrowserFlags(browser, args); + // assert + expect(result).toEqual([]); + }); }); describe('saveHar', () => { diff --git a/src/Plugin.ts b/src/Plugin.ts index 839abb5..2241de8 100644 --- a/src/Plugin.ts +++ b/src/Plugin.ts @@ -3,11 +3,11 @@ import { Connection, ConnectionFactory, RetryStrategy } from './cdp'; import { EntryBuilder, HarBuilder, + NetworkIdleMonitor, + NetworkObserverOptions, NetworkRequest, Observer, - NetworkObserverOptions, - ObserverFactory, - NetworkIdleMonitor + ObserverFactory } from './network'; import { join } from 'path'; import { WriteStream } from 'fs'; @@ -61,11 +61,17 @@ export class Plugin { ); } - const browserFlags: string[] = this.ensureRdpAddrArgs( - this.ensureTestingFlags(args) - ); + const electronUsed = browser.name === 'electron'; + + if (electronUsed) { + args = this.parseElectronSwitches(browser); + } - return browserFlags.filter((x: string): boolean => !args.includes(x)); + const browserFlags: string[] = this.ensureRdpAddrArgs(args); + + return electronUsed + ? [] + : browserFlags.filter((x: string): boolean => !args.includes(x)); } public async recordHar(options: RecordOptions): Promise { @@ -130,6 +136,25 @@ export class Plugin { return null; } + private parseElectronSwitches(browser: Cypress.Browser): string[] { + if ( + !process.env.ELECTRON_EXTRA_LAUNCH_ARGS?.includes(this.PORT_OPTION_NAME) + ) { + this.logger + .err(`The '${browser.name}' browser was detected, however, the required '${this.PORT_OPTION_NAME}' command line switch was not provided. + This switch is necessary to enable remote debugging over HTTP on the specified port. + + Please refer to the documentation: + - https://www.electronjs.org/docs/latest/api/command-line-switches#--remote-debugging-portport + - https://docs.cypress.io/api/plugins/browser-launch-api#Modify-Electron-app-switches`); + throw new Error( + `Missing '${this.PORT_OPTION_NAME}' command line switch for Electron browser` + ); + } + + return process.env.ELECTRON_EXTRA_LAUNCH_ARGS.split(' '); + } + private async buildHar(): Promise { if (this.tmpPath) { const content = await this.fileManager.readFile(this.tmpPath); @@ -187,17 +212,6 @@ export class Plugin { return ['chromium'].includes(browser?.family); } - private ensureTestingFlags(args: string[]): string[] { - return [ - ...args, - '--no-sandbox', - '--disable-background-networking', - '--reduce-security-for-testing', - '--allow-insecure-localhost', - '--ignore-certificate-errors' - ]; - } - private ensureRdpAddrArgs(args: string[]): string[] { const { host = 'localhost',