mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
feat: add persistent environment variable handling in IPC events and Bru class (#5172)
This commit is contained in:
@@ -2,4 +2,4 @@ import { test, expect } from '../../playwright';
|
||||
|
||||
test('Check if the logo on top left is visible', async ({ page }) => {
|
||||
await expect(page.getByRole('button', { name: 'bruno' })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test.describe.serial('Persistent Environment Test', () => {
|
||||
test.setTimeout(2 * 10 * 1000);
|
||||
|
||||
test('add env using script', async ({ pageWithUserData: page, restartApp }) => {
|
||||
await page.locator('#sidebar-collection-name').click();
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
await page.getByText('ping', { exact: true }).click();
|
||||
await page.getByText('No Environment').click();
|
||||
await page.getByRole('tooltip').locator('div').filter({ hasText: 'Env' }).nth(3).click();
|
||||
await page.locator('#send-request').getByRole('img').nth(2).click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.locator('div').filter({ hasText: /^Env$/ }).nth(3).click();
|
||||
await page.getByText('Configure', { exact: true }).click();
|
||||
await expect(page.getByRole('row', { name: 'persistent-env-test' }).getByRole('cell').nth(3)).toBeVisible();
|
||||
await page.getByText('×').click();
|
||||
|
||||
const newApp = await restartApp();
|
||||
const newPage = await newApp.firstWindow();
|
||||
await newPage.locator('#sidebar-collection-name').click();
|
||||
await newPage.getByRole('button', { name: 'Save' }).click();
|
||||
await newPage.getByText('ping', { exact: true }).click();
|
||||
await newPage.getByText('No Environment').click();
|
||||
await newPage.getByRole('tooltip').locator('div').filter({ hasText: 'Env' }).nth(3).click();
|
||||
await newPage.locator('div').filter({ hasText: /^Env$/ }).nth(3).click();
|
||||
await newPage.getByText('Configure', { exact: true }).click();
|
||||
await expect(newPage.getByRole('row', { name: 'persistent-env-test' }).getByRole('cell').nth(3)).toBeVisible();
|
||||
await newPage.getByText('×').click();
|
||||
await newPage.waitForTimeout(1000);
|
||||
await newPage.close();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import { test, expect } from '../../playwright';
|
||||
|
||||
test.describe.serial('Persistent Environment Test', () => {
|
||||
test.setTimeout(2 * 10 * 1000);
|
||||
|
||||
test('add env using script', async ({ pageWithUserData: page, restartApp }) => {
|
||||
await page.locator('#sidebar-collection-name').click();
|
||||
await page.getByText('ping2', { exact: true }).click();
|
||||
await page.getByText('Env', { exact: true }).click();
|
||||
await page.getByText('Stage', { exact: true }).click();
|
||||
await page.locator('#send-request').getByRole('img').nth(2).click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page
|
||||
.locator('div')
|
||||
.filter({ hasText: /^Stage$/ })
|
||||
.nth(3)
|
||||
.click();
|
||||
await page.getByText('Configure', { exact: true }).click();
|
||||
await expect(page.getByRole('row', { name: 'persistent-env-test' }).getByRole('cell').nth(3)).toBeVisible();
|
||||
await page.getByText('×').click();
|
||||
|
||||
const newApp = await restartApp();
|
||||
const newPage = await newApp.firstWindow();
|
||||
await newPage.locator('#sidebar-collection-name').click();
|
||||
await newPage.getByRole('button', { name: 'Save' }).click();
|
||||
await newPage.getByText('ping2', { exact: true }).click();
|
||||
await newPage.getByText('No Environment').click();
|
||||
await newPage.getByText('Stage').click();
|
||||
await newPage
|
||||
.locator('div')
|
||||
.filter({ hasText: /^Stage$/ })
|
||||
.nth(3)
|
||||
.click();
|
||||
await newPage.getByText('Configure', { exact: true }).click();
|
||||
await expect(newPage.getByRole('row', { name: 'persistent-env-test' }).getByRole('cell').nth(3)).not.toBeVisible();
|
||||
await newPage.getByText('×').click();
|
||||
await newPage.waitForTimeout(1000);
|
||||
await newPage.close();
|
||||
});
|
||||
});
|
||||
5
e2e-tests/persistent-env-tests/collection/bruno.json
Normal file
5
e2e-tests/persistent-env-tests/collection/bruno.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": "1",
|
||||
"name": "collection",
|
||||
"type": "collection"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
vars {
|
||||
host: https://testbench-sanity.usebruno.com
|
||||
persistent-env-test: persistent-env-test-value
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
vars {
|
||||
host: https://testbench-sanity.usebruno.com
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: ping2
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
bru.setEnvVar("persistent-env-test", "persistent-env-test-value");
|
||||
}
|
||||
15
e2e-tests/persistent-env-tests/collection/request.bru
Normal file
15
e2e-tests/persistent-env-tests/collection/request.bru
Normal file
@@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: ping
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
bru.setEnvVar("persistent-env-test", "persistent-env-test-value", { persist: true });
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"maximized": true,
|
||||
"lastOpenedCollections": [
|
||||
"{{projectRoot}}/e2e-tests/persistent-env-tests/collection"
|
||||
]
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
runRequestEvent,
|
||||
scriptEnvironmentUpdateEvent
|
||||
} from 'providers/ReduxStore/slices/collections';
|
||||
import { collectionAddEnvFileEvent, openCollectionEvent, hydrateCollectionWithUiStateSnapshot } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { collectionAddEnvFileEvent, openCollectionEvent, hydrateCollectionWithUiStateSnapshot, mergeAndPersistEnvironment } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { isElectron } from 'utils/common/platform';
|
||||
@@ -112,6 +112,10 @@ const useIpcEvents = () => {
|
||||
dispatch(scriptEnvironmentUpdateEvent(val));
|
||||
});
|
||||
|
||||
const removePersistentEnvVariablesUpdateListener = ipcRenderer.on('main:persistent-env-variables-update', (val) => {
|
||||
dispatch(mergeAndPersistEnvironment(val));
|
||||
});
|
||||
|
||||
const removeGlobalEnvironmentVariablesUpdateListener = ipcRenderer.on('main:global-environment-variables-update', (val) => {
|
||||
dispatch(globalEnvironmentsUpdateEvent(val));
|
||||
});
|
||||
@@ -204,6 +208,7 @@ const useIpcEvents = () => {
|
||||
removeSnapshotHydrationListener();
|
||||
removeCollectionOauth2CredentialsUpdatesListener();
|
||||
removeCollectionLoadingStateListener();
|
||||
removePersistentEnvVariablesUpdateListener();
|
||||
};
|
||||
}, [isElectron]);
|
||||
};
|
||||
|
||||
@@ -1050,6 +1050,68 @@ export const saveEnvironment = (variables, environmentUid, collectionUid) => (di
|
||||
});
|
||||
};
|
||||
|
||||
export const mergeAndPersistEnvironment =
|
||||
({ persistentEnvVariables, collectionUid }) =>
|
||||
(_dispatch, getState) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const state = getState();
|
||||
const collection = findCollectionByUid(state.collections.collections, collectionUid);
|
||||
|
||||
if (!collection) {
|
||||
return reject(new Error('Collection not found'));
|
||||
}
|
||||
|
||||
const environmentUid = collection.activeEnvironmentUid;
|
||||
if (!environmentUid) {
|
||||
return reject(new Error('No active environment found'));
|
||||
}
|
||||
|
||||
const collectionCopy = cloneDeep(collection);
|
||||
const environment = findEnvironmentInCollection(collectionCopy, environmentUid);
|
||||
if (!environment) {
|
||||
return reject(new Error('Environment not found'));
|
||||
}
|
||||
|
||||
// Only proceed if there are persistent variables to save
|
||||
if (!persistentEnvVariables || Object.keys(persistentEnvVariables).length === 0) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
let existingVars = environment.variables || [];
|
||||
|
||||
let normalizedNewVars = Object.entries(persistentEnvVariables).map(([name, value]) => ({
|
||||
uid: uuid(),
|
||||
name,
|
||||
value,
|
||||
type: 'text',
|
||||
enabled: true,
|
||||
secret: false
|
||||
}));
|
||||
|
||||
const merged = existingVars.map((v) => {
|
||||
const found = normalizedNewVars.find((nv) => nv.name === v.name);
|
||||
if (found) {
|
||||
return { ...v, value: found.value };
|
||||
}
|
||||
return v;
|
||||
});
|
||||
normalizedNewVars.forEach((nv) => {
|
||||
if (!merged.some((v) => v.name === nv.name)) {
|
||||
merged.push(nv);
|
||||
}
|
||||
});
|
||||
|
||||
environment.variables = merged;
|
||||
|
||||
const { ipcRenderer } = window;
|
||||
environmentSchema
|
||||
.validate(environment)
|
||||
.then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, environment))
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
export const selectEnvironment = (environmentUid, collectionUid) => (dispatch, getState) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const state = getState();
|
||||
|
||||
@@ -60,7 +60,8 @@ const STATIC_API_HINTS = {
|
||||
'bru.getEnvVar(key)',
|
||||
'bru.getFolderVar(key)',
|
||||
'bru.getCollectionVar(key)',
|
||||
'bru.setEnvVar(key,value)',
|
||||
'bru.setEnvVar(key, value)',
|
||||
'bru.setEnvVar(key, value, options)',
|
||||
'bru.deleteEnvVar(key)',
|
||||
'bru.hasVar(key)',
|
||||
'bru.getVar(key)',
|
||||
|
||||
@@ -468,6 +468,11 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionUid
|
||||
});
|
||||
|
||||
mainWindow.webContents.send('main:persistent-env-variables-update', {
|
||||
persistentEnvVariables: scriptResult.persistentEnvVariables,
|
||||
collectionUid
|
||||
});
|
||||
|
||||
mainWindow.webContents.send('main:global-environment-variables-update', {
|
||||
globalEnvironmentVariables: scriptResult.globalEnvironmentVariables
|
||||
});
|
||||
@@ -542,6 +547,11 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionUid
|
||||
});
|
||||
|
||||
mainWindow.webContents.send('main:persistent-env-variables-update', {
|
||||
persistentEnvVariables: result.persistentEnvVariables,
|
||||
collectionUid
|
||||
});
|
||||
|
||||
mainWindow.webContents.send('main:global-environment-variables-update', {
|
||||
globalEnvironmentVariables: result.globalEnvironmentVariables
|
||||
});
|
||||
@@ -583,6 +593,11 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionUid
|
||||
});
|
||||
|
||||
mainWindow.webContents.send('main:persistent-env-variables-update', {
|
||||
persistentEnvVariables: scriptResult.persistentEnvVariables,
|
||||
collectionUid
|
||||
});
|
||||
|
||||
mainWindow.webContents.send('main:global-environment-variables-update', {
|
||||
globalEnvironmentVariables: scriptResult.globalEnvironmentVariables
|
||||
});
|
||||
@@ -887,6 +902,11 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionUid
|
||||
});
|
||||
|
||||
mainWindow.webContents.send('main:persistent-env-variables-update', {
|
||||
persistentEnvVariables: testResults.persistentEnvVariables,
|
||||
collectionUid
|
||||
});
|
||||
|
||||
mainWindow.webContents.send('main:global-environment-variables-update', {
|
||||
globalEnvironmentVariables: testResults.globalEnvironmentVariables
|
||||
});
|
||||
|
||||
@@ -18,7 +18,6 @@ class Bru {
|
||||
this.collectionPath = collectionPath;
|
||||
this.collectionName = collectionName;
|
||||
this.sendRequest = sendRequest;
|
||||
|
||||
this.cookies = {
|
||||
jar: () => {
|
||||
const cookieJar = createCookieJar();
|
||||
@@ -62,6 +61,8 @@ class Bru {
|
||||
};
|
||||
}
|
||||
};
|
||||
// Holds variables that are marked as persistent by scripts
|
||||
this.persistentEnvVariables = {};
|
||||
this.runner = {
|
||||
skipRequest: () => {
|
||||
this.skipRequest = true;
|
||||
@@ -119,12 +120,25 @@ class Bru {
|
||||
return this.interpolate(this.envVariables[key]);
|
||||
}
|
||||
|
||||
setEnvVar(key, value) {
|
||||
setEnvVar(key, value, options = {}) {
|
||||
if (!key) {
|
||||
throw new Error('Creating a env variable without specifying a name is not allowed.');
|
||||
}
|
||||
|
||||
// When persist is true, only string values are allowed
|
||||
if (options?.persist && typeof value !== 'string') {
|
||||
throw new Error(`Persistent environment variables must be strings. Received ${typeof value} for key "${key}".`);
|
||||
}
|
||||
|
||||
this.envVariables[key] = value;
|
||||
|
||||
if (options?.persist) {
|
||||
this.persistentEnvVariables[key] = value
|
||||
} else {
|
||||
if (this.persistentEnvVariables[key]) {
|
||||
delete this.persistentEnvVariables[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deleteEnvVar(key) {
|
||||
|
||||
@@ -122,6 +122,7 @@ class ScriptRuntime {
|
||||
request,
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
persistentEnvVariables: bru.persistentEnvVariables,
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
results: cleanJson(__brunoTestResults.getResults()),
|
||||
nextRequestName: bru.nextRequest,
|
||||
@@ -177,6 +178,7 @@ class ScriptRuntime {
|
||||
request,
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
persistentEnvVariables: bru.persistentEnvVariables,
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
results: cleanJson(__brunoTestResults.getResults()),
|
||||
nextRequestName: bru.nextRequest,
|
||||
@@ -268,6 +270,7 @@ class ScriptRuntime {
|
||||
return {
|
||||
response,
|
||||
envVariables: cleanJson(envVariables),
|
||||
persistentEnvVariables: cleanJson(bru.persistentEnvVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
results: cleanJson(__brunoTestResults.getResults()),
|
||||
@@ -323,6 +326,7 @@ class ScriptRuntime {
|
||||
return {
|
||||
response,
|
||||
envVariables: cleanJson(envVariables),
|
||||
persistentEnvVariables: cleanJson(bru.persistentEnvVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
results: cleanJson(__brunoTestResults.getResults()),
|
||||
|
||||
@@ -184,6 +184,7 @@ class TestRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
persistentEnvVariables: cleanJson(bru.persistentEnvVariables),
|
||||
results: cleanJson(__brunoTestResults.getResults()),
|
||||
nextRequestName: bru.nextRequest
|
||||
};
|
||||
|
||||
@@ -74,6 +74,7 @@ class VarsRuntime {
|
||||
envVariables,
|
||||
runtimeVariables,
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
persistentEnvVariables: cleanJson(bru.persistentEnvVariables),
|
||||
error
|
||||
};
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ const addBruShimToContext = (vm, bru) => {
|
||||
vm.setProp(bruObject, 'getEnvVar', getEnvVar);
|
||||
getEnvVar.dispose();
|
||||
|
||||
let setEnvVar = vm.newFunction('setEnvVar', function (key, value) {
|
||||
bru.setEnvVar(vm.dump(key), vm.dump(value));
|
||||
let setEnvVar = vm.newFunction('setEnvVar', function (key, value, options = {}) {
|
||||
bru.setEnvVar(vm.dump(key), vm.dump(value), vm.dump(options));
|
||||
});
|
||||
vm.setProp(bruObject, 'setEnvVar', setEnvVar);
|
||||
setEnvVar.dispose();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
const { describe, it, expect } = require('@jest/globals');
|
||||
const TestRuntime = require('../src/runtime/test-runtime');
|
||||
const ScriptRuntime = require('../src/runtime/script-runtime');
|
||||
const Bru = require('../src/bru');
|
||||
const VarsRuntime = require('../src/runtime/vars-runtime');
|
||||
|
||||
describe('runtime', () => {
|
||||
describe('test-runtime', () => {
|
||||
@@ -175,4 +177,73 @@ describe('runtime', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('persistent environment variables validation', () => {
|
||||
it('should throw error when trying to persist non-string values', async () => {
|
||||
const script = `bru.setEnvVar('number', 42, {persist: true});`;
|
||||
const runtime = new ScriptRuntime({ runtime: 'vm2' });
|
||||
|
||||
await expect(runtime.runRequestScript(script, {}, {}, {}, '.', null, process.env))
|
||||
.rejects.toThrow('Persistent environment variables must be strings. Received number for key "number".');
|
||||
});
|
||||
|
||||
it('should throw error when trying to persist boolean values', async () => {
|
||||
const script = `bru.setEnvVar('isActive', true, {persist: true});`;
|
||||
const runtime = new ScriptRuntime({ runtime: 'vm2' });
|
||||
|
||||
await expect(runtime.runRequestScript(script, {}, {}, {}, '.', null, process.env))
|
||||
.rejects.toThrow('Persistent environment variables must be strings. Received boolean for key "isActive".');
|
||||
});
|
||||
|
||||
it('should throw error when trying to persist object values', async () => {
|
||||
const script = `bru.setEnvVar('config', {port: 3000}, {persist: true});`;
|
||||
const runtime = new ScriptRuntime({ runtime: 'vm2' });
|
||||
|
||||
await expect(runtime.runRequestScript(script, {}, {}, {}, '.', null, process.env))
|
||||
.rejects.toThrow('Persistent environment variables must be strings. Received object for key "config".');
|
||||
});
|
||||
|
||||
it('should throw error when trying to persist array values', async () => {
|
||||
const script = `bru.setEnvVar('items', ['item1', 'item2'], {persist: true});`;
|
||||
const runtime = new ScriptRuntime({ runtime: 'vm2' });
|
||||
|
||||
await expect(runtime.runRequestScript(script, {}, {}, {}, '.', null, process.env))
|
||||
.rejects.toThrow('Persistent environment variables must be strings. Received object for key "items".');
|
||||
});
|
||||
|
||||
it('should allow string values when persist is true', async () => {
|
||||
const script = `bru.setEnvVar('api_key', 'abc123', {persist: true});`;
|
||||
const runtime = new ScriptRuntime({ runtime: 'vm2' });
|
||||
|
||||
const result = await runtime.runRequestScript(script, {}, {}, {}, '.', null, process.env);
|
||||
|
||||
expect(result.envVariables.api_key).toBe('abc123');
|
||||
});
|
||||
|
||||
it('should allow non-string values when persist is false', async () => {
|
||||
const script = `
|
||||
bru.setEnvVar('number', 42, {persist: false});
|
||||
bru.setEnvVar('boolean', true, {persist: false});
|
||||
bru.setEnvVar('object', {key: 'value'}, {persist: false});
|
||||
bru.setEnvVar('array', [1, 2, 3], {persist: false});
|
||||
`;
|
||||
const runtime = new ScriptRuntime({ runtime: 'vm2' });
|
||||
|
||||
const result = await runtime.runRequestScript(script, {}, {}, {}, '.', null, process.env);
|
||||
|
||||
expect(result.envVariables.number).toBe(42);
|
||||
expect(result.envVariables.boolean).toBe(true);
|
||||
expect(result.envVariables.object).toEqual({key: 'value'});
|
||||
expect(result.envVariables.array).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
it('should allow non-string values when persist is not specified', async () => {
|
||||
const script = `bru.setEnvVar('number', 42);`;
|
||||
const runtime = new ScriptRuntime({ runtime: 'vm2' });
|
||||
|
||||
const result = await runtime.runRequestScript(script, {}, {}, {}, '.', null, process.env);
|
||||
|
||||
expect(result.envVariables.number).toBe(42);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ export const test = baseTest.extend<
|
||||
page: Page;
|
||||
newPage: Page;
|
||||
pageWithUserData: Page;
|
||||
restartApp: (options?: { initUserDataPath?: string }) => Promise<ElectronApplication>;
|
||||
},
|
||||
{
|
||||
createTmpDir: (tag?: string) => Promise<string>;
|
||||
@@ -67,17 +68,22 @@ export const test = baseTest.extend<
|
||||
args: [electronAppPath],
|
||||
env: {
|
||||
...process.env,
|
||||
ELECTRON_USER_DATA_PATH: userDataPath,
|
||||
ELECTRON_USER_DATA_PATH: userDataPath
|
||||
}
|
||||
});
|
||||
|
||||
const { workerIndex } = workerInfo;
|
||||
app.process()?.stdout?.on('data', (data) => {
|
||||
process.stdout.write(data.toString().replace(/^(?=.)/gm, `[Electron #${workerIndex}] |`));
|
||||
});
|
||||
app.process()?.stderr?.on('data', (error) => {
|
||||
process.stderr.write(error.toString().replace(/^(?=.)/gm, `[Electron #${workerIndex}] |`));
|
||||
});
|
||||
const electronProcess = app.process();
|
||||
if (electronProcess?.stdout) {
|
||||
electronProcess.stdout.on('data', (data) => {
|
||||
process.stdout.write(data.toString().replace(/^(?=.)/gm, `[Electron #${workerIndex}] |`));
|
||||
});
|
||||
}
|
||||
if (electronProcess?.stderr) {
|
||||
electronProcess.stderr.on('data', (error) => {
|
||||
process.stderr.write(error.toString().replace(/^(?=.)/gm, `[Electron #${workerIndex}] |`));
|
||||
});
|
||||
}
|
||||
|
||||
apps.push(app);
|
||||
return app;
|
||||
@@ -157,6 +163,32 @@ export const test = baseTest.extend<
|
||||
{ scope: 'worker' }
|
||||
],
|
||||
|
||||
restartApp: async ({ launchElectronApp }, use, testInfo) => {
|
||||
const appInstances: Array<{ app: ElectronApplication; initUserDataPath?: string }> = [];
|
||||
await use(async ({ initUserDataPath } = {}) => {
|
||||
// Get the test directory and check for init-user-data folder
|
||||
const testDir = path.dirname(testInfo.file);
|
||||
const defaultInitUserDataPath = path.join(testDir, 'init-user-data');
|
||||
|
||||
// Use provided initUserDataPath, or check if default path exists, or use undefined
|
||||
let userDataPath = initUserDataPath;
|
||||
if (!userDataPath) {
|
||||
const hasInitUserData = await fs.promises.stat(defaultInitUserDataPath).catch(() => false);
|
||||
userDataPath = hasInitUserData ? defaultInitUserDataPath : undefined;
|
||||
}
|
||||
|
||||
const app = await launchElectronApp({ initUserDataPath: userDataPath });
|
||||
appInstances.push({ app, initUserDataPath: userDataPath });
|
||||
return app;
|
||||
});
|
||||
|
||||
// Clean up all app instances
|
||||
for (const { app } of appInstances) {
|
||||
await app.context().close();
|
||||
await app.close();
|
||||
}
|
||||
},
|
||||
|
||||
pageWithUserData: async ({ reuseOrLaunchElectronApp }, use, testInfo) => {
|
||||
const testDir = path.dirname(testInfo.file);
|
||||
const initUserDataPath = path.join(testDir, 'init-user-data');
|
||||
|
||||
Reference in New Issue
Block a user