Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
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 .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ concurrency:

jobs:
Test:
timeout-minutes: 15
timeout-minutes: 40
runs-on: ubuntu-22.04
steps:
- name: Checkout branch
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/insomnia-smoke-test/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ const config: PlaywrightTestConfig = {
timeout: process.env.CI ? 25 * 1000 : 10 * 1000,
},
workers: 1,
globalTimeout: 20 * 60 * 1000,
};
export default config;
19 changes: 4 additions & 15 deletions packages/insomnia-smoke-test/tests/smoke/grpc-interactions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ import { test } from '../../playwright/test';

test.describe('gRPC interactions', () => {
test.slow(process.platform === 'darwin' || process.platform === 'win32', 'Slow app start on these platforms');
let statusTag: Locator;
let responseBody: Locator;
let streamMessage: Locator;

test.beforeEach(async ({ app, page }) => {
test('can send all types of requests', async ({ page, app }) => {
const text = await loadFixture('grpc.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);

Expand All @@ -20,14 +17,12 @@ test.describe('gRPC interactions', () => {
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByLabel('PreRelease gRPC').click();

statusTag = page.locator('[data-testid="response-status-tag"]:visible');
responseBody = page.locator('[data-testid="response-pane"] >> [data-testid="CodeEditor"]:visible', {
const statusTag = page.locator('[data-testid="response-status-tag"]:visible');
const responseBody = page.locator('[data-testid="response-pane"] >> [data-testid="CodeEditor"]:visible', {
has: page.locator('.CodeMirror-activeline'),
});
streamMessage = page.locator('[data-testid="request-pane"] button:has-text("Stream")');
});
const streamMessage = page.locator('[data-testid="request-pane"] button:has-text("Stream")');

test('can send unidirectional requests', async ({ page }) => {
await page.getByLabel('Request Collection').getByTestId('Unary').click();
await page.locator('[data-testid="request-pane"] >> text=Unary').click();
await page.click('text=Send');
Expand All @@ -36,9 +31,7 @@ test.describe('gRPC interactions', () => {
await page.click('text=Response 1');
await expect.soft(statusTag).toContainText('0 OK');
await expect.soft(responseBody).toContainText('Berkshire Valley Management Area Trail');
});

test('can send bidirectional requests', async ({ page }) => {
await page.getByLabel('Request Collection').getByTestId('Bidirectional Stream').press('Enter');
await page.locator('text=Bi-directional Streaming').click();
await page.click('text=Start');
Expand All @@ -55,9 +48,7 @@ test.describe('gRPC interactions', () => {
// Finish the stream
await page.locator('text=Commit').click();
await expect.soft(statusTag).toContainText('0 OK');
});

test('can send client stream requests', async ({ page }) => {
await page.getByLabel('Request Collection').getByTestId('Client Stream').press('Enter');
await page.click('text=Client Streaming');
await page.click('text=Start');
Expand All @@ -73,9 +64,7 @@ test.describe('gRPC interactions', () => {
await page.locator('text=Response 1').click();
await expect.soft(statusTag).toContainText('0 OK');
await expect.soft(responseBody).toContainText('point_count": 3');
});

test('can send server stream requests', async ({ page }) => {
await page.getByLabel('Request Collection').getByTestId('Server Stream').press('Enter');
await page.click('text=Server Streaming');
await page.click('text=Start');
Expand Down
1 change: 0 additions & 1 deletion packages/insomnia-smoke-test/tests/smoke/grpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ test('can send gRPC requests with reflection', async ({ app, page }) => {
await page.getByLabel('PreRelease gRPC').click();

await page.getByLabel('Request Collection').getByTestId('UnaryWithOutProtoFile').press('Enter');
await expect.soft(page.getByRole('button', { name: 'Select Method' })).toBeDisabled();
await page.getByTestId('button-server-reflection').click();

await page.getByRole('button', { name: 'Select Method' }).click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ const templateTagTestCases: Record<string, TemplateTagTestCase[]> = {
expectedResult: 'File Tag Test',
},
],
hash: [{ tagPrefix: "{% hash 'md5', 'hex', 'insomnia-test' %}", expectedResult: 'b9c076eabf32fa4cdd7573a6df12d33c' }],
hash: [
{
tagPrefix: "{% hash 'md5', 'hex', 'insomnia-test' %}",
expectedResult: 'b79b28083768d54575eacc7389e9128624685310',
},
],
jsonPath: [{ tagPrefix: '{% jsonpath', expectedResult: 'bar' }],
os: [{ tagPrefix: "{% os 'arch', '' %}", expectedResult: os.arch() }],
timeStamp: [
Expand Down Expand Up @@ -84,11 +89,11 @@ test('Critical Path For Template Tags Interactions', async ({ page, app }) => {
// wait for render complete
await expect.soft(previewResult).not.toHaveText('rendering...');
const previewText = await previewResult.textContent();
const isFunction = typeof expectedResult === 'function';
expect
.soft(
typeof expectedResult === 'function'
? expectedResult(previewText || '')
: previewText?.includes(expectedResult),
isFunction ? expectedResult(previewText || '') : previewText?.includes(expectedResult),
` Template tag "${tagPrefix}" should render as "${expectedResult}" but returned ${previewText}.`,
)
.toBeTruthy();
// close modal
Expand Down
8 changes: 7 additions & 1 deletion packages/insomnia/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
"type-check:watch": "npm run type-check -- --watch",
"convert-svg": "npm_config_yes=true npx @svgr/[email protected] --no-index --config-file svgr.config.js --out-dir src/ui/components/assets/svgr src/ui/components/assets/"
},
"//": [
"dependencies will be external to the vite bundle and electron main (commonjs)",
"devDependencies will be included in the vite bundle (esm)",
"See: packages/insomnia/vite.config.ts",
"and: packages/insomnia/esbuild.main.ts"
],
"dependencies": {
"@apideck/better-ajv-errors": "^0.3.6",
"@apidevtools/swagger-parser": "10.1.1",
Expand Down Expand Up @@ -75,7 +81,6 @@
"jsdom": "^25.0.1",
"jshint": "^2.13.6",
"jsonlint-mod-fixed": "1.7.7",
"jsonpath-plus": "^10.3.0",
"marked": "^5.1.2",
"mime-types": "^2.1.35",
"mocha": "^10.8.2",
Expand Down Expand Up @@ -161,6 +166,7 @@
"httplease-asap": "^0.6.0",
"isomorphic-git": "1.25.7",
"json-order": "^1.1.3",
"jsonpath-plus": "^10.3.0",
"less": "^4.3.0",
"monaco-editor": "^0.52.2",
"nunjucks": "^3.2.4",
Expand Down
5 changes: 3 additions & 2 deletions packages/insomnia/src/common/__tests__/import.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,14 @@ describe('importRaw()', () => {
it('should import an openapi collection to an existing workspace with scope design', async () => {
const fixturePath = path.join(__dirname, '..', '__fixtures__', 'openapi', 'endpoint-security-input.yaml');
const content = fs.readFileSync(fixturePath, 'utf8').toString();

const disableLogs = console.log;
console.log = () => {};
const scanResult = await importUtil.scanResources([
{
contentStr: content,
},
]);

console.log = disableLogs;
expect(scanResult[0].type?.id).toBe('openapi3');
expect(scanResult[0].errors.length).toBe(0);
});
Expand Down
16 changes: 8 additions & 8 deletions packages/insomnia/src/common/__tests__/render.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ describe('render tests', () => {
const rootEnvironment = envBuilder
.data({
consume: '{{ replaced }}',
hashed: "{% hash 'md5', 'hex', value %}",
replaced: "{{ hashed | replace('f67565de946a899a534fd908e7eef872', 'cat') }}",
hashed: "{% hash 'sha1', 'hex', value %}",
replaced: "{{ hashed | replace('1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f', 'cat') }}",
value: 'ThisIsATopSecretValue',
})
.dataPropertyOrder({
Expand All @@ -65,9 +65,9 @@ describe('render tests', () => {
const context = await renderUtils.buildRenderContext({ ancestors: [], rootEnvironment });
expect(context).toEqual({
value: 'ThisIsATopSecretValue',
hashed: 'f67565de946a899a534fd908e7eef872',
replaced: 'f67565de946a899a534fd908e7eef872',
consume: 'f67565de946a899a534fd908e7eef872',
hashed: '1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f',
replaced: '1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f',
consume: '1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f',
});
// In runtime, this context is used to render, which re-evaluates the expression for replaced in the rootEnvironment by using the built context
// Regression test from issue 1917 - https://github.com/Kong/insomnia/issues/1917
Expand Down Expand Up @@ -450,8 +450,8 @@ describe('render tests', () => {
const rootEnvironment = envBuilder
.data({
consume: '{{ replaced }}',
hashed: "{% hash 'md5', 'hex', value %}",
replaced: "{{ hashed | replace('f67565de946a899a534fd908e7eef872', 'cat') }}",
hashed: "{% hash 'sha1', 'hex', value %}",
replaced: "{{ hashed | replace('1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f', 'cat') }}",
value: 'ThisIsATopSecretValue',
})
.dataPropertyOrder({
Expand All @@ -461,7 +461,7 @@ describe('render tests', () => {
const context = await renderUtils.buildRenderContext({ ancestors: [], rootEnvironment });
expect(context).toEqual({
value: 'ThisIsATopSecretValue',
hashed: 'f67565de946a899a534fd908e7eef872',
hashed: '1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f',
replaced: 'cat',
consume: 'cat',
});
Expand Down
121 changes: 75 additions & 46 deletions packages/insomnia/src/main/templating-worker-database.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,91 @@
import fs from 'node:fs';
import os from 'node:os';

import iconv from 'iconv-lite';

import { database as db } from '../common/database';
import * as models from '../models';
import type { Request as DBRequest } from '../models/request';
import type { RequestGroup } from '../models/request-group';
import type { Response } from '../models/response';
import type { Workspace } from '../models/workspace';
import { fetchRequestData, sendCurlAndWriteTimeline, tryToInterpolateRequest } from '../network/network';

export const resolveDbByKey = async (request: Request) => {
const url = new URL(request.url);
let result;
const body = await request.json();
if (url.host === 'request.getById'.toLowerCase()) {
result = await models.request.getById(body.id);
}
if (url.host === 'request.getAncestors'.toLowerCase()) {
result = await db.withAncestors<DBRequest | RequestGroup | Workspace>(body.request, body.types);
}
if (url.host === 'workspace.getById'.toLowerCase()) {
result = await models.workspace.getById(body.id);
}
if (url.host === 'oAuth2Token.getByRequestId'.toLowerCase()) {
result = await models.oAuth2Token.getByParentId(body.parentId);
}
if (url.host === 'cookieJar.getOrCreateForParentId'.toLowerCase()) {
result = await models.cookieJar.getOrCreateForParentId(body.parentId);
}
if (url.host === 'response.getLatestForRequestId'.toLowerCase()) {
result = await models.response.getLatestForRequest(body.requestId, body.environmentId);
}
if (url.host === 'response.getBodyBuffer'.toLowerCase()) {
result = await models.response.getBodyBuffer(body.response, body.readFailureValue);
}
if (url.host === 'pluginData.hasItem'.toLowerCase()) {
// url get normalized to lowercase, so we need to normalize the keys to lower case as well
const withLowercasedKeys = Object.fromEntries(
Object.entries(pluginToMainAPI).map(([key, value]) => [key.toLowerCase(), value]),
);
const result = await withLowercasedKeys[url.host.toLowerCase()](body);
return new Response(JSON.stringify(result));
};

// These are exposed to the templating worker and can be used by plugins from context.util
const pluginToMainAPI = {
'readFile': async (body: { path: string; encoding: 'utf8' }) => {
return await fs.promises.readFile(body.path, { encoding: body.encoding || 'utf8' });
},
'nodeOS': async () => {
return {
arch: os.arch(),
platform: os.platform(),
release: os.release(),
cpus: os.cpus(),
hostname: os.hostname(),
freemem: os.freemem(),
userInfo: os.userInfo(),
};
},
'decode': async (body: { buffer: Buffer; encoding: 'utf8' }) => {
return iconv.decode(body.buffer, body.encoding || 'utf8');
},
'request.getById': async (body: { id: string }) => {
return await models.request.getById(body.id);
},
'request.getAncestors': async (body: { request: DBRequest | RequestGroup | Workspace; types: string[] }) => {
return await db.withAncestors<DBRequest | RequestGroup | Workspace>(body.request, body.types);
},
'workspace.getById': async (body: { id: string }) => {
return await models.workspace.getById(body.id);
},
'oAuth2Token.getByRequestId': async (body: { parentId: string }) => {
return await models.oAuth2Token.getByParentId(body.parentId);
},
'cookieJar.getOrCreateForParentId': async (body: { parentId: string }) => {
return await models.cookieJar.getOrCreateForParentId(body.parentId);
},
'response.getLatestForRequestId': async (body: { requestId: string; environmentId: string }) => {
return await models.response.getLatestForRequest(body.requestId, body.environmentId);
},
'response.getBodyBuffer': async (body: { response: Response; readFailureValue: string }) => {
return await models.response.getBodyBuffer(body.response, body.readFailureValue);
},
'pluginData.hasItem': async (body: { pluginName: string; key: string }) => {
const doc = await models.pluginData.getByKey(body.pluginName, body.key);
result = doc !== null;
}
if (url.host === 'pluginData.setItem'.toLowerCase()) {
result = models.pluginData.upsertByKey(body.pluginName, body.key, String(body.value));
}
if (url.host === 'pluginData.getItem'.toLowerCase()) {
return doc !== null;
},
'pluginData.setItem': async (body: { pluginName: string; key: string; value: string }) => {
return models.pluginData.upsertByKey(body.pluginName, body.key, String(body.value));
},
'pluginData.getItem': async (body: { pluginName: string; key: string }) => {
const doc = await models.pluginData.getByKey(body.pluginName, body.key);
result = doc ? doc.value : null;
}
if (url.host === 'pluginData.removeItem'.toLowerCase()) {
result = models.pluginData.removeByKey(body.pluginName, body.key);
}
if (url.host === 'pluginData.clear'.toLowerCase()) {
result = models.pluginData.removeAll(body.pluginName);
}
if (url.host === 'pluginData.all'.toLowerCase()) {
return doc ? doc.value : null;
},
'pluginData.removeItem': async (body: { pluginName: string; key: string }) => {
return models.pluginData.removeByKey(body.pluginName, body.key);
},
'pluginData.clear': async (body: { pluginName: string }) => {
return models.pluginData.removeAll(body.pluginName);
},
'pluginData.all': async (body: { pluginName: string }) => {
const docs = (await models.pluginData.all(body.pluginName)) || [];
result = docs.map(d => ({
return docs.map(d => ({
value: d.value,
key: d.key,
}));
}
if (url.host === 'network.sendRequest'.toLowerCase()) {
},
'network.sendRequest': async (body: { request: DBRequest; extraInfo?: { requestChain: string[] } }) => {
const { request, environment, settings, clientCertificates, caCert, timelinePath, responseId } =
await fetchRequestData(body.request._id);

Expand All @@ -72,8 +103,6 @@ export const resolveDbByKey = async (request: Request) => {
timelinePath,
responseId,
);
result = await models.response.create({ ...response, bodyCompression: null }, settings.maxHistoryResponses);
}

return new Response(JSON.stringify(result));
return await models.response.create({ ...response, bodyCompression: null }, settings.maxHistoryResponses);
},
};
2 changes: 1 addition & 1 deletion packages/insomnia/src/main/window-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export function createWindow(): ElectronBrowserWindow {
preload: path.join(__dirname, 'preload.js'),
zoomFactor: getZoomFactor(),
nodeIntegration: true,
nodeIntegrationInWorker: true,
nodeIntegrationInWorker: false, // must remain false to ensure the nunjucks web worker sandbox does not have access to Node.js APIs
webviewTag: true,
// TODO: enable context isolation
contextIsolation: false,
Expand Down
Loading
Loading