Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/browser/commands/restoreState/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { getActivePuppeteerPage } from "../../existing-browser";
import { Cookie } from "@testplane/wdio-protocols";

export type RestoreStateOptions = SaveStateOptions & {
export type RestoreStateOptions = Omit<SaveStateOptions, "keepFile"> & {
data?: SaveStateData;
refresh?: boolean;
};
Expand Down
24 changes: 22 additions & 2 deletions src/browser/commands/saveState/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ExistingBrowser, getActivePuppeteerPage } from "../../existing-browser"
import * as logger from "../../../utils/logger";
import { Cookie } from "../../../types";
import type { Browser } from "../../types";
import { MasterEvents } from "../../../events";

export type SaveStateOptions = {
path?: string;
Expand All @@ -16,6 +17,7 @@ export type SaveStateOptions = {
sessionStorage?: boolean;

cookieFilter?: (cookie: Cookie) => boolean;
keepFile?: boolean;
};

export type FrameData = StorageData;
Expand All @@ -29,6 +31,7 @@ export const defaultOptions = {
cookies: true,
localStorage: true,
sessionStorage: true,
keepFile: false,
};

// in case when we use webdriver protocol, bidi and isolation
Expand Down Expand Up @@ -178,8 +181,25 @@ export default (browser: ExistingBrowser): void => {
data.cookies = data.cookies.filter(options.cookieFilter);
}

if (options && options.path) {
await fs.writeJson(options.path, data, { spaces: 2 });
const dataIsEmpty = data.cookies?.length === 0 && _.isEmpty(data.framesData);

if (options && options.path && !dataIsEmpty) {
await fs.outputJson(options.path, data, { spaces: 2 });

if (options.keepFile) {
logger.warn(
"\x1b[31mPlease be aware that the file containing authorization data will not be automatically deleted after the tests are completed!!!\x1b[0m",
);
} else {
if (process.send) {
process.send({
event: MasterEvents.ADD_FILE_TO_REMOVE,
data: options.path,
});
}

browser.emitter.emit(MasterEvents.ADD_FILE_TO_REMOVE, options.path);
}
}

return data;
Expand Down
13 changes: 12 additions & 1 deletion src/browser/standalone/attachToBrowser.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Config } from "../../config";
import { ExistingBrowser } from "./../existing-browser";
import { Calibrator } from "./../calibrator";
import { AsyncEmitter } from "../../events";
import { AsyncEmitter, MasterEvents } from "../../events";
import { BrowserName, type W3CBrowserName, type SessionOptions } from "./../types";
import { getNormalizedBrowserName } from "../../utils/browser";
import fs from "fs-extra";

export async function attachToBrowser(session: SessionOptions): Promise<WebdriverIO.Browser> {
const browserName = session.sessionCaps?.browserName || BrowserName.CHROME;
Expand All @@ -24,6 +25,8 @@ export async function attachToBrowser(session: SessionOptions): Promise<Webdrive
},
};

const filesToRemove: string[] = [];

