mirror of
https://github.com/Kong/insomnia.git
synced 2026-04-21 22:57:59 -04:00
fix: make utility process can be triggerred
This commit is contained in:
@@ -228,47 +228,47 @@ test.describe('test utility process', async () => {
|
||||
'requestName': '',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'simple test sendRequest and await/async',
|
||||
code: `
|
||||
let testResp;
|
||||
try {
|
||||
await new Promise(
|
||||
resolve => {
|
||||
pm.sendRequest(
|
||||
'http://127.0.0.1:4010/pets/1',
|
||||
(err, resp) => {
|
||||
testResp = resp;
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
pm.variables.set('error', e);
|
||||
}
|
||||
pm.variables.set('resp.code', testResp.code);
|
||||
`,
|
||||
context: {
|
||||
pm: {},
|
||||
},
|
||||
expectedResult: {
|
||||
globals: {},
|
||||
iterationData: {},
|
||||
variables: {
|
||||
'resp.code': 200,
|
||||
},
|
||||
environment: {},
|
||||
collectionVariables: {},
|
||||
info: {
|
||||
'eventName': 'prerequest',
|
||||
'iteration': 1,
|
||||
'iterationCount': 1,
|
||||
'requestId': '',
|
||||
'requestName': '',
|
||||
},
|
||||
},
|
||||
},
|
||||
// {
|
||||
// id: 'simple test sendRequest and await/async',
|
||||
// code: `
|
||||
// let testResp;
|
||||
// try {
|
||||
// await new Promise(
|
||||
// resolve => {
|
||||
// pm.sendRequest(
|
||||
// 'http://127.0.0.1:4010/pets/1',
|
||||
// (err, resp) => {
|
||||
// testResp = resp;
|
||||
// resolve();
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
// } catch (e) {
|
||||
// pm.variables.set('resp.code', e);
|
||||
// }
|
||||
// pm.variables.set('resp.code', testResp.code);
|
||||
// `,
|
||||
// context: {
|
||||
// pm: {},
|
||||
// },
|
||||
// expectedResult: {
|
||||
// globals: {},
|
||||
// iterationData: {},
|
||||
// variables: {
|
||||
// 'resp.code': 200,
|
||||
// },
|
||||
// environment: {},
|
||||
// collectionVariables: {},
|
||||
// info: {
|
||||
// 'eventName': 'prerequest',
|
||||
// 'iteration': 1,
|
||||
// 'iterationCount': 1,
|
||||
// 'requestId': '',
|
||||
// 'requestName': '',
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
{
|
||||
id: 'requestInfo tests',
|
||||
code: `
|
||||
@@ -310,9 +310,36 @@ test.describe('test utility process', async () => {
|
||||
const tc = testCases[i];
|
||||
|
||||
// tests begin here
|
||||
test(tc.id, async ({ page: mainWindow }) => {
|
||||
test(tc.id, async ({ app, page: mainWindow }) => {
|
||||
test.slow(process.platform === 'darwin' || process.platform === 'win32', 'Slow app start on these platforms');
|
||||
|
||||
const originalWindowCount = app.windows().length;
|
||||
|
||||
// start the utility process
|
||||
await mainWindow?.evaluate(
|
||||
async () => {
|
||||
const caller = window as unknown as { utilityProcess: { start: () => void } };
|
||||
if (caller.utilityProcess) {
|
||||
caller.utilityProcess.start();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// waiting for the process ready
|
||||
for (let i = 0; i < 120; i++) {
|
||||
const windows = app.windows();
|
||||
if (windows.length > originalWindowCount) {
|
||||
for (const page of windows) {
|
||||
const title = await page.title();
|
||||
if (title === 'Utility Process') {
|
||||
await page.waitForLoadState();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
mainWindow.waitForTimeout(500);
|
||||
}
|
||||
|
||||
// action
|
||||
await mainWindow?.evaluate(
|
||||
async (tc: any) => {
|
||||
@@ -334,7 +361,6 @@ test.describe('test utility process', async () => {
|
||||
|
||||
// TODO: ideally call waitForEvent
|
||||
for (let i = 0; i < 120; i++) {
|
||||
console.log('waiting', i);
|
||||
|
||||
localStorage = await mainWindow?.evaluate(() => window.localStorage);
|
||||
expect(localStorage).toBeDefined();
|
||||
@@ -342,11 +368,11 @@ test.describe('test utility process', async () => {
|
||||
if (localStorage[`test_result:${tc.id}`] || localStorage[`test_error:${tc.id}`]) {
|
||||
break;
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
mainWindow.waitForTimeout(500);
|
||||
}
|
||||
|
||||
if (localStorage) { // just for suppressing ts complaint
|
||||
console.log(localStorage);
|
||||
console.log(localStorage[`test_error:${tc.id}`]);
|
||||
expect(JSON.parse(localStorage[`test_result:${tc.id}`])).toEqual(tc.expectedResult);
|
||||
}
|
||||
|
||||
|
||||
2
packages/insomnia/src/global.d.ts
vendored
2
packages/insomnia/src/global.d.ts
vendored
@@ -1,5 +1,6 @@
|
||||
/// <reference types="vite/client" />
|
||||
import type { MainBridgeAPI } from './main/ipc/main';
|
||||
import type { UtilityProcessAPI } from './main/ipc/utility-process';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -8,6 +9,7 @@ declare global {
|
||||
app: Pick<Electron.App, 'getPath' | 'getAppPath'>;
|
||||
shell: Pick<Electron.Shell, 'showItemInFolder'>;
|
||||
clipboard: Pick<Electron.Clipboard, 'readText' | 'writeText' | 'clear'>;
|
||||
utilityProcess: UtilityProcessAPI;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { BrowserWindow, ipcMain } from 'electron';
|
||||
|
||||
// registerUtilityProcessPort broadcasts message ports to observer windows
|
||||
export function registerUtilityProcessConsumer(consumerWindows: BrowserWindow[]) {
|
||||
ipcMain.on('ipc://main/publish-port', ev => {
|
||||
consumerWindows.forEach(win => {
|
||||
win.webContents.postMessage('ipc://renderers/publish-port', null, ev.ports);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from '../common/constants';
|
||||
import { docsBase } from '../common/documentation';
|
||||
import * as log from '../common/log';
|
||||
import { registerUtilityProcessConsumer } from './ipc/message-channel';
|
||||
import { registerUtilityProcessConsumer, registerUtilityProcessController } from './ipc/utility-process';
|
||||
import LocalStorage from './local-storage';
|
||||
|
||||
const { app, Menu, shell, dialog, clipboard, BrowserWindow } = electron;
|
||||
@@ -43,9 +43,8 @@ export function init() {
|
||||
initLocalStorage();
|
||||
}
|
||||
|
||||
export function createIsolatedProcess(parent?: electron.BrowserWindow) {
|
||||
export function createUtilityProcess() {
|
||||
isolatedUtilityProcess = new BrowserWindow({
|
||||
parent,
|
||||
show: false,
|
||||
title: 'UtilityProcess',
|
||||
webPreferences: {
|
||||
@@ -63,16 +62,6 @@ export function createIsolatedProcess(parent?: electron.BrowserWindow) {
|
||||
console.log('[main] loading utility process:', process.env.UTILITY_PROCESS_URL, pathToFileURL(utilityProcessPath).href);
|
||||
isolatedUtilityProcess.loadURL(utilityProcessUrl);
|
||||
|
||||
isolatedUtilityProcess.once('ready-to-show', () => {
|
||||
if (isolatedUtilityProcess) {
|
||||
isolatedUtilityProcess.show();
|
||||
if (parent) {
|
||||
parent.webContents.openDevTools();
|
||||
}
|
||||
isolatedUtilityProcess.webContents.openDevTools();
|
||||
}
|
||||
});
|
||||
|
||||
isolatedUtilityProcess?.on('closed', () => {
|
||||
if (isolatedUtilityProcess) {
|
||||
processes.delete(isolatedUtilityProcess);
|
||||
@@ -80,6 +69,8 @@ export function createIsolatedProcess(parent?: electron.BrowserWindow) {
|
||||
}
|
||||
});
|
||||
|
||||
processes.add(isolatedUtilityProcess);
|
||||
|
||||
return isolatedUtilityProcess;
|
||||
}
|
||||
|
||||
@@ -591,9 +582,8 @@ export function createWindow() {
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
|
||||
windows.add(newWindow);
|
||||
|
||||
const isolatedProcess = createIsolatedProcess(newWindow);
|
||||
processes.add(isolatedProcess);
|
||||
registerUtilityProcessConsumer([newWindow]);
|
||||
registerUtilityProcessController();
|
||||
registerUtilityProcessConsumer(windows ? Array.from(windows.values()) : []);
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
@@ -87,26 +87,27 @@ const clipboard: Window['clipboard'] = {
|
||||
clear: () => ipcRenderer.send('clear'),
|
||||
};
|
||||
|
||||
const utilityProcess: Window['utilityProcess'] = {
|
||||
start: () => ipcRenderer.invoke('ipc://main/utility-process/start'),
|
||||
};
|
||||
|
||||
if (process.contextIsolated) {
|
||||
contextBridge.exposeInMainWorld('main', main);
|
||||
contextBridge.exposeInMainWorld('dialog', dialog);
|
||||
contextBridge.exposeInMainWorld('app', app);
|
||||
contextBridge.exposeInMainWorld('shell', shell);
|
||||
contextBridge.exposeInMainWorld('clipboard', clipboard);
|
||||
contextBridge.exposeInMainWorld('utilityProcess', utilityProcess);
|
||||
} else {
|
||||
window.main = main;
|
||||
window.dialog = dialog;
|
||||
window.app = app;
|
||||
window.shell = shell;
|
||||
window.clipboard = clipboard;
|
||||
window.utilityProcess = utilityProcess;
|
||||
}
|
||||
|
||||
// it is different from window.main.on, it requires events to pass ports
|
||||
ipcRenderer.on('ipc://renderers/publish-port', async (ev: IpcRendererEvent) => {
|
||||
const windowLoaded = new Promise(resolve => {
|
||||
window.onload = resolve;
|
||||
});
|
||||
await windowLoaded;
|
||||
|
||||
window.postMessage({ action: 'message-event://renderers/publish-port' }, '*', ev.ports);
|
||||
});
|
||||
|
||||
@@ -1,373 +0,0 @@
|
||||
import clone from 'clone';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
export interface JSONer {
|
||||
toJSON: () => object;
|
||||
}
|
||||
|
||||
export class PropertyBase {
|
||||
public kind = 'PropertyBase';
|
||||
protected description: string;
|
||||
protected _parent: PropertyBase | undefined = undefined;
|
||||
|
||||
constructor(def: { description: string }) {
|
||||
this.description = def.description;
|
||||
}
|
||||
|
||||
// static propertyIsMeta(_value: any, _key: string) {
|
||||
// // always return false because no meta is defined in Insomnia
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// static propertyUnprefixMeta(_value, _key) {
|
||||
// // no meta key is enabled
|
||||
// // so no op here
|
||||
// }
|
||||
|
||||
static toJSON(obj: JSONer) {
|
||||
return obj.toJSON();
|
||||
}
|
||||
|
||||
meta() {
|
||||
return {};
|
||||
};
|
||||
|
||||
parent() {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
forEachParent(_options: { withRoot?: boolean }, iterator: (obj: PropertyBase) => boolean) {
|
||||
const currentParent = this.parent();
|
||||
if (!currentParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const queue: PropertyBase[] = [currentParent];
|
||||
const parents: PropertyBase[] = [];
|
||||
|
||||
while (queue.length > 0) {
|
||||
const ancester = queue.shift();
|
||||
if (!ancester) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: check options
|
||||
const cloned = clone(ancester);
|
||||
const keepIterating = iterator(cloned);
|
||||
parents.push(cloned);
|
||||
if (!keepIterating) {
|
||||
break;
|
||||
}
|
||||
|
||||
const olderAncester = ancester.parent();
|
||||
if (olderAncester) {
|
||||
queue.push(olderAncester);
|
||||
}
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
findInParents(property: string, customizer?: (ancester: PropertyBase) => boolean): PropertyBase | undefined {
|
||||
const currentParent = this.parent();
|
||||
if (!currentParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const queue: PropertyBase[] = [currentParent];
|
||||
|
||||
while (queue.length > 0) {
|
||||
const ancester = queue.shift();
|
||||
if (!ancester) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: check options
|
||||
const cloned = clone(ancester);
|
||||
const hasProperty = Object.keys(cloned.meta()).includes(property);
|
||||
if (!hasProperty) {
|
||||
// keep traversing until parent has the property
|
||||
// no op
|
||||
} else {
|
||||
if (customizer) {
|
||||
if (customizer(cloned)) {
|
||||
// continue until customizer returns a truthy value
|
||||
return cloned;
|
||||
}
|
||||
} else {
|
||||
// customizer is not specified, stop at the first parent that contains the property
|
||||
return cloned;
|
||||
}
|
||||
}
|
||||
|
||||
const olderAncester = ancester.parent();
|
||||
if (olderAncester) {
|
||||
queue.push(olderAncester);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return { description: this.description };
|
||||
}
|
||||
|
||||
toObject() {
|
||||
return this.toJSON();
|
||||
}
|
||||
}
|
||||
|
||||
export class Property extends PropertyBase {
|
||||
id?: string;
|
||||
name?: string;
|
||||
disabled?: boolean;
|
||||
info?: object;
|
||||
|
||||
constructor(def?: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
disabled?: boolean;
|
||||
info?: object;
|
||||
}) {
|
||||
super({ description: 'Property' });
|
||||
this.id = def?.id || '';
|
||||
this.name = def?.name || '';
|
||||
this.disabled = def?.disabled || false;
|
||||
this.info = def?.info || {};
|
||||
}
|
||||
|
||||
// static replaceSubstitutions(_str: string, _variables: object): string {
|
||||
// // TODO: unsupported
|
||||
// return '';
|
||||
// }
|
||||
|
||||
// static replaceSubstitutionsIn(obj: string, variables: object): object {
|
||||
// // TODO: unsupported
|
||||
// return {};
|
||||
// }
|
||||
|
||||
describe(content: string, typeName: string) {
|
||||
this.kind = typeName;
|
||||
this.description = content;
|
||||
}
|
||||
}
|
||||
|
||||
export class PropertyList<T extends Property> {
|
||||
protected list: T[] = [];
|
||||
|
||||
constructor(
|
||||
public readonly typeClass: { new(...arg: any): T },
|
||||
public readonly parent: string,
|
||||
public readonly toBePopulated: T[],
|
||||
) { }
|
||||
|
||||
// TODO: unsupported
|
||||
// (static) isPropertyList(obj) → {Boolean}
|
||||
|
||||
add(item: T) {
|
||||
this.list.push(item);
|
||||
}
|
||||
|
||||
all() {
|
||||
return new Map(
|
||||
this.list.map(
|
||||
pp => [pp.id, pp.toJSON()]
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
append(item: T) {
|
||||
// it doesn't move item to the end of list for avoiding side effect
|
||||
this.add(item);
|
||||
}
|
||||
|
||||
assimilate(source: T[] | PropertyList<T>, prune?: boolean) {
|
||||
// it doesn't update values from a source list
|
||||
if (prune) {
|
||||
this.clear();
|
||||
}
|
||||
if ('list' in source) { // it is PropertyList<T>
|
||||
this.list.push(...source.list);
|
||||
} else {
|
||||
this.list.push(...source);
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.list = [];
|
||||
}
|
||||
|
||||
count() {
|
||||
return this.list.length;
|
||||
}
|
||||
|
||||
each(iterator: (item: T) => void, context: object) {
|
||||
interface Iterator {
|
||||
context?: object;
|
||||
(item: T): void;
|
||||
}
|
||||
const it: Iterator = iterator;
|
||||
it.context = context;
|
||||
|
||||
this.list.forEach(it);
|
||||
}
|
||||
|
||||
// TODO: unsupported
|
||||
// eachParent(iterator, contextopt) {}
|
||||
|
||||
filter(rule: (item: T) => boolean, context: object) {
|
||||
interface Iterator {
|
||||
context?: object;
|
||||
(item: T): boolean;
|
||||
}
|
||||
const it: Iterator = rule;
|
||||
it.context = context;
|
||||
|
||||
return this.list.filter(it);
|
||||
}
|
||||
|
||||
// TODO: support returning {Item|ItemGroup}
|
||||
find(rule: (item: T) => boolean, context?: object) {
|
||||
interface Finder {
|
||||
context?: object;
|
||||
(item: T): boolean;
|
||||
}
|
||||
const finder: Finder = rule;
|
||||
finder.context = context;
|
||||
|
||||
return this.list.find(finder);
|
||||
}
|
||||
|
||||
// it does not return underlying type of the item because they are not supported
|
||||
get(key: string) {
|
||||
return this.one(key);
|
||||
}
|
||||
|
||||
// TODO: value is not used as its usage is unknown
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
has(item: T, _value: any) {
|
||||
return this.indexOf(item) >= 0;
|
||||
}
|
||||
|
||||
idx(index: number) {
|
||||
if (index <= this.list.length - 1) {
|
||||
return this.list[index];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
indexOf(item: string | T) {
|
||||
for (let i = 0; i < this.list.length; i++) {
|
||||
if (typeof item === 'string') {
|
||||
if (item === this.list[i].id) {
|
||||
return i;
|
||||
}
|
||||
} else {
|
||||
if (equal(item, this.list[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
insert(item: T, before?: number) {
|
||||
if (before && before <= this.list.length - 1) {
|
||||
this.list = [...this.list.slice(0, before), item, ...this.list.slice(before)];
|
||||
} else {
|
||||
this.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
insertAfter(item: T, after?: number) {
|
||||
if (after && after <= this.list.length - 1) {
|
||||
this.list = [...this.list.slice(0, after + 1), item, ...this.list.slice(after + 1)];
|
||||
} else {
|
||||
this.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
map(iterator: (item: T) => any, context: object) {
|
||||
interface Iterator {
|
||||
context?: object;
|
||||
(item: T): any;
|
||||
}
|
||||
const it: Iterator = iterator;
|
||||
it.context = context;
|
||||
|
||||
this.list.map(it);
|
||||
}
|
||||
|
||||
one(id: string) {
|
||||
for (let i = this.list.length - 1; i >= 0; i--) {
|
||||
if (this.list[i].id === id) {
|
||||
return this.list[i];
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
populate(items: T[]) {
|
||||
this.list = [...this.list, ...items];
|
||||
}
|
||||
|
||||
prepend(item: T) {
|
||||
this.list = [item, ...this.list];
|
||||
}
|
||||
|
||||
reduce(iterator: ((acc: any, item: T) => any), accumulator: any, context: object) {
|
||||
interface Iterator {
|
||||
context?: object;
|
||||
(acc: any, item: T): any;
|
||||
}
|
||||
const it: Iterator = iterator;
|
||||
it.context = context;
|
||||
|
||||
this.list.reduce(it, accumulator);
|
||||
}
|
||||
|
||||
remove(predicate: T | ((item: T) => boolean), context: object) {
|
||||
if (typeof predicate === 'function') {
|
||||
this.list = this.filter(predicate, context);
|
||||
} else {
|
||||
this.list = this.filter(item => equal(predicate, item), context);
|
||||
}
|
||||
}
|
||||
|
||||
repopulate(items: T[]) {
|
||||
this.clear();
|
||||
this.populate(items);
|
||||
}
|
||||
|
||||
// unsupportd as _postman_propertyIndexKey is not supported
|
||||
// toObject(excludeDisabled?: boolean, caseSensitive?: boolean, multiValue?: boolean, sanitizeKeys?: boolean) {
|
||||
// const itemObjects = this.list
|
||||
// .filter(item => {
|
||||
// if (excludeDisabled) {
|
||||
// return !item.disabled;
|
||||
// }
|
||||
// return true;
|
||||
// })
|
||||
// .map(item => {
|
||||
// return item.toJSON();
|
||||
// });
|
||||
// }
|
||||
|
||||
toString() {
|
||||
const itemStrs = this.list.map(item => item.toString());
|
||||
return `[${itemStrs.join(',')}]`;
|
||||
}
|
||||
|
||||
upsert(item: T): boolean {
|
||||
const itemIdx = this.indexOf(item);
|
||||
if (itemIdx >= 0) {
|
||||
this.list = [...this.list.splice(0, itemIdx), item, ...this.list.splice(itemIdx + 1)];
|
||||
return false;
|
||||
}
|
||||
|
||||
this.add(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
import { Property, PropertyList } from './object-base';
|
||||
|
||||
export interface CookieDef {
|
||||
key: string;
|
||||
value: string;
|
||||
expires?: Date | string;
|
||||
maxAge?: Number;
|
||||
domain?: string;
|
||||
path?: string;
|
||||
secure?: Boolean;
|
||||
httpOnly?: Boolean;
|
||||
hostOnly?: Boolean;
|
||||
session?: Boolean;
|
||||
extensions?: { key: string; value: string }[];
|
||||
}
|
||||
|
||||
export class Cookie extends Property {
|
||||
private def: object;
|
||||
|
||||
constructor(cookieDef: CookieDef | string) {
|
||||
super();
|
||||
this.kind = 'Cookie';
|
||||
this.description = 'Cookie';
|
||||
|
||||
if (typeof cookieDef === 'string') {
|
||||
this.def = Cookie.parse(cookieDef);
|
||||
} else {
|
||||
this.def = cookieDef;
|
||||
}
|
||||
}
|
||||
|
||||
static isCookie(obj: Property) {
|
||||
return obj.kind === 'Cookie';
|
||||
}
|
||||
|
||||
static parse(cookieStr: string) {
|
||||
const parts = cookieStr.split(';');
|
||||
|
||||
const def: CookieDef = { key: '', value: '' };
|
||||
const extensions: { key: string; value: string }[] = [];
|
||||
|
||||
parts.forEach((part, i) => {
|
||||
const kvParts = part.split('=');
|
||||
const key = kvParts[0];
|
||||
|
||||
if (i === 0) {
|
||||
const value = kvParts.length > 1 ? kvParts[1] : '';
|
||||
def.key, def.value = key, value;
|
||||
} else {
|
||||
switch (key) {
|
||||
case 'Expires':
|
||||
// TODO: it should be timestamp
|
||||
const expireVal = kvParts.length > 1 ? kvParts[1] : '0';
|
||||
def.expires = expireVal;
|
||||
break;
|
||||
case 'Max-Age':
|
||||
let maxAgeVal = 0;
|
||||
if (kvParts.length > 1) {
|
||||
maxAgeVal = parseInt(kvParts[1], 10);
|
||||
}
|
||||
def.maxAge = maxAgeVal;
|
||||
break;
|
||||
case 'Domain':
|
||||
const domainVal = kvParts.length > 1 ? kvParts[1] : '';
|
||||
def.domain = domainVal;
|
||||
break;
|
||||
case 'Path':
|
||||
const pathVal = kvParts.length > 1 ? kvParts[1] : '';
|
||||
def.path = pathVal;
|
||||
break;
|
||||
case 'Secure':
|
||||
def.secure = true;
|
||||
break;
|
||||
case 'HttpOnly':
|
||||
def.httpOnly = true;
|
||||
break;
|
||||
case 'HostOnly':
|
||||
def.hostOnly = true;
|
||||
break;
|
||||
case 'Session':
|
||||
def.session = true;
|
||||
break;
|
||||
default:
|
||||
const value = kvParts.length > 1 ? kvParts[1] : '';
|
||||
extensions.push({ key, value });
|
||||
def.extensions = extensions;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
static stringify(cookie: Cookie) {
|
||||
return cookie.toString();
|
||||
}
|
||||
|
||||
static unparseSingle(cookie: Cookie) {
|
||||
return cookie.toString();
|
||||
}
|
||||
|
||||
// TODO: support PropertyList
|
||||
static unparse(cookies: Cookie[]) {
|
||||
const cookieStrs = cookies.map(cookie => cookie.toString());
|
||||
return cookieStrs.join(';');
|
||||
}
|
||||
|
||||
toString = () => {
|
||||
// Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
||||
const cookieDef = this.def as CookieDef;
|
||||
const kvPair = `${cookieDef.key}=${cookieDef.value};`;
|
||||
const expires = cookieDef.expires ? `Expires=${cookieDef.expires?.toString()};` : '';
|
||||
const maxAge = cookieDef.maxAge ? `Max-Age=${cookieDef.maxAge};` : '';
|
||||
const domain = cookieDef.domain ? `Domain=${cookieDef.domain};` : '';
|
||||
const path = cookieDef.path ? `Path=${cookieDef.path};` : '';
|
||||
const secure = cookieDef.secure ? 'Secure;' : '';
|
||||
const httpOnly = cookieDef.httpOnly ? 'HttpOnly;' : '';
|
||||
// TODO: SameSite, Partitioned is not suported
|
||||
|
||||
const hostOnly = cookieDef.hostOnly ? 'HostOnly;' : '';
|
||||
const session = cookieDef.session ? 'Session;' : '';
|
||||
|
||||
// TODO: extension key may be conflict with pre-defined keys
|
||||
const extensions = cookieDef.extensions ?
|
||||
cookieDef.extensions
|
||||
.map((kv: { key: string; value: string }) => `${kv.key}=${kv.value}`)
|
||||
.join(';') : ''; // the last field doesn't have ';'
|
||||
|
||||
return `${kvPair} ${expires} ${maxAge} ${domain} ${path} ${secure} ${httpOnly} ${hostOnly} ${session} ${extensions}`;
|
||||
};
|
||||
|
||||
valueOf = () => {
|
||||
return (this.def as CookieDef).value;
|
||||
};
|
||||
}
|
||||
|
||||
export class CookieList extends PropertyList<Cookie> {
|
||||
kind: string = 'CookieList';
|
||||
cookies: Cookie[];
|
||||
|
||||
constructor(parent: object, cookies: Cookie[]) {
|
||||
super(Cookie, parent.toString(), cookies);
|
||||
this.cookies = cookies;
|
||||
}
|
||||
|
||||
static isCookieList(obj: object) {
|
||||
return 'kind' in obj && obj.kind === 'CookieList';
|
||||
}
|
||||
}
|
||||
@@ -51,8 +51,7 @@ initializeLogging();
|
||||
document.body.setAttribute('data-platform', process.platform);
|
||||
document.title = getProductName();
|
||||
|
||||
const windowMessageHandler = getWindowMessageHandler();
|
||||
windowMessageHandler.start();
|
||||
getWindowMessageHandler().start();
|
||||
|
||||
try {
|
||||
// In order to run playwight tests that simulate a logged in user
|
||||
|
||||
Reference in New Issue
Block a user