Skip to content

Commit

Permalink
feat(plugin): allow controlling the time to wait for idle network (#186)
Browse files Browse the repository at this point in the history
You can pass the `waitForIdle` option to wait for all pending requests
to complete before saving the HAR file:

```js
cy.saveHar({ waitForIdle: true });
```

This option is false by default. When set to true, the plugin will
monitor the count of pending requests and wait for it to reach zero
before proceeding with saving the HAR file. This ensures that all
responses have been received and the data in the file is complete and
accurate.

Additionally, you can pass the `maxWaitDuration` option to specify the
maximum time to wait for the pending requests to complete:

```js
cy.saveHar({ waitForIdle: true, maxWaitDuration: 20000 });
```

The `maxWaitDuration` option is set to 5000 milliseconds by default,
meaning it will wait for 5 seconds until all pending requests have
completed.

You can also pass the `minIdleDuration` option to specify the minimum
duration in milliseconds to wait for the network idle during the
`maxWaitDuration` time. The network is idle if there are no pending requests during this
time.

```js
cy.saveHar({ waitForIdle: true, minIdleDuration: 1000 });
```

The `minIdleDuration` option is set to 100 milliseconds by default.

closes #185
  • Loading branch information
derevnjuk committed Feb 3, 2023
1 parent a909821 commit 409c772
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 14 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,22 @@ cy.saveHar({ waitForIdle: true });
This option is false by default. When set to true, the plugin will monitor the count of pending requests and wait for it to reach zero before proceeding with saving the HAR file. This ensures that all responses have been received and the data in the file is complete and accurate.
Additionally, you can pass the `maxWaitDuration` option to specify the maximum time to wait for the pending requests to complete:
```js
cy.saveHar({ waitForIdle: true, maxWaitDuration: 20000 });
```
The `maxWaitDuration` option is set to 5000 milliseconds by default, meaning it will wait for 5 seconds until all pending requests have completed.
You can also pass the `minIdleDuration` option to specify the minimum duration in milliseconds to wait for the network idle during the `maxWaitDuration` time. The network is idle if there are no pending requests during this time.
```js
cy.saveHar({ waitForIdle: true, minIdleDuration: 1000 });
```
The `minIdleDuration` option is set to 100 milliseconds by default.
### disposeOfHar
Stops the ongoing recording of network requests and disposes of the recorded logs, which will be not saved to a HAR file.
Expand Down
23 changes: 16 additions & 7 deletions src/Plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ import { FileManager } from './utils/FileManager';
import type {
HarExporter,
HarExporterFactory,
HarExporterOptions,
NetworkObserverOptions,
Observer,
ObserverFactory,
HarExporterOptions
ObserverFactory
} from './network';
import { HarBuilder, NetworkIdleMonitor, NetworkRequest } from './network';
import { ErrorUtils } from './utils/ErrorUtils';
import type { Connection, ConnectionFactory } from './cdp';
import {
ADDRESS_OPTION_NAME,
MAX_NETWORK_IDLE_THRESHOLD,
MAX_NETWORK_IDLE_DURATION,
PORT_OPTION_NAME,
SUPPORTED_BROWSERS
} from './constants';
Expand All @@ -24,6 +26,8 @@ export interface SaveOptions {
fileName: string;
outDir: string;
waitForIdle?: boolean;
minIdleDuration?: number;
maxWaitDuration?: number;
}

export type RecordOptions = NetworkObserverOptions & HarExporterOptions;
Expand Down Expand Up @@ -105,7 +109,7 @@ export class Plugin {
await this.fileManager.createFolder(options.outDir);

if (options.waitForIdle) {
await this.waitForNetworkIdle();
await this.waitForNetworkIdle(options);
}

const har: string | undefined = await this.buildHar();
Expand Down Expand Up @@ -171,14 +175,19 @@ Please refer to the documentation:
}

private async waitForNetworkIdle(
options: { idleTime?: number; timeout?: number } = {}
options: Pick<SaveOptions, 'minIdleDuration' | 'maxWaitDuration'>
): Promise<void> {
const { idleTime = 100, timeout = 5000 } = options;
const cancellation = promisify(setTimeout)(timeout);
const {
minIdleDuration = MAX_NETWORK_IDLE_THRESHOLD,
maxWaitDuration = MAX_NETWORK_IDLE_DURATION
} = options;
const cancellation = promisify(setTimeout)(maxWaitDuration);

return Promise.race([
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
new NetworkIdleMonitor(this.networkObservable!).waitForIdle(idleTime),
new NetworkIdleMonitor(this.networkObservable!).waitForIdle(
minIdleDuration
),
cancellation
]);
}
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const PORT_OPTION_NAME = '--remote-debugging-port';
export const ADDRESS_OPTION_NAME = '--remote-debugging-address';
export const SUPPORTED_BROWSERS: readonly string[] = ['chromium'];
export const MAX_NETWORK_IDLE_THRESHOLD = 100;
export const MAX_NETWORK_IDLE_DURATION = 5000;
16 changes: 9 additions & 7 deletions src/network/NetworkObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class NetworkObserver implements Observer<NetworkRequest> {
Protocol.Network.RequestId,
ExtraInfoBuilder
>;
private destination?: (chromeEntry: NetworkRequest) => void;
private destination?: (chromeEntry: NetworkRequest) => unknown;

get empty(): boolean {
return this._entries.size === 0;
Expand All @@ -34,9 +34,9 @@ export class NetworkObserver implements Observer<NetworkRequest> {
}

public async subscribe(
callback: (chromeEntry: NetworkRequest) => void
callback: (chromeEntry: NetworkRequest) => unknown
): Promise<void> {
this.destination = (entry: NetworkRequest): void => callback(entry);
this.destination = callback;

await this.network.attachToTargets((event: NetworkEvent): void =>
this.handleEvent(event)
Expand Down Expand Up @@ -427,10 +427,12 @@ export class NetworkObserver implements Observer<NetworkRequest> {
this.loadContent(networkRequest);

this.getExtraInfoBuilder(networkRequest.requestId).finished();
this._entries.delete(networkRequest.requestId);

if (!this.excludeRequest(networkRequest)) {
this.destination?.(networkRequest);
if (!this.shouldExcludeRequest(networkRequest)) {
networkRequest
.waitForCompletion()
.then(() => this.destination?.(networkRequest))
.finally(() => this._entries.delete(networkRequest.requestId));
}
}

Expand Down Expand Up @@ -555,7 +557,7 @@ export class NetworkObserver implements Observer<NetworkRequest> {
);
}

private excludeRequest(request: NetworkRequest): boolean {
private shouldExcludeRequest(request: NetworkRequest): boolean {
return this.requestFilter?.wouldApply(this.options)
? !this.requestFilter.apply(request, this.options)
: false;
Expand Down
4 changes: 4 additions & 0 deletions src/network/NetworkRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,10 @@ export class NetworkRequest {
this.url = url;
}

public async waitForCompletion(): Promise<void> {
await Promise.all([this._contentData, this._formParametersPromise]);
}

public isBlob(): boolean {
return this._url.startsWith('blob:');
}
Expand Down

0 comments on commit 409c772

Please sign in to comment.