const config = new Config({
browsers: {
[browserName]: browserConfig,
Expand All @@ -36,6 +39,10 @@ export async function attachToBrowser(session: SessionOptions): Promise<Webdrive

const emitter = new AsyncEmitter();

emitter.on(MasterEvents.ADD_FILE_TO_REMOVE, (path: string) => {
filesToRemove.push(path);
});

const existingBrowser = new ExistingBrowser(config, {
id: browserName,
version: session.sessionCaps?.browserVersion,
Expand All @@ -54,6 +61,10 @@ export async function attachToBrowser(session: SessionOptions): Promise<Webdrive
if (session.driverPid) {
process.kill(session.driverPid, 9);
}

if (filesToRemove.length > 0) {
await Promise.all(filesToRemove.map(path => fs.remove(path)));
}
});

return existingBrowser.publicAPI;
Expand Down
13 changes: 12 additions & 1 deletion src/browser/standalone/launchBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { Config } from "../../config";
import { NewBrowser } from "./../new-browser";
import { ExistingBrowser } from "./../existing-browser";
import { Calibrator } from "./../calibrator";
import { AsyncEmitter } from "../../events";
import { AsyncEmitter, MasterEvents } from "../../events";
import { BrowserName, type W3CBrowserName } from "./../types";
import { getNormalizedBrowserName } from "../../utils/browser";
import { LOCAL_GRID_URL } from "../../constants/config";
import { WebdriverPool } from "../../browser-pool/webdriver-pool";
import type { StandaloneBrowserOptionsInput } from "./types";
import fs from "fs-extra";

const webdriverPool = new WebdriverPool();

Expand Down Expand Up @@ -50,6 +51,8 @@ export async function launchBrowser(
prepareBrowser: options.prepareBrowser,
};

const filesToRemove: string[] = [];

const config = new Config({
browsers: {
[browserName]: browserConfig,
Expand All @@ -62,6 +65,10 @@ export async function launchBrowser(

const emitter = new AsyncEmitter();

emitter.on(MasterEvents.ADD_FILE_TO_REMOVE, (path: string) => {
filesToRemove.push(path);
});

const newBrowser = new NewBrowser(config, {
id: browserName,
version: desiredCapabilities.browserVersion,
Expand Down Expand Up @@ -97,6 +104,10 @@ export async function launchBrowser(
existingBrowser.publicAPI.overwriteCommand("deleteSession", async function () {
await existingBrowser.quit();
await newBrowser.kill();

if (filesToRemove.length > 0) {
await Promise.all(filesToRemove.map(path => fs.remove(path)));
}
});

existingBrowser.publicAPI.addCommand("getDriverPid", () => newBrowser.getDriverPid());
Expand Down
2 changes: 2 additions & 0 deletions src/events/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export const RunnerSyncEvents = {

DOM_SNAPSHOTS: "domSnapshots",

ADD_FILE_TO_REMOVE: "addFileToRemove",

TEST_DEPENDENCIES: "testDependencies",
} as const;

Expand Down
1 change: 1 addition & 0 deletions src/runner/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export class MainRunner extends RunnableEmitter {
MasterEvents.NEW_WORKER_PROCESS,
MasterEvents.ERROR,
MasterEvents.DOM_SNAPSHOTS,
MasterEvents.ADD_FILE_TO_REMOVE,
MasterEvents.TEST_DEPENDENCIES,
]);

Expand Down
14 changes: 14 additions & 0 deletions src/testplane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,27 @@ export class Testplane extends BaseTestplane {
protected runner: MainRunner | null;
protected viteServer: ViteServer | null;

private _filesToRemove: string[];

constructor(config?: string | ConfigInput) {
super(config);

this.failed = false;
this.failedList = [];
this.runner = null;
this.viteServer = null;

this._filesToRemove = [];
}

extendCli(parser: Command): void {
this.emit(MasterEvents.CLI, parser);
}

addFileToRemove(path: string): void {
this._filesToRemove.push(path);
}

protected async _init(): Promise<void> {
await initDevServer({
testplane: this,
Expand Down Expand Up @@ -155,6 +163,8 @@ export class Testplane extends BaseTestplane {

this.on(MasterEvents.RUNNER_END, async () => await this._saveFailed());

this.on(MasterEvents.ADD_FILE_TO_REMOVE, this.addFileToRemove);

await initReporters(reporters, this);

eventsUtils.passthroughEvent(this.runner, this, _.values(MasterSyncEvents));
Expand Down Expand Up @@ -189,6 +199,10 @@ export class Testplane extends BaseTestplane {
await this.config.afterAll.call({ config: this.config }, { config: this.config });
}

if (this._filesToRemove.length > 0) {
await Promise.all(this._filesToRemove.map(path => fs.remove(path)));
}

return !this.isFailed();
}

Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ export type MasterEventHandler<T extends BaseTestplane> = {
(event: Events["ERROR"], callback: (err: Error) => void): T;

(event: Events["UPDATE_REFERENCE"], callback: (data: { state: string; refImg: RefImageInfo }) => void): T;
(event: Events["ADD_FILE_TO_REMOVE"], callback: (path: string) => void): T;
(event: Events["NEW_BROWSER"], callback: SyncSessionEventCallback): T;
};

Expand Down
4 changes: 4 additions & 0 deletions src/utils/workers-registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ module.exports = class WorkersRegistry extends EventEmitter {
this.emit(MasterEvents.DOM_SNAPSHOTS, data.context, data.data);
break;
}
case MasterEvents.ADD_FILE_TO_REMOVE: {
this.emit(MasterEvents.ADD_FILE_TO_REMOVE, data.data);
break;
}
case MasterEvents.TEST_DEPENDENCIES: {
this.emit(MasterEvents.TEST_DEPENDENCIES, data.context, data.data);
break;
Expand Down
41 changes: 41 additions & 0 deletions test/integration/standalone/standalone-save-state.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import fs from "fs";
import { strict as assert } from "assert";
import { launchBrowser } from "../../../src/browser/standalone";
import { BROWSER_CONFIG, BROWSER_NAME } from "./constants";
Expand Down Expand Up @@ -96,6 +97,46 @@ type AutomationProtocol = typeof DEVTOOLS_PROTOCOL | typeof WEBDRIVER_PROTOCOL;
assert.strictEqual(await status.getText(), "You are logged in");
});

it("saveState: {keepFile: true}", async function () {
await browser.saveState({
keepFile: true,
path: "./state.json",
});

await browser.deleteSession();

const fileExist = fs.existsSync("./state.json");
assert.strictEqual(fileExist, true);
fs.rmSync("./state.json");
});

it("saveState: {keepFile: false}", async function () {
await browser.saveState({
keepFile: false,
path: "./state.json",
});

await browser.deleteSession();

const fileExist = fs.existsSync("./state.json");
assert.strictEqual(fileExist, false);
});

it("saveState: emptyState", async function () {
await browser.saveState({
keepFile: true,
cookieFilter: () => false,
path: "./state.json",
localStorage: false,
sessionStorage: false,
});

await browser.deleteSession();

const fileExist = fs.existsSync("./state.json");
assert.strictEqual(fileExist, false);
});

it("restoreState", async function () {
if (loginState) {
removeDomainFromCookies(loginState);
Expand Down
Loading