test(insomnia-test): add http-request, cookie and environment specs

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Bob QiuandClaude Sonnet 5.5 authored and GitHub committed 2026-11-03 17:18:49 +08:00
1 parent 654897312d
commit 641d924b52
64 files changed
+4307

No files matched your search

@@ -0,0 +1,50 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/cookies`;
test("Verify Cookie With Mismatched Path Is Not Sent With HTTP Request", async ({
user,
}) => {
const { cookieFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url,
});
const mismatchedCookie = {
key: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/foo",
};
const matchedCookie = {
key: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/",
};
await cookieFlow.link(request, [mismatchedCookie, matchedCookie]);
const responseView = await httpRequestFlow.send(request);
const { cookies } = responseView.body as { cookies: Record<string, string> };
expect(cookies).not.toHaveProperty(mismatchedCookie.key);
expect(cookies).toMatchObject({ [matchedCookie.key]: matchedCookie.value });
});
@@ -0,0 +1,47 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/cookies`;
test("Verify Re-Linking Same Cookie Key Overwrites Previous Value", async ({
user,
}) => {
const { cookieFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url,
});
const key = faker.string.alphanumeric(8);
const staleValue = faker.string.alphanumeric(8);
const freshValue = faker.string.alphanumeric(8);
await cookieFlow.link(request, [
{ key, value: staleValue, domain: "localhost", path: "/" },
]);
const cookieList = await cookieFlow.link(request, [
{ key, value: freshValue, domain: "localhost", path: "/" },
]);
const responseView = await httpRequestFlow.send(request);
const { cookies } = responseView.body as { cookies: Record<string, string> };
expect(cookieList.filter((cookie) => cookie.key === key)).toHaveLength(1);
expect(cookieList).toMatchObject([{ key, value: freshValue }]);
expect(cookies).toMatchObject({ [key]: freshValue });
});
@@ -0,0 +1,51 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/cookies`;
test("Verify Expired Cookie Is Not Sent With HTTP Request", async ({
user,
}) => {
const { cookieFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url,
});
const expiredCookie = {
key: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/",
expires: new Date("2000-01-01T00:00:00"),
};
const activeCookie = {
key: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/",
};
await cookieFlow.link(request, [expiredCookie, activeCookie]);
const responseView = await httpRequestFlow.send(request);
const { cookies } = responseView.body as { cookies: Record<string, string> };
expect(cookies).not.toHaveProperty(expiredCookie.key);
expect(cookies).toMatchObject({ [activeCookie.key]: activeCookie.value });
});
@@ -0,0 +1,62 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/cookies`;
test("Verify Linked Cookie Is Sent With HTTP Request", async ({ user }) => {
const { cookieFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url,
});
const cookieList = await cookieFlow.link(request, [
{
key: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/",
},
{
key: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/",
},
{
key: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
domain: "example.org",
path: "/",
},
]);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
const { cookies } = responseView.body as { cookies: Record<string, string> };
expect(Object.keys(cookies)).toHaveLength(2);
const expectedCookies = Object.fromEntries(
cookieList
.filter((cookie) => cookie.domain === "localhost")
.map((cookie) => [cookie.key, cookie.value]),
);
expect(cookies).toMatchObject(expectedCookies);
});
@@ -0,0 +1,55 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/cookies`;
test("Verify __Host- Prefixed Cookie Is Only Sent When Marked HostOnly", async ({
user,
}) => {
const { cookieFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url,
});
const hostOnlyCookie = {
key: `__Host-${faker.string.alphanumeric(8)}`,
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/",
secure: true,
hostOnly: true,
};
const nonHostOnlyCookie = {
key: `__Host-${faker.string.alphanumeric(8)}`,
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/",
secure: true,
};
await cookieFlow.link(request, [hostOnlyCookie, nonHostOnlyCookie]);
const responseView = await httpRequestFlow.send(request);
const { cookies } = responseView.body as { cookies: Record<string, string> };
expect(cookies).toMatchObject({
[hostOnlyCookie.key]: hostOnlyCookie.value,
});
expect(cookies).not.toHaveProperty(nonHostOnlyCookie.key);
});
@@ -0,0 +1,66 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, HTTP_SERVER_HTTPS, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
test("Verify HttpOnly Cookie Flag Persists And Cookie Is Always Sent Over HTTP And HTTPS", async ({
user,
}) => {
const { cookieFlow, httpRequestFlow, workspaceFlow, preferencesFlow } =
user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
await preferencesFlow.set({ validateSSL: false });
const httpRequest = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${HTTP_SERVER}/cookies`,
});
const httpsRequest = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${HTTP_SERVER_HTTPS}/cookies`,
});
const httpOnlyCookie = {
key: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/",
httpOnly: true,
};
const cookieList = await cookieFlow.link(httpRequest, [httpOnlyCookie]);
const httpResponse = await httpRequestFlow.send(httpRequest);
const httpsResponse = await httpRequestFlow.send(httpsRequest);
expect(httpResponse.statusCode).toBe(200);
const { cookies: httpCookies } = httpResponse.body as {
cookies: Record<string, string>;
};
expect(httpCookies).toMatchObject({
[httpOnlyCookie.key]: httpOnlyCookie.value,
});
expect(httpsResponse.statusCode).toBe(200);
const { cookies: httpsCookies } = httpsResponse.body as {
cookies: Record<string, string>;
};
expect(httpsCookies).toMatchObject({
[httpOnlyCookie.key]: httpOnlyCookie.value,
});
expect(
cookieList.find((cookie) => cookie.key === httpOnlyCookie.key)?.httpOnly,
).toBe(true);
});
@@ -0,0 +1,52 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/cookies`;
test("Verify Editing A Cookie Via The Raw Tab Updates Its Fields And Is Sent", async ({
user,
}) => {
const { cookieFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const { cookiePage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url,
});
const key = faker.string.alphanumeric(8);
const oldValue = faker.string.alphanumeric(8);
const newValue = faker.string.alphanumeric(8);
await cookieFlow.link(request, [
{ key, value: oldValue, domain: "example.org", path: "/" },
]);
await cookiePage.open();
await cookiePage.editCookieRaw(key, `${key}=${newValue}; Domain=localhost; Path=/`);
const cookiesWhileOpen = await cookiePage.getCookies();
await cookiePage.close();
const responseView = await httpRequestFlow.send(request);
const { cookies: sentCookies } = responseView.body as {
cookies: Record<string, string>;
};
expect(cookiesWhileOpen).toMatchObject([
{ key, value: newValue, domain: "localhost", path: "/" },
]);
expect(sentCookies).toEqual({ [key]: newValue });
});
@@ -0,0 +1,62 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, HTTP_SERVER_HTTPS, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
test("Verify Secure Cookie Is Sent Over HTTPS But Not Over Plain HTTP", async ({
user,
}) => {
test.fail(true, 'INS-3179');
const { cookieFlow, httpRequestFlow, workspaceFlow, preferencesFlow } =
user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
await preferencesFlow.set({ validateSSL: false });
const httpRequest = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${HTTP_SERVER}/cookies`,
});
const httpsRequest = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${HTTP_SERVER_HTTPS}/cookies`,
});
const secureCookie = {
key: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
domain: "localhost",
path: "/",
secure: true,
};
await cookieFlow.link(httpRequest, [secureCookie]);
const httpsResponse = await httpRequestFlow.send(httpsRequest);
expect(httpsResponse.statusCode).toBe(200);
const { cookies: httpsCookies } = httpsResponse.body as {
cookies: Record<string, string>;
};
expect(httpsCookies).toMatchObject({
[secureCookie.key]: secureCookie.value,
});
const httpResponse = await httpRequestFlow.send(httpRequest);
const { cookies: httpCookies } = httpResponse.body as {
cookies: Record<string, string>;
};
expect(httpCookies).not.toHaveProperty(secureCookie.key);
});
@@ -0,0 +1,68 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const lowerCaseVariable = "caseVar";
const upperCaseVariable = "CaseVar";
test("Verify Variable Names Are Case Sensitive Across Environment Levels", async ({
user,
}) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const baseValue = faker.string.alphanumeric(10);
const subValue = faker.string.alphanumeric(10);
const baseEnvironment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: lowerCaseVariable,
value: baseValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
const subEnvironment = await environmentFlow.createSubEnvironment(baseEnvironment, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: upperCaseVariable,
value: subValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
await environmentFlow.link(collection, subEnvironment);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?lower={{${lowerCaseVariable}}}&upper={{${upperCaseVariable}}}`,
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
args: { lower: baseValue, upper: subValue },
});
});
@@ -0,0 +1,58 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const variableA = "a";
const variableB = "b";
test("Verify Circular Variable Reference Resolves To Literal Unresolved Text", async ({
user,
}) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const environment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: variableA,
value: `{{${variableB}}}`,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
{
id: "",
name: variableB,
value: `{{${variableA}}}`,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
await environmentFlow.link(collection, environment);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?value={{${variableA}}}`,
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({ args: { value: `{{${variableA}}}` } });
});
@@ -0,0 +1,60 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
test("Verify creating and duplicating a global environment", async ({
user,
}) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const variableValue = faker.string.alphanumeric(10);
const environment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: "globalVar",
value: variableValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
const duplicatedName = faker.string.alphanumeric(10);
const duplicatedEnvironment = await workspaceFlow.duplicateEnvironment(
environment,
duplicatedName,
);
await environmentFlow.link(collection, {
...duplicatedEnvironment,
name: "Base Environment",
});
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?value={{ globalVar }}`,
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(duplicatedEnvironment.id).not.toBe(environment.id);
expect(duplicatedEnvironment.name).toBe(duplicatedName);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({ args: { value: variableValue } });
});
@@ -0,0 +1,65 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const sharedVariable = "shared";
test("Verify a disabled sub-environment variable falls back to the base environment's value", async ({
user,
}) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const baseValue = faker.string.alphanumeric(10);
const subValue = faker.string.alphanumeric(10);
const base = await environmentFlow.createBaseEnvironment(project, {
name: "Base Environment",
kvPairData: [
{
id: "",
name: sharedVariable,
value: baseValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
const sub = await environmentFlow.createSubEnvironment(base, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: sharedVariable,
value: subValue,
type: EnvironmentKvPairDataType.STRING,
enabled: false,
},
],
});
await environmentFlow.link(collection, sub);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?value={{${sharedVariable}}}`,
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({ args: { value: baseValue } });
});
@@ -0,0 +1,70 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const leafVariable = "leaf";
const midVariable = "mid";
const topVariable = "top";
test("Verify Disabled Mid-Chain Variable Leaves Reference Unresolved", async ({
user,
}) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const leafValue = faker.string.alphanumeric(10);
const environment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: leafVariable,
value: leafValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
{
id: "",
name: midVariable,
value: `{{${leafVariable}}}`,
type: EnvironmentKvPairDataType.STRING,
enabled: false,
},
{
id: "",
name: topVariable,
value: `{{${midVariable}}}`,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
await environmentFlow.link(collection, environment);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?value={{${topVariable}}}`,
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
args: { value: `{{${midVariable}}}` },
});
});
@@ -0,0 +1,48 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ProjectType } from "../../enums/project-types";
import { test } from "../../misc/fixtures";
import type {
EnvironmentKvPairData} from "../../models/environment";
import {
EnvironmentKvPairDataType,
} from "../../models/environment";
import { Project } from "../../models/project";
test("Verify Environment Raw JSON Editor Reads Back And Persists Edits", async ({
user,
}) => {
const { environmentFlow, workspaceFlow } = user.flowManager;
const { environmentPage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const varA = {
id: "",
name: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
type: EnvironmentKvPairDataType.STRING,
enabled: true,
} satisfies EnvironmentKvPairData;
const environment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [varA],
});
await environmentPage.selectEnvironment(environment.name);
await environmentPage.toggleRawEdit();
const rawBefore = await environmentPage.getRawJson();
const newKey = faker.string.alphanumeric(8);
const newValue = faker.string.alphanumeric(8);
await environmentPage.setRawJson(JSON.stringify({ [newKey]: newValue }));
await user.page.reload();
await environmentPage.selectEnvironment(environment.name);
const rawAfterReload = await environmentPage.getRawJson();
expect(JSON.parse(rawBefore)).toEqual({ [varA.name]: varA.value });
expect(JSON.parse(rawAfterReload)).toEqual({ [newKey]: newValue });
});
@@ -0,0 +1,56 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ProjectType } from "../../enums/project-types";
import { test } from "../../misc/fixtures";
import type {
EnvironmentKvPairData} from "../../models/environment";
import {
EnvironmentKvPairDataType,
} from "../../models/environment";
import { Project } from "../../models/project";
test("Verify Environment Table Editor's Blank Row Is Not Persisted And Deleting A Row Leaves No Stale Text", async ({
user,
}) => {
const { environmentFlow, workspaceFlow } = user.flowManager;
const { environmentPage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const varA = {
id: "",
name: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
type: EnvironmentKvPairDataType.STRING,
enabled: true,
} satisfies EnvironmentKvPairData;
const varB = {
id: "",
name: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
type: EnvironmentKvPairDataType.STRING,
enabled: true,
} satisfies EnvironmentKvPairData;
const varC = {
id: "",
name: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
type: EnvironmentKvPairDataType.STRING,
enabled: true,
} satisfies EnvironmentKvPairData;
const environment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [varA, varB, varC],
});
const beforeDelete = await environmentFlow.get(environment.name);
await environmentPage.deleteRow(environmentPage.getRow(varB.name));
const afterDelete = await environmentFlow.get(environment.name);
expect(beforeDelete?.kvPairData).toEqual([varA, varB, varC]);
expect(afterDelete?.kvPairData).toEqual([varA, varC]);
});
@@ -0,0 +1,63 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const firstVariable = "a";
const secondVariable = "b";
test("Verify Multiple Variables Mixed In A Single Value Resolve Together", async ({
user,
}) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const firstValue = faker.string.alphanumeric(10);
const secondValue = faker.string.alphanumeric(10);
const environment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: firstVariable,
value: firstValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
{
id: "",
name: secondVariable,
value: secondValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
await environmentFlow.link(collection, environment);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?value={{${firstVariable}}}-{{${secondVariable}}}`,
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
args: { value: `${firstValue}-${secondValue}` },
});
});
@@ -0,0 +1,67 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const leafVariable = "leaf";
const midVariable = "mid";
const topVariable = "top";
test("Verify Multi-Level Nested Variable Resolution", async ({ user }) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const finalValue = faker.string.alphanumeric(10);
const environment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: leafVariable,
value: finalValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
{
id: "",
name: midVariable,
value: `{{${leafVariable}}}`,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
{
id: "",
name: topVariable,
value: `{{${midVariable}}}`,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
await environmentFlow.link(collection, environment);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?value={{${topVariable}}}`,
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({ args: { value: finalValue } });
});
@@ -0,0 +1,91 @@
import * as crypto from "node:crypto";
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import {
ENVIRONMENT_TYPE,
EnvironmentKvPairDataType,
} from "../../models/environment";
import { Project } from "../../models/project";
const testWithVaultKey = test.extend({
vaultKey: async ({}, use) => {
const jwk = {
alg: "A256GCM",
ext: true,
k: crypto.randomBytes(32).toString("base64url"),
key_ops: ["encrypt", "decrypt"],
kty: "oct",
};
await use(Buffer.from(JSON.stringify(jwk), "utf8").toString("base64"));
},
vaultSalt: async ({}, use) => {
await use(crypto.randomBytes(32).toString("hex"));
},
});
testWithVaultKey(
"Verify Secret-typed environment variables are stored encrypted and rendered decrypted at send-time",
async ({ user }) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } =
user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const globalEnvironment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
type: ENVIRONMENT_TYPE,
});
const secretValueFoo = faker.string.alphanumeric(10);
const secretValueHello = faker.string.alphanumeric(10);
const privateEnvironment = await environmentFlow.createSubEnvironment(globalEnvironment, {
name: faker.string.alphanumeric(10),
isPrivate: true,
kvPairData: [
{
id: "",
name: "foo",
value: secretValueFoo,
type: EnvironmentKvPairDataType.SECRET,
enabled: true,
},
{
id: "",
name: "hello",
value: secretValueHello,
type: EnvironmentKvPairDataType.SECRET,
enabled: true,
},
],
});
await environmentFlow.link(collection, privateEnvironment);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post`,
body: {
mimeType: ContentType.Plain,
text: "{{ _.vault.foo }}\n{{ _.vault.hello }}",
},
});
const responseView = await httpRequestFlow.send(request!);
expect(responseView.statusCode).toBe(200);
expect((responseView.body as { data: string }).data).toBe(
`${secretValueFoo}\n${secretValueHello}`,
);
},
);
@@ -0,0 +1,52 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const selfVariable = "a";
test("Verify Self-Referencing Variable Resolves To Literal Unresolved Text", async ({
user,
}) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const environment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: selfVariable,
value: `{{${selfVariable}}}`,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
await environmentFlow.link(collection, environment);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?value={{${selfVariable}}}`,
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
args: { value: `{{${selfVariable}}}` },
});
});
@@ -0,0 +1,73 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const sharedVariable = "shared";
test("Verify an empty sub-environment falls back to the base environment until it defines its own value", async ({
user,
}) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const { environmentPage, workspacePage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const baseValue = faker.string.alphanumeric(10);
const subValue = faker.string.alphanumeric(10);
const base = await environmentFlow.createBaseEnvironment(project, {
name: "Base Environment",
kvPairData: [
{
id: "",
name: sharedVariable,
value: baseValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
const sub = await environmentFlow.createSubEnvironment(base, {
name: faker.string.alphanumeric(10),
});
await environmentFlow.link(collection, sub);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?value={{${sharedVariable}}}`,
} satisfies HttpRequest);
const beforeOwnValue = await httpRequestFlow.send(request);
const baseNode = await workspacePage.findItemNode(base);
await workspacePage.clickNode(baseNode!);
await environmentPage.selectEnvironment(sub.name);
await environmentPage.setVariables([
{
id: "",
name: sharedVariable,
value: subValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
]);
const afterOwnValue = await httpRequestFlow.send(request);
expect(beforeOwnValue.statusCode).toBe(200);
expect(beforeOwnValue.body).toMatchObject({ args: { value: baseValue } });
expect(afterOwnValue.statusCode).toBe(200);
expect(afterOwnValue.body).toMatchObject({ args: { value: subValue } });
});
@@ -0,0 +1,64 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const sharedVariable = "shared";
test("Verify Sub Environment Variable Overrides Base Environment", async ({
user,
}) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const baseValue = faker.string.alphanumeric(10);
const subValue = faker.string.alphanumeric(10);
const baseEnvironment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: sharedVariable,
value: baseValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
const subEnvironment = await environmentFlow.createSubEnvironment(baseEnvironment, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: sharedVariable,
value: subValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
await environmentFlow.link(collection, subEnvironment);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?value={{${sharedVariable}}}`,
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({ args: { value: subValue } });
});
@@ -0,0 +1,48 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ProjectType } from "../../enums/project-types";
import { test } from "../../misc/fixtures";
import type {
EnvironmentKvPairData} from "../../models/environment";
import {
EnvironmentKvPairDataType,
} from "../../models/environment";
import { Project } from "../../models/project";
test("Verify Disabling A Row In The Table Editor Is Reflected On Read-Back", async ({
user,
}) => {
const { environmentFlow, workspaceFlow } = user.flowManager;
const { environmentPage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const varA = {
id: "",
name: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
type: EnvironmentKvPairDataType.STRING,
enabled: true,
} satisfies EnvironmentKvPairData;
const varB = {
id: "",
name: faker.string.alphanumeric(8),
value: faker.string.alphanumeric(8),
type: EnvironmentKvPairDataType.STRING,
enabled: true,
} satisfies EnvironmentKvPairData;
await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [varA, varB],
});
await environmentPage.disableRow(environmentPage.getRow(varA.name));
const variables = await environmentPage.getVariables();
expect(variables).toEqual([
{ ...varA, enabled: false },
{ ...varB, enabled: true },
]);
});
@@ -0,0 +1,45 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { MOCK_API_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import { Project } from "../../models/project";
const variableName = "unlinked";
test("Verify Unlinked Environment Variable Causes Error", async ({ user }) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: variableName,
value: "variable",
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${MOCK_API_SERVER}/{{${variableName}}}`,
});
await expect(httpRequestFlow.send(request)).rejects.toThrow(
/environment variable is missing.*have not been assigned.*unlinked/s,
);
});
@@ -0,0 +1,87 @@
import * as crypto from "node:crypto";
import path from "node:path";
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ProjectType } from "../../../enums/project-types";
import { test } from "../../../misc/fixtures";
import { Collection } from "../../../models/collection";
import {
ENVIRONMENT_TYPE,
EnvironmentKvPairDataType,
} from "../../../models/environment";
import { Project } from "../../../models/project";
const testWithVaultKey = test.extend({
vaultKey: async ({}, use) => {
const jwk = {
alg: "A256GCM",
ext: true,
k: crypto.randomBytes(32).toString("base64url"),
key_ops: ["encrypt", "decrypt"],
kty: "oct",
};
await use(Buffer.from(JSON.stringify(jwk), "utf8").toString("base64"));
},
vaultSalt: async ({}, use) => {
await use(crypto.randomBytes(32).toString("hex"));
},
});
testWithVaultKey(
"Verify legacy array/object vault environment variables render correctly and a scalar vault value throws the reserved-key error",
async ({ user }) => {
const { environmentFlow, httpRequestFlow, importFlow, workspaceFlow } =
user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const globalEnvironment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
type: ENVIRONMENT_TYPE,
});
const secretEnvironment = await environmentFlow.createSubEnvironment(globalEnvironment, {
name: faker.string.alphanumeric(10),
isPrivate: true,
kvPairData: [
{
id: "",
name: "secretKey",
value: faker.string.alphanumeric(10),
type: EnvironmentKvPairDataType.SECRET,
enabled: true,
},
],
});
await importFlow.importFile(
project,
path.join(__dirname, "vault-legacy-formats.yaml"),
);
const collection = new Collection("Vault Legacy Format Collection");
await environmentFlow.link(collection, secretEnvironment);
await environmentFlow.activate(collection, "legacy vault value array");
const arrayRequest = await httpRequestFlow.get("legacy-array-vault");
const arrayResponse = await httpRequestFlow.send(arrayRequest!);
await environmentFlow.activate(collection, "legacy vault value object");
const objectRequest = await httpRequestFlow.get("legacy-object-vault");
const objectResponse = await httpRequestFlow.send(objectRequest!);
await environmentFlow.activate(collection, "base with vault");
const invalidRequest = await httpRequestFlow.get("legacy-invalid-vault");
expect(arrayResponse.statusCode).toBe(200);
expect((arrayResponse.body as { data: string }).data).toBe(
"vault_array_a\nvault_array_b",
);
expect(objectResponse.statusCode).toBe(200);
expect((objectResponse.body as { data: string }).data).toBe("secv1\nsecv2");
await expect(httpRequestFlow.send(invalidRequest!)).rejects.toThrow(
/vault is a reserved key for insomnia vault/,
);
},
);
@@ -0,0 +1,173 @@
_type: export
__export_format: 4
__export_date: 2025-01-24T07:58:39.196Z
__export_source: insomnia.desktop.app:v10.3.1-beta.0
resources:
- _id: wrk_37e3ee9c2ce7468493378fa5e525b4b1
parentId: null
modified: 1737705410863
created: 1737705410863
name: Vault Legacy Format Collection
description: ""
scope: collection
_type: workspace
- _id: req_1c9ef3a2afae47d1bd960ae23de09750
parentId: wrk_37e3ee9c2ce7468493378fa5e525b4b1
modified: 1737617845875
created: 1734948333857
url: localhost:4060/post
name: legacy-array-vault
description: ""
method: POST
body:
mimeType: text/plain
text: |-
{{ _.vault[0] }}
{{ _.vault[1] }}
headers:
- name: Content-Type
value: text/plain
authentication: {}
metaSortKey: -1734948333857
isPrivate: false
pathParameters: []
settingStoreCookies: true
settingSendCookies: true
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingRebuildPath: true
settingFollowRedirects: global
_type: request
- _id: req_fb7fb8d4345f471fb53d03b069737a07
parentId: wrk_37e3ee9c2ce7468493378fa5e525b4b1
modified: 1737617874271
created: 1737617856040
url: localhost:4060/post
name: legacy-object-vault
description: ""
method: POST
body:
mimeType: text/plain
text: |-
{{ _.vault.v1 }}
{{ _.vault.v2 }}
headers:
- name: Content-Type
value: text/plain
authentication: {}
metaSortKey: -1729018003774
isPrivate: false
pathParameters: []
settingStoreCookies: true
settingSendCookies: true
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingRebuildPath: true
settingFollowRedirects: global
_type: request
- _id: req_2a150b45acb242cfa2db04d929a11085
parentId: wrk_37e3ee9c2ce7468493378fa5e525b4b1
modified: 1737617920254
created: 1737617896390
url: localhost:4060/post
name: legacy-invalid-vault
description: ""
method: POST
body:
mimeType: text/plain
text: ""
headers:
- name: Content-Type
value: text/plain
authentication: {}
metaSortKey: -1731983168815.5
isPrivate: false
pathParameters: []
settingStoreCookies: true
settingSendCookies: true
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingRebuildPath: true
settingFollowRedirects: global
_type: request
- _id: env_40681941450149a4a41f2dcbc22ec616
parentId: wrk_37e3ee9c2ce7468493378fa5e525b4b1
modified: 1737618683836
created: 1732861968102
name: Base Environment1
data:
a_hello: test
dataPropertyOrder:
"&":
- a_hello
color: null
isPrivate: false
metaSortKey: 1732861968102
environmentType: kv
kvPairData:
- id: envPair_62a7e9c0cdb949e0abf15e0fe4b1e8d3
name: a_hello
value: test
type: str
enabled: true
_type: environment
- _id: env_7ace551350dc40cbbb8302234ec0af0a
parentId: env_40681941450149a4a41f2dcbc22ec616
modified: 1737618683836
created: 1736745679348
name: base with vault
data:
vault: hello
dataPropertyOrder:
"&":
- vault
color: null
isPrivate: false
metaSortKey: 1736745679348
environmentType: kv
kvPairData:
- id: envPair_4bcd80eeb9c544c8a5cca0a1a6a85ffc
name: vault
value: hello
type: str
enabled: true
_type: environment
- _id: env_fce7e052bb99440a9019a162afea7f85
parentId: env_40681941450149a4a41f2dcbc22ec616
modified: 1737617847199
created: 1736745692249
name: legacy vault value array
data:
vault:
- vault_array_a
- vault_array_b
dataPropertyOrder:
"&":
- vault
color: null
isPrivate: false
metaSortKey: 1736745679398
environmentType: json
kvPairData: []
_type: environment
- _id: env_9214888ae2dc497e87a7f8f8edaf19f2
parentId: env_40681941450149a4a41f2dcbc22ec616
modified: 1737617875350
created: 1737617352406
name: legacy vault value object
data:
vault:
v1: secv1
v2: secv2
dataPropertyOrder:
"&":
- vault
"&~|vault":
- v1
- v2
color: null
isPrivate: false
metaSortKey: 1736881902959
environmentType: json
kvPairData: []
_type: environment
@@ -0,0 +1,76 @@
import { faker } from '@faker-js/faker';
import { expect } from "@playwright/test";
import { ContentType } from '../../enums/content-type';
import { HttpMethod } from '../../enums/http-method';
import { ProjectType } from '../../enums/project-types';
import { DEFAULT_TIMEOUT, HTTP_SERVER, test } from '../../misc/fixtures';
import { Collection } from '../../models/collection';
import { Project } from '../../models/project';
const url = `${HTTP_SERVER}/post`;
test('Verify insomnia.test/insomnia.expect report PASS/FAIL results, including a transient variable and insomnia.response accessors', async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(new Project(faker.string.alphanumeric(10), ProjectType.Local));
const collection = await workspaceFlow.createCollection(project, new Collection(faker.string.alphanumeric(10)));
const transientValue = faker.string.alphanumeric(10);
const sentValue = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: { mimeType: ContentType.JSON, text: `{"sent": "${sentValue}"}` },
afterResponseScript: `
insomnia.variables.set('transientVar', '${transientValue}');
insomnia.test('transient var', () => {
insomnia.expect(insomnia.variables.get('transientVar')).to.equal('${transientValue}');
});
insomnia.test('happyTestInFunc', () => {
insomnia.expect(200).to.equal(200);
});
insomnia.test('response accessors', () => {
insomnia.expect(insomnia.response.code).to.equal(200);
insomnia.expect(insomnia.response.status).to.equal('OK');
insomnia.expect(insomnia.response.json().json.sent).to.equal('${sentValue}');
insomnia.expect(insomnia.response.text()).to.include('${sentValue}');
insomnia.expect(insomnia.response.headers.get('Content-Type')).to.include('application/json');
insomnia.expect(insomnia.response.responseTime).to.be.a('number');
insomnia.expect(insomnia.response.size().body).to.be.above(0);
});
insomnia.test('response assertions', () => {
insomnia.response.to.have.status(200);
insomnia.response.to.have.header('Content-Type');
insomnia.response.to.have.jsonBody('data', '{"sent": "${sentValue}"}');
});
insomnia.test('unhappy tests', () => {
insomnia.expect(199).to.equal(200);
});
`,
});
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
await expect
.poll(() => responseView.tests?.(), { timeout: DEFAULT_TIMEOUT })
.toEqual(
expect.arrayContaining([
expect.objectContaining({ name: 'transient var', status: 'PASS' }),
expect.objectContaining({ name: 'happyTestInFunc', status: 'PASS' }),
expect.objectContaining({ name: 'response accessors', status: 'PASS' }),
expect.objectContaining({
name: 'response assertions',
status: 'PASS',
}),
expect.objectContaining({
name: 'unhappy tests',
status: 'FAIL',
error: expect.stringContaining('AssertionError: expected 199 to equal 200'),
}),
]),
);
});
@@ -0,0 +1,226 @@
import path from "node:path";
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
const uploadFilePath = path.join(
__dirname,
"..",
"..",
"misc",
"fixtures",
"upload-sample.txt",
);
test("Send HTTP Request with x-www-form-urlencoded Body", async ({ user }) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const title = faker.string.alphanumeric(8);
const userId = faker.string.numeric(3);
const request = {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: {
mimeType: ContentType.Form,
params: [
{ name: "title", value: title },
{ name: "userId", value: userId },
{ name: "excluded", value: "should-not-be-sent", disabled: true },
],
},
} satisfies HttpRequest;
const persisted = await httpRequestFlow.create(collection, request);
const responseView = await httpRequestFlow.send(request);
const raw = (responseView.body as { data: string }).data;
expect(persisted.body?.mimeType).toBe(ContentType.Form);
expect(persisted.body?.params).toMatchObject([
{ name: "title", value: title },
{ name: "userId", value: userId },
{ name: "excluded", disabled: true },
]);
expect(responseView.statusCode).toBe(200);
expect(Object.fromEntries(new URLSearchParams(raw))).toEqual({
title,
userId,
});
expect(responseView.body).toMatchObject({
headers: expect.objectContaining({
"content-type": expect.stringContaining(ContentType.Form),
}),
});
});
test("Send HTTP Request with JSON Body", async ({ user }) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const payload = { title: faker.string.alphanumeric(8), userId: 1 };
const request = {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: { mimeType: ContentType.JSON, text: JSON.stringify(payload) },
} satisfies HttpRequest;
await httpRequestFlow.create(collection, request);
const persisted = await httpRequestFlow.get(request.name);
const responseView = await httpRequestFlow.send(request);
expect(persisted).toMatchObject(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
json: payload,
headers: expect.objectContaining({
"content-type": expect.stringContaining(ContentType.JSON),
}),
});
});
test("Send HTTP Request with XML Body", async ({ user }) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const title = faker.string.alphanumeric(8);
const xml = `<note><title>${title}</title></note>`;
const request = {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: { mimeType: ContentType.XML, text: xml },
} satisfies HttpRequest;
await httpRequestFlow.create(collection, request);
const persisted = await httpRequestFlow.get(request.name);
const responseView = await httpRequestFlow.send(request);
expect(persisted).toMatchObject(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
data: xml,
headers: expect.objectContaining({
"content-type": expect.stringContaining(ContentType.XML),
}),
});
});
test("Send HTTP Request with No Body explicitly selected", async ({ user }) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: { mimeType: ContentType.NoBody },
} satisfies HttpRequest;
await httpRequestFlow.create(collection, request);
const persisted = await httpRequestFlow.get(request.name);
const responseView = await httpRequestFlow.send(request);
expect(persisted).toMatchObject({
method: request.method,
url: request.url,
body: undefined,
});
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
data: "",
json: null,
});
});
test("Send HTTP Request with multipart/form-data Body including a file field", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow, preferencesFlow } = user.flowManager;
// Insomnia only reads files from allow-listed directories (Preferences -> General -> Security).
await preferencesFlow.set({ dataFolders: [path.dirname(uploadFilePath)] });
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const title = faker.string.alphanumeric(8);
const request = {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: {
mimeType: ContentType.Multipart,
params: [
{ name: "title", value: title },
{ name: "upload", fileName: uploadFilePath },
],
},
} satisfies HttpRequest;
await httpRequestFlow.create(collection, request);
const persisted = await httpRequestFlow.get(request.name);
const responseView = await httpRequestFlow.send(request);
const raw = (responseView.body as { data: string }).data;
expect(persisted?.body?.mimeType).toBe(ContentType.Multipart);
expect(persisted?.body?.params?.[0]).toMatchObject({
name: "title",
value: title,
});
expect(persisted?.body?.params?.[1]?.name).toBe("upload");
expect(persisted?.body?.params?.[1]?.fileName).toContain("upload-sample.txt");
expect(responseView.statusCode).toBe(200);
expect(raw).toContain('name="title"');
expect(raw).toContain(title);
expect(raw).toContain('name="upload"; filename="upload-sample.txt"');
expect(raw).toContain("insomnia-e2e-upload-fixture");
expect(responseView.body).toMatchObject({
headers: expect.objectContaining({
"content-type": expect.stringContaining(ContentType.Multipart),
}),
});
});
@@ -0,0 +1,56 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { RequestState } from "../../enums/request-state";
import { DEFAULT_TIMEOUT, HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
test("Verify Cancelling an In-Flight HTTP Request Shows a Cancellation Message and a Later Request Still Succeeds", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const { httpRequestPage, responsePage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const slowRequest = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post`,
headers: [{ name: "x-reply-delay-ms", value: "10000" }],
});
const laterRequest = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post`,
});
await httpRequestFlow.get(slowRequest.name);
await httpRequestPage.send();
await expect
.poll(() => responsePage.getRequestState(), { timeout: DEFAULT_TIMEOUT })
.toBe(RequestState.Sending);
await responsePage.cancelRequest();
await expect
.poll(() => responsePage.hasMessage("Request was cancelled"), {
timeout: DEFAULT_TIMEOUT,
})
.toBe(true);
const requestStateAfterCancel = await responsePage.getRequestState();
const cancelledResponse = await responsePage.get();
const laterResponse = await httpRequestFlow.send(laterRequest);
expect(requestStateAfterCancel).toBe(RequestState.Idle);
expect(cancelledResponse.statusCode).toBeUndefined();
expect(laterResponse.statusCode).toBe(200);
});
@@ -0,0 +1,56 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
const bodyJsonPathFilter = "b64::JC5kYXRh::46b";
test("Verify A Response Tag Chain Resolves Through Multiple Requests", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const first = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: { mimeType: ContentType.Plain, text: "first" },
});
const second = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: {
mimeType: ContentType.Plain,
text: `{% response 'body', '${first.id}', '${bodyJsonPathFilter}', 'always', 60 %} and second`,
},
});
const third = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: {
mimeType: ContentType.Plain,
text: `{% response 'body', '${second.id}', '${bodyJsonPathFilter}', 'always', 60 %} and third`,
},
});
const responseView = await httpRequestFlow.send(third);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({ data: "first and second and third" });
});
@@ -0,0 +1,53 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { certPath } from "../../misc/certs";
import { DEFAULT_TIMEOUT, HTTP_SERVER_CUSTOM_CA_HTTPS, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER_CUSTOM_CA_HTTPS}/post`;
test("Verify Custom CA Root Certificate Establishes Trust For HTTPS Request", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow, certificatesFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const requestBeforeCa = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
});
const responseBeforeCa = await httpRequestFlow.send(requestBeforeCa);
expect(responseBeforeCa.statusCode).toBeUndefined();
await expect
.poll(() => responseBeforeCa.console?.(), { timeout: DEFAULT_TIMEOUT })
.toMatch(/unable to get local issuer certificate/i);
await certificatesFlow.setCaCertificate(
collection,
certPath("mtls-ca.pem"),
);
const requestAfterCa = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
});
const responseAfterCa = await httpRequestFlow.send(requestAfterCa);
expect(responseAfterCa.statusCode).toBe(200);
expect(responseAfterCa.body).toMatchObject({
headers: expect.objectContaining({ host: "localhost:4062" }),
});
});
@@ -0,0 +1,53 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { DEFAULT_TIMEOUT, HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Folder } from "../../models/folder";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify a folder-level script wrapping insomnia.variables.replaceIn resolves synchronously for a downstream request consuming it without await", async ({
user,
}) => {
const { folderFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const folder = await folderFlow.create(
collection,
new Folder(faker.string.alphanumeric(10)),
);
await folderFlow.setScripts(folder, {
preRequest: `
insomnia.globals.set('firstname', insomnia.variables.replaceIn('{{ $randomFirstName }}'));
`,
});
const request = await httpRequestFlow.create(folder, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
preRequestScript: `
const firstname = insomnia.globals.get('firstname');
console.log(typeof firstname, firstname);
`,
});
const responseView = await httpRequestFlow.send(request);
await expect
.poll(() => responseView.console?.(), { timeout: DEFAULT_TIMEOUT })
.toMatch(/log: string \S+/);
const consoleText = await responseView.console?.();
expect(consoleText).not.toContain("Promise");
expect(consoleText).not.toContain("undefined");
});
@@ -0,0 +1,50 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/get`;
test("Verify switching the Generate Code dialog's target language and client library regenerates the snippet", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url,
});
const shellCurlCode = await workspaceFlow.generateCode(request);
const pythonCode = await workspaceFlow.generateCode(request, {
target: "Python",
client: "http.client",
});
const nodeAxiosCode = await workspaceFlow.generateCode(request, {
target: "Node.js",
client: "Axios",
});
const nodeFetchCode = await workspaceFlow.generateCode(request, {
target: "Node.js",
client: "Fetch",
});
expect(shellCurlCode).toContain("curl");
expect(pythonCode).toContain("import http.client");
expect(nodeAxiosCode).toContain("require('axios')");
expect(nodeAxiosCode).toContain("axios.request");
expect(nodeFetchCode).toContain("require('node-fetch')");
expect(nodeFetchCode).not.toContain("axios");
});
@@ -0,0 +1,35 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify Generate Code Produces A Matching cURL Snippet", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url,
});
const code = await workspaceFlow.generateCode(request);
expect(code).toContain("curl");
expect(code).toContain("--request GET");
expect(code).toContain(url);
});
@@ -0,0 +1,52 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { DEFAULT_TIMEOUT, HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
test("Verify Import from URL Moves Query String Into Params and Preserves It on Send", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const { httpRequestPage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const paramName1 = faker.string.alphanumeric(8);
const paramValue1 = faker.string.alphanumeric(8);
const paramName2 = faker.string.alphanumeric(8);
const paramValue2 = faker.string.alphanumeric(8);
const baseUrl = `${HTTP_SERVER}/get`;
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${baseUrl}?${paramName1}=${paramValue1}&${paramName2}=${paramValue2}`,
});
await httpRequestPage.importParamsFromUrl();
const updatedUrl = await httpRequestPage.getUrl();
const updatedParams = await httpRequestPage.getParams();
const responseView = await httpRequestFlow.send(request!);
expect(updatedUrl).toBe(baseUrl);
expect(updatedParams).toEqual(
expect.arrayContaining([
expect.objectContaining({ name: paramName1, value: paramValue1 }),
expect.objectContaining({ name: paramName2, value: paramValue2 }),
]),
);
expect(responseView.statusCode).toBe(200);
await expect
.poll(() => responseView.console?.(), { timeout: DEFAULT_TIMEOUT })
.toContain(
`Preparing request to ${baseUrl}?${paramName1}=${paramValue1}&${paramName2}=${paramValue2}`,
);
});
@@ -0,0 +1,38 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = "http://[::1]:4060/post";
test("Verify HTTP request succeeds against a local IPv6 address", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const bodyText = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: url,
body: { mimeType: ContentType.Plain, text: bodyText },
});
const responseView = await httpRequestFlow.send(request!);
expect(responseView.statusCode).toBe(200);
expect(responseView.statusMessage).toBe("OK");
expect(responseView.body).toMatchObject({ data: bodyText });
});
@@ -0,0 +1,61 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
test("Verify Trailing Blank Row In Headers And Params Is Not Persisted Until Typed Into", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const { httpRequestPage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${HTTP_SERVER}/get`,
});
const headersBefore = await httpRequestPage.getHeaders();
const paramsBefore = await httpRequestPage.getParams();
const headerName = faker.string.alphanumeric(8);
const headerValue = faker.string.alphanumeric(8);
const paramName = faker.string.alphanumeric(8);
const paramValue = faker.string.alphanumeric(8);
await httpRequestPage.setHeaders([{ name: headerName, value: headerValue }]);
await httpRequestPage.setParams([{ name: paramName, value: paramValue }]);
const headersAfter = await httpRequestPage.getHeaders();
const paramsAfter = await httpRequestPage.getParams();
const isBlank = (pair: { name: string; value: string }) =>
pair.name === "" && pair.value === "";
expect(request).toBeDefined();
expect(headersBefore.some(isBlank)).toBe(false);
expect(paramsBefore.some(isBlank)).toBe(false);
expect(headersAfter.some(isBlank)).toBe(false);
expect(paramsAfter.some(isBlank)).toBe(false);
expect(headersAfter).toHaveLength(headersBefore.length + 1);
expect(paramsAfter).toHaveLength(paramsBefore.length + 1);
expect(headersAfter).toEqual(
expect.arrayContaining([
{ name: headerName, value: headerValue, disabled: false },
]),
);
expect(paramsAfter).toEqual(
expect.arrayContaining([
{ name: paramName, value: paramValue, disabled: false },
]),
);
});
@@ -0,0 +1,106 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify LiquidJS control flow tags render correctly", async ({ user }) => {
const { environmentFlow, httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const envValue = faker.string.alphanumeric(8);
const environment = await environmentFlow.createBaseEnvironment(project, {
name: "Base Environment",
kvPairData: [
{
id: "",
name: "envVar",
value: envValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
await environmentFlow.link(collection, environment);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: {
mimeType: ContentType.Plain,
text: `{{ envVar }}-{% assign x = 5 %}{% if x > 3 %}big{% else %}small{% endif %}-{% for i in (1..3) %}{{ i }}{% endfor %}-{% unless x == 5 %}no{% else %}yes{% endunless %}`,
},
} satisfies HttpRequest);
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
data: `${envValue}-big-123-yes`,
});
});
test("Verify LiquidJS include/render/layout tags are blocked", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const includeRequest = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: { mimeType: ContentType.Plain, text: `{% include 'foo' %}` },
} satisfies HttpRequest);
const renderRequest = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: { mimeType: ContentType.Plain, text: `{% render 'foo' %}` },
} satisfies HttpRequest);
const layoutRequest = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: { mimeType: ContentType.Plain, text: `{% layout 'foo' %}` },
} satisfies HttpRequest);
const blockedTagPattern = /include.*render.*layout.*disabled/is;
await expect(httpRequestFlow.send(includeRequest)).rejects.toThrow(
blockedTagPattern,
);
await workspaceFlow.closeDialog();
await expect(httpRequestFlow.send(renderRequest)).rejects.toThrow(
blockedTagPattern,
);
await workspaceFlow.closeDialog();
await expect(httpRequestFlow.send(layoutRequest)).rejects.toThrow(
blockedTagPattern,
);
await workspaceFlow.closeDialog();
});
@@ -0,0 +1,78 @@
import path from "node:path";
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { certPath } from "../../misc/certs";
import { DEFAULT_TIMEOUT, HTTP_SERVER_MTLS, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER_MTLS}/post`;
test("Verify Client Certificate Toggle Controls mTLS Enforcement For HTTP Request", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow, preferencesFlow, certificatesFlow } =
user.flowManager;
await preferencesFlow.set({
validateSSL: false,
dataFolders: [path.join(__dirname, "../../misc/fixtures")],
});
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const requestBeforeCert = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
});
const responseBeforeCert = await httpRequestFlow.send(requestBeforeCert);
expect(responseBeforeCert.statusCode).toBeUndefined();
await expect
.poll(() => responseBeforeCert.console?.(), { timeout: DEFAULT_TIMEOUT })
.toMatch(/certificate required/i);
await certificatesFlow.addClientCertificate(collection, {
host: "localhost",
cert: certPath("mtls-client-cert.pem"),
key: certPath("mtls-client-key.pem"),
});
const requestWithCert = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
});
const responseWithCert = await httpRequestFlow.send(requestWithCert);
expect(responseWithCert.statusCode).toBe(200);
expect(responseWithCert.body).toMatchObject({
headers: expect.objectContaining({ host: "localhost:4063" }),
});
await certificatesFlow.setClientCertificateEnabled(
collection,
"localhost",
false,
);
const requestAfterDisable = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
});
const responseAfterDisable = await httpRequestFlow.send(requestAfterDisable);
expect(responseAfterDisable.statusCode).toBeUndefined();
await expect
.poll(() => responseAfterDisable.console?.(), { timeout: DEFAULT_TIMEOUT })
.toMatch(/certificate required/i);
});
@@ -0,0 +1,56 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { AuthTypeOAuth1 } from "../../models/http-request";
import { Project } from "../../models/project";
test("Verify OAuth 1.0 auth fields persist and sign the sent request", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const authentication: AuthTypeOAuth1 = {
type: "oauth1",
consumerKey: faker.string.alphanumeric(10),
consumerSecret: faker.string.alphanumeric(10),
tokenKey: faker.string.alphanumeric(10),
tokenSecret: faker.string.alphanumeric(10),
signatureMethod: "HMAC-SHA256",
callback: "https://example.com/callback",
version: "1.0",
realm: faker.string.alphanumeric(8),
};
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post`,
authentication: authentication,
});
const responseView = await httpRequestFlow.send(request);
const authHeader = (responseView.body as { headers: Record<string, string> })
.headers.authorization;
expect(responseView.statusCode).toBe(200);
expect(authHeader).toContain("OAuth ");
expect(authHeader).toContain(
`oauth_consumer_key="${authentication.consumerKey}"`,
);
expect(authHeader).toContain(`oauth_token="${authentication.tokenKey}"`);
expect(authHeader).toContain(
`oauth_signature_method="${authentication.signatureMethod}"`,
);
expect(authHeader).toContain(`oauth_version="${authentication.version}"`);
});
@@ -0,0 +1,62 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, OAUTH2_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { AuthTypeOAuth2 } from "../../models/http-request";
import { Project } from "../../models/project";
for (const pkceMethod of ["S256", "plain"] as const) {
test(`Verify Authorization Code grant with PKCE (${pkceMethod}) is verified server-side and authorizes the sent request`, async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const authentication: AuthTypeOAuth2 = {
type: "oauth2",
grantType: "authorization_code",
authorizationUrl: `${OAUTH2_SERVER}/authorize`,
accessTokenUrl: `${OAUTH2_SERVER}/token`,
clientId: OAUTH2_CLIENT_ID,
clientSecret: OAUTH2_CLIENT_SECRET,
redirectUrl: `${OAUTH2_SERVER}/health`,
usePkce: true,
pkceMethod,
};
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${OAUTH2_SERVER}/resource`,
authentication: authentication,
});
const tokens = await httpRequestFlow.fetchOAuth2Tokens(request);
const lastTokenRequest = await (
await fetch(
`${OAUTH2_SERVER}/_debug/last-token-request?access_token=${encodeURIComponent(tokens.accessToken)}`,
)
).json();
const responseView = await httpRequestFlow.send(request);
const body = responseView.body as { authorization?: string };
expect(tokens.accessToken).not.toBe("");
expect(lastTokenRequest.grantType).toBe("authorization_code");
expect(lastTokenRequest.pkceUsed).toBe(true);
expect(lastTokenRequest.pkceMethod).toBe(pkceMethod);
expect(lastTokenRequest.pkceVerified).toBe(true);
expect(responseView.statusCode).toBe(200);
expect(body.authorization).toBe(`Bearer ${tokens.accessToken}`);
});
}
@@ -0,0 +1,58 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, OAUTH2_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { AuthTypeOAuth2 } from "../../models/http-request";
import { Project } from "../../models/project";
test("Verify Authorization Code grant fetches tokens via a popup and authorizes the sent request", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const authentication: AuthTypeOAuth2 = {
type: "oauth2",
grantType: "authorization_code",
authorizationUrl: `${OAUTH2_SERVER}/authorize`,
accessTokenUrl: `${OAUTH2_SERVER}/token`,
clientId: OAUTH2_CLIENT_ID,
clientSecret: OAUTH2_CLIENT_SECRET,
redirectUrl: `${OAUTH2_SERVER}/health`,
};
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${OAUTH2_SERVER}/resource`,
authentication: authentication,
});
const tokens = await httpRequestFlow.fetchOAuth2Tokens(request);
const lastTokenRequest = await (
await fetch(
`${OAUTH2_SERVER}/_debug/last-token-request?access_token=${encodeURIComponent(tokens.accessToken)}`,
)
).json();
const responseView = await httpRequestFlow.send(request);
const body = responseView.body as { authorization?: string };
expect(tokens.accessToken).not.toBe("");
expect(tokens.refreshToken).not.toBe("");
expect(tokens.identityToken).not.toBe("");
expect(lastTokenRequest.grantType).toBe("authorization_code");
expect(lastTokenRequest.pkceUsed).toBe(false);
expect(responseView.statusCode).toBe(200);
expect(body.authorization).toBe(`Bearer ${tokens.accessToken}`);
});
@@ -0,0 +1,57 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, OAUTH2_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { AuthTypeOAuth2 } from "../../models/http-request";
import { Project } from "../../models/project";
test("Verify Client Credentials grant fetches tokens with no popup and authorizes the sent request", async ({
user,
insomnia,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const authentication: AuthTypeOAuth2 = {
type: "oauth2",
grantType: "client_credentials",
accessTokenUrl: `${OAUTH2_SERVER}/token`,
clientId: OAUTH2_CLIENT_ID,
clientSecret: OAUTH2_CLIENT_SECRET,
};
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${OAUTH2_SERVER}/resource`,
authentication: authentication,
});
const windowsBeforeFetch = insomnia.windows().length;
const tokens = await httpRequestFlow.fetchOAuth2Tokens(request);
const windowsAfterFetch = insomnia.windows().length;
const lastTokenRequest = await (
await fetch(
`${OAUTH2_SERVER}/_debug/last-token-request?access_token=${encodeURIComponent(tokens.accessToken)}`,
)
).json();
const responseView = await httpRequestFlow.send(request);
const body = responseView.body as { authorization?: string };
expect(tokens.accessToken).not.toBe("");
expect(windowsAfterFetch).toBe(windowsBeforeFetch);
expect(lastTokenRequest.grantType).toBe("client_credentials");
expect(responseView.statusCode).toBe(200);
expect(body.authorization).toBe(`Bearer ${tokens.accessToken}`);
});
@@ -0,0 +1,53 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { AuthType } from "../../enums/auth-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, OAUTH2_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Folder } from "../../models/folder";
import { Project } from "../../models/project";
test("Verify a request set to Inherit from parent picks up its folder's OAuth 2.0 authentication", async ({
user,
}) => {
const { workspaceFlow, folderFlow, httpRequestFlow } = user.flowManager;
const { httpRequestPage, folderPage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const folder = await folderFlow.create(
collection,
new Folder(faker.string.alphanumeric(10)),
);
await folderFlow.open(folder);
await folderPage.auth.setOAuth2Fields({
type: "oauth2",
grantType: "client_credentials",
accessTokenUrl: `${OAUTH2_SERVER}/token`,
clientId: OAUTH2_CLIENT_ID,
clientSecret: OAUTH2_CLIENT_SECRET,
});
const folderTokens = await folderFlow.fetchOAuth2Tokens(folder);
const request = await httpRequestFlow.create(folder, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${OAUTH2_SERVER}/resource`,
});
await httpRequestPage.auth.setAuthType(AuthType.Inherit);
const responseView = await httpRequestFlow.send(request);
const body = responseView.body as { authorization?: string };
expect(folderTokens.accessToken).not.toBe("");
expect(responseView.statusCode).toBe(200);
expect(body.authorization).toBe(`Bearer ${folderTokens.accessToken}`);
});
@@ -0,0 +1,85 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { OAUTH2_CLIENT_ID, OAUTH2_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { AuthTypeOAuth2 } from "../../models/http-request";
import { Project } from "../../models/project";
test("Verify Implicit grant with response type ID Token fetches only an identity token", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const authentication: AuthTypeOAuth2 = {
type: "oauth2",
grantType: "implicit",
authorizationUrl: `${OAUTH2_SERVER}/authorize`,
clientId: OAUTH2_CLIENT_ID,
redirectUrl: `${OAUTH2_SERVER}/health`,
responseType: "id_token",
};
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${OAUTH2_SERVER}/resource`,
authentication: authentication,
});
const tokens = await httpRequestFlow.fetchOAuth2Tokens(request);
// With no separate access_token in the fragment, the app displays the
// identity token in the Access Token field too, rather than leaving it
// blank.
expect(tokens.identityToken).not.toBe("");
expect(tokens.accessToken).toBe(tokens.identityToken);
});
test("Verify Implicit grant with response type ID and Access Token authorizes the sent request", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const authentication: AuthTypeOAuth2 = {
type: "oauth2",
grantType: "implicit",
authorizationUrl: `${OAUTH2_SERVER}/authorize`,
clientId: OAUTH2_CLIENT_ID,
redirectUrl: `${OAUTH2_SERVER}/health`,
responseType: "id_token token",
};
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${OAUTH2_SERVER}/resource`,
authentication: authentication,
});
const tokens = await httpRequestFlow.fetchOAuth2Tokens(request);
const responseView = await httpRequestFlow.send(request);
const body = responseView.body as { authorization?: string };
expect(tokens.identityToken).not.toBe("");
expect(tokens.accessToken).not.toBe("");
expect(responseView.statusCode).toBe(200);
expect(body.authorization).toBe(`Bearer ${tokens.accessToken}`);
});
@@ -0,0 +1,60 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, OAUTH2_PASSWORD, OAUTH2_SERVER, OAUTH2_USERNAME, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { AuthTypeOAuth2 } from "../../models/http-request";
import { Project } from "../../models/project";
test("Verify Resource Owner Password Credentials grant fetches tokens with no popup and authorizes the sent request", async ({
user,
insomnia,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const authentication: AuthTypeOAuth2 = {
type: "oauth2",
grantType: "password",
accessTokenUrl: `${OAUTH2_SERVER}/token`,
clientId: OAUTH2_CLIENT_ID,
clientSecret: OAUTH2_CLIENT_SECRET,
username: OAUTH2_USERNAME,
password: OAUTH2_PASSWORD,
};
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${OAUTH2_SERVER}/resource`,
authentication: authentication,
});
const windowsBeforeFetch = insomnia.windows().length;
const tokens = await httpRequestFlow.fetchOAuth2Tokens(request);
const windowsAfterFetch = insomnia.windows().length;
const lastTokenRequest = await (
await fetch(
`${OAUTH2_SERVER}/_debug/last-token-request?access_token=${encodeURIComponent(tokens.accessToken)}`,
)
).json();
const responseView = await httpRequestFlow.send(request);
const body = responseView.body as { authorization?: string };
expect(tokens.accessToken).not.toBe("");
expect(tokens.refreshToken).not.toBe("");
expect(windowsAfterFetch).toBe(windowsBeforeFetch);
expect(lastTokenRequest.grantType).toBe("password");
expect(responseView.statusCode).toBe(200);
expect(body.authorization).toBe(`Bearer ${tokens.accessToken}`);
});
@@ -0,0 +1,97 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { OAUTH2_CLIENT_ID, OAUTH2_CLIENT_SECRET, OAUTH2_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { AuthTypeOAuth2 } from "../../models/http-request";
import { Project } from "../../models/project";
test("Verify refreshing an existing OAuth 2.0 token issues a new access token without reopening the authorization window", async ({
user,
insomnia,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const authentication: AuthTypeOAuth2 = {
type: "oauth2",
grantType: "authorization_code",
authorizationUrl: `${OAUTH2_SERVER}/authorize`,
accessTokenUrl: `${OAUTH2_SERVER}/token`,
clientId: OAUTH2_CLIENT_ID,
clientSecret: OAUTH2_CLIENT_SECRET,
redirectUrl: `${OAUTH2_SERVER}/health`,
};
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${OAUTH2_SERVER}/resource`,
authentication: authentication,
});
const tokensAfterFetch = await httpRequestFlow.fetchOAuth2Tokens(request);
const windowsBeforeRefresh = insomnia.windows().length;
const tokensAfterRefresh = await httpRequestFlow.fetchOAuth2Tokens(request);
const windowsAfterRefresh = insomnia.windows().length;
const lastTokenRequest = await (
await fetch(
`${OAUTH2_SERVER}/_debug/last-token-request?access_token=${encodeURIComponent(tokensAfterRefresh.accessToken)}`,
)
).json();
expect(tokensAfterFetch.accessToken).not.toBe("");
expect(windowsAfterRefresh).toBe(windowsBeforeRefresh);
expect(lastTokenRequest.grantType).toBe("refresh_token");
expect(tokensAfterRefresh.refreshToken).toBe(tokensAfterFetch.refreshToken);
expect(tokensAfterRefresh.accessToken).not.toBe(tokensAfterFetch.accessToken);
});
test("Verify clearing OAuth 2.0 tokens wipes the stored Refresh/Identity/Access Token fields", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const { httpRequestPage } = user.pageManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const authentication: AuthTypeOAuth2 = {
type: "oauth2",
grantType: "client_credentials",
accessTokenUrl: `${OAUTH2_SERVER}/token`,
clientId: OAUTH2_CLIENT_ID,
clientSecret: OAUTH2_CLIENT_SECRET,
};
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${OAUTH2_SERVER}/resource`,
authentication: authentication,
});
const tokensAfterFetch = await httpRequestFlow.fetchOAuth2Tokens(request);
await httpRequestPage.auth.clearOAuth2Tokens();
const tokensAfterClear = await httpRequestPage.auth.getOAuth2Tokens();
expect(tokensAfterFetch.accessToken).not.toBe("");
expect(tokensAfterClear.accessToken).toBe("");
expect(tokensAfterClear.refreshToken).toBe("");
expect(tokensAfterClear.identityToken).toBe("");
});
@@ -0,0 +1,91 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify pending async work in a pre-request script (Promise, setTimeout, sendRequest callback/await) is settled before the request is sent, and a synchronous replaceIn call in the same script is unaffected by it", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const syncVariableName = faker.string.alpha(8);
const syncVariableValue = faker.string.alphanumeric(10);
const marker = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: {
mimeType: ContentType.JSON,
text: `{"asyncDoneViaPromise": {{ asyncDoneViaPromise }}, "asyncDoneViaTimeout": {{ asyncDoneViaTimeout }}, "asyncDoneViaCallback": {{ asyncDoneViaCallback }}, "bodyFromAwait": {{ bodyFromAwait }}, "bodyFromCallback": {{ bodyFromCallback }}, "syncReplaceInResult": "{{ syncReplaceInResult }}"}`,
},
preRequestScript: `
insomnia.environment.set('${syncVariableName}', '${syncVariableValue}');
const syncReplaceInResult = insomnia.environment.replaceIn('{{ ${syncVariableName} }}');
insomnia.environment.set('syncReplaceInResult', syncReplaceInResult);
new Promise((resolve) => {
setTimeout(() => {
insomnia.environment.set('asyncDoneViaPromise', true);
resolve();
}, 500);
});
setTimeout(() => {
insomnia.environment.set('asyncDoneViaTimeout', true);
}, 500);
insomnia.sendRequest({ url: '${url}', method: 'POST' }, (err, resp) => {
if (err != null) {
throw err;
} else {
insomnia.environment.set('asyncDoneViaCallback', true);
}
});
let respFromCallback;
const respFromAwait = await insomnia.sendRequest({
url: '${url}',
method: 'POST',
body: { mode: 'raw', raw: '${marker}' },
}, (err, resp) => {
if (err != null) {
throw err;
} else {
respFromCallback = resp;
}
});
insomnia.environment.set('bodyFromAwait', respFromAwait.body);
insomnia.environment.set('bodyFromCallback', respFromCallback.body);
`,
});
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
json: {
asyncDoneViaPromise: true,
asyncDoneViaTimeout: true,
asyncDoneViaCallback: true,
bodyFromAwait: expect.objectContaining({ data: marker }),
bodyFromCallback: expect.objectContaining({ data: marker }),
syncReplaceInResult: syncVariableValue,
},
});
});
@@ -0,0 +1,42 @@
import { faker } from '@faker-js/faker';
import { expect } from "@playwright/test";
import { HttpMethod } from '../../enums/http-method';
import { ProjectType } from '../../enums/project-types';
import { HTTP_SERVER, test } from '../../misc/fixtures';
import { Collection } from '../../models/collection';
import { Project } from '../../models/project';
test('Verify pre-request script manages cookies via insomnia.cookies.jar() and they are sent with the request', async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(new Project(faker.string.alphanumeric(10), ProjectType.Local));
const collection = await workspaceFlow.createCollection(project, new Collection(faker.string.alphanumeric(10)));
const keptName = faker.string.alpha(8);
const keptValue = faker.string.alphanumeric(10);
const unsetName = faker.string.alpha(9);
const objectName = faker.string.alpha(10);
const objectValue = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${HTTP_SERVER}/cookies`,
preRequestScript: `
const jar = insomnia.cookies.jar();
const call = (fn, ...args) => new Promise((resolve, reject) => fn.call(jar, ...args, (err, res) => err ? reject(err) : resolve(res)));
await call(jar.set, '${HTTP_SERVER}', '${keptName}', { key: '${keptName}', value: '${keptValue}', domain: 'localhost' });
await call(jar.set, '${HTTP_SERVER}', '${unsetName}', { key: '${unsetName}', value: 'temporary', domain: 'localhost' });
await call(jar.set, '${HTTP_SERVER}', '${objectName}', { key: '${objectName}', value: '${objectValue}', domain: 'localhost' });
await call(jar.unset, '${HTTP_SERVER}', '${unsetName}');
`,
});
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toEqual({
cookies: { [keptName]: keptValue, [objectName]: objectValue },
});
});
@@ -0,0 +1,63 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { DEFAULT_TIMEOUT, HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify a thrown error in pre-request script surfaces in the response console", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const errorMessage = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
preRequestScript: `throw new Error('${errorMessage}');`,
});
const responseView = await httpRequestFlow.send(request);
await expect
.poll(() => responseView.console?.(), { timeout: DEFAULT_TIMEOUT })
.toContain(errorMessage);
});
test("Verify accessing an invalid field in pre-request script surfaces in the response console", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
preRequestScript: `insomnia.INVALID_FIELD.set('', '');`,
});
const responseView = await httpRequestFlow.send(request);
await expect
.poll(() => responseView.console?.(), { timeout: DEFAULT_TIMEOUT })
.toContain("Cannot read properties of undefined (reading 'set')");
});
@@ -0,0 +1,75 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify pre-request script overrides base environment values through the environment chain and persists set/get variables", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow, environmentFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const baseEnvironment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
});
const subEnvironment = await environmentFlow.createSubEnvironment(baseEnvironment, {
name: faker.string.alphanumeric(10),
});
await environmentFlow.link(collection, subEnvironment);
const fallbackValue = faker.string.alphanumeric(10);
const baseScriptValue = faker.string.alphanumeric(10);
const envScriptValue = faker.string.alphanumeric(10);
const preDefinedValue = faker.string.alphanumeric(10);
const varStr = faker.string.alphanumeric(10);
const varNum = faker.number.int({ min: 1, max: 1000 });
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: {
mimeType: ContentType.JSON,
text: `{"fallbackToBase": "{{ fallbackToBase }}", "scriptValue": "{{ scriptValue }}", "preDefinedValue": "{{ preDefinedValue }}", "varStr": "{{ varStr }}", "varNum": {{ varNum }}, "varBool": {{ varBool }}}`,
},
preRequestScript: `
insomnia.baseEnvironment.set('fallbackToBase', '${fallbackValue}');
insomnia.baseEnvironment.set('scriptValue', '${baseScriptValue}');
insomnia.environment.set('scriptValue', '${envScriptValue}');
insomnia.baseEnvironment.set('preDefinedValue', '${preDefinedValue}');
insomnia.variables.set('varStr', '${varStr}');
insomnia.variables.set('varNum', ${varNum});
insomnia.variables.set('varBool', true);
insomnia.environment.set('varStr', insomnia.variables.get('varStr'));
insomnia.environment.set('varNum', insomnia.variables.get('varNum'));
insomnia.environment.set('varBool', insomnia.variables.get('varBool'));
`,
});
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
json: {
fallbackToBase: fallbackValue,
scriptValue: envScriptValue,
preDefinedValue: preDefinedValue,
varStr,
varNum,
varBool: true,
},
});
});
@@ -0,0 +1,126 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify pre-request script can eval() and require Node built-in modules, external modules, and insomnia-collection classes", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const parsedUrl = new URL(
"https://user:pwd@insomnia.com:6666/p1?q1=a&q2=b#hashcontent",
);
const builtinModules = [
"path",
"assert",
"buffer",
"util",
"url",
"punycode",
"querystring",
"string_decoder",
"stream",
"timers",
"events",
];
const externalModules = {
atob: "atob",
btoa: "btoa",
chai: "chai",
cheerio: "cheerio",
crypto: "crypto-js",
csv: "csv-parse/lib/sync",
lodash: "lodash",
moment: "moment",
tv4: "tv4",
uuid: "uuid",
xml2js: "xml2js",
};
const externalModuleKeys = Object.keys(externalModules);
const propertyId = faker.string.alphanumeric(10);
const propertyName = faker.string.alphanumeric(10);
const headerKey = faker.string.alphanumeric(10);
const headerValue = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: {
mimeType: ContentType.JSON,
text: `{"evalResult": {{ evalResult }}, "hash": "{{ hash }}", "host": "{{ host }}", "hostname": "{{ hostname }}", "origin": "{{ origin }}", "password": "{{ password }}", "pathname": "{{ pathname }}", "port": "{{ port }}", "protocol": "{{ protocol }}", "search": "{{ search }}", "username": "{{ username }}", "searchParam": "{{ searchParam }}", ${builtinModules.map((m) => `"${m}": {{ ${m} }}`).join(", ")}, ${externalModuleKeys.map((k) => `"${k}": {{ ${k} }}`).join(", ")}, "builtInLodash": {{ builtInLodash }}, "uuidNil": "{{ uuidNil }}", "propJson": {{ propJson }}, "headerJson": {{ headerJson }}}`,
},
preRequestScript: `
const evalResult = eval('8+8');
insomnia.environment.set('evalResult', evalResult);
const { URL } = require('url');
const parsedUrl = new URL('${parsedUrl.href}');
insomnia.environment.set('hash', parsedUrl.hash);
insomnia.environment.set('host', parsedUrl.host);
insomnia.environment.set('hostname', parsedUrl.hostname);
insomnia.environment.set('origin', parsedUrl.origin);
insomnia.environment.set('password', parsedUrl.password);
insomnia.environment.set('pathname', parsedUrl.pathname);
insomnia.environment.set('port', parsedUrl.port);
insomnia.environment.set('protocol', parsedUrl.protocol);
insomnia.environment.set('search', parsedUrl.search);
insomnia.environment.set('username', parsedUrl.username);
insomnia.environment.set('searchParam', parsedUrl.searchParams.toString());
${builtinModules.map((m) => `insomnia.environment.set('${m}', require('${m}') != null);`).join("\n")}
${externalModuleKeys.map((k) => `insomnia.environment.set('${k}', require('${externalModules[k as keyof typeof externalModules]}') != null);`).join("\n")}
insomnia.environment.set('builtInLodash', _ != null);
const uuid = require('uuid');
insomnia.environment.set('uuidNil', uuid.NIL);
const { Property, Header } = require('insomnia-collection');
const prop = new Property('${propertyId}', '${propertyName}');
const header = new Header({ key: '${headerKey}', value: '${headerValue}' });
insomnia.environment.set('propJson', JSON.stringify(prop.toJSON()));
insomnia.environment.set('headerJson', JSON.stringify(header.toJSON()));
`,
});
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
json: {
evalResult: 16,
hash: parsedUrl.hash,
host: parsedUrl.host,
hostname: parsedUrl.hostname,
origin: parsedUrl.origin,
password: parsedUrl.password,
pathname: parsedUrl.pathname,
port: parsedUrl.port,
protocol: parsedUrl.protocol,
search: parsedUrl.search,
username: parsedUrl.username,
searchParam: parsedUrl.searchParams.toString(),
...Object.fromEntries(builtinModules.map((m) => [m, true])),
...Object.fromEntries(externalModuleKeys.map((k) => [k, true])),
builtInLodash: true,
uuidNil: "00000000-0000-0000-0000-000000000000",
propJson: { id: propertyId, name: propertyName, disabled: false },
headerJson: { key: headerKey, value: headerValue, id: "", name: "" },
},
});
});
@@ -0,0 +1,171 @@
import { faker } from '@faker-js/faker';
import { expect } from "@playwright/test";
import { HttpMethod } from '../../enums/http-method';
import { ProjectType } from '../../enums/project-types';
import { HTTP_SERVER, test } from '../../misc/fixtures';
import { Collection } from '../../models/collection';
import { Project } from '../../models/project';
const url = `${HTTP_SERVER}/post`;
test('Verify pre-request script manipulates request headers, query params and body via insomnia.request', async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(new Project(faker.string.alphanumeric(10), ProjectType.Local));
const collection = await workspaceFlow.createCollection(project, new Collection(faker.string.alphanumeric(10)));
const headerValue = faker.string.alphanumeric(10);
const rawContent = faker.string.alphanumeric(10);
const upsertedValue = faker.string.alphanumeric(10);
const addedParam = faker.string.alphanumeric(10);
const updatedParam = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${url}?removeMe=1&keepMe=2`,
preRequestScript: `
const { Header } = require('insomnia-collection');
insomnia.request.headers.add(new Header({ key: 'X-Hello', value: '${headerValue}' }));
insomnia.request.headers.add(new Header({ key: 'X-Remove', value: 'gone' }));
insomnia.request.headers.upsert({ key: 'X-Upsert', value: '${upsertedValue}' });
insomnia.request.headers.remove((header) => header.key === 'X-Remove');
insomnia.request.url.addQueryParams('added=${addedParam}');
insomnia.request.url.removeQueryParams('removeMe');
insomnia.request.url.removeQueryParams('keepMe');
insomnia.request.url.addQueryParams('keepMe=${updatedParam}');
insomnia.request.body.update({ mode: 'raw', raw: '${rawContent}' });
`,
});
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
data: rawContent,
args: { added: addedParam, keepMe: updatedParam },
headers: expect.objectContaining({
'x-hello': headerValue,
'x-upsert': upsertedValue,
}),
});
expect((responseView.body as { args: Record<string, string>; headers: object }).args).not.toHaveProperty('removeMe');
expect((responseView.body as { args: Record<string, string>; headers: object }).headers).not.toHaveProperty('x-remove');
});
test('Verify pre-request script sets bearer auth via insomnia.request.auth', async ({ user }) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(new Project(faker.string.alphanumeric(10), ProjectType.Local));
const collection = await workspaceFlow.createCollection(project, new Collection(faker.string.alphanumeric(10)));
const token = faker.string.alphanumeric(10);
const prefix = faker.string.alpha(8);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
preRequestScript: `
insomnia.request.auth.update({
type: 'bearer',
bearer: [
{ key: 'token', value: '${token}' },
{ key: 'prefix', value: '${prefix}' },
],
}, 'bearer');
`,
});
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
headers: expect.objectContaining({
authorization: `${prefix} ${token}`,
}),
});
});
test('Verify pre-request script sets basic auth via insomnia.request.auth', async ({ user }) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(new Project(faker.string.alphanumeric(10), ProjectType.Local));
const collection = await workspaceFlow.createCollection(project, new Collection(faker.string.alphanumeric(10)));
const username = faker.string.alphanumeric(10);
const password = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
preRequestScript: `
insomnia.request.auth.update({
type: 'basic',
basic: [
{ key: 'username', value: '${username}' },
{ key: 'password', value: '${password}' },
],
}, 'basic');
`,
});
const responseView = await httpRequestFlow.send(request);
const expectedEncodedCredentials = Buffer.from(`${username}:${password}`, 'utf8').toString('base64');
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
headers: expect.objectContaining({
authorization: `Basic ${expectedEncodedCredentials}`,
}),
});
});
test('Verify pre-request script applies apikey, AWS v4, Hawk and OAuth 1.0 auth via insomnia.request.auth', async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(new Project(faker.string.alphanumeric(10), ProjectType.Local));
const collection = await workspaceFlow.createCollection(project, new Collection(faker.string.alphanumeric(10)));
const apiKeyName = faker.string.alpha(8);
const apiKeyValue = faker.string.alphanumeric(10);
const accessKey = faker.string.alphanumeric(10);
const secretKey = faker.string.alphanumeric(20);
const region = faker.helpers.arrayElement(['us-east-1', 'eu-west-1']);
const service = faker.string.alpha(6);
const hawkId = faker.string.alphanumeric(10);
const hawkKey = faker.string.alphanumeric(20);
const consumerKey = faker.string.alphanumeric(10);
const consumerSecret = faker.string.alphanumeric(10);
const authScripts = {
apiKeyHeader: `insomnia.request.auth.update({ type: 'apikey', apikey: [{ key: 'key', value: '${apiKeyName}' }, { key: 'value', value: '${apiKeyValue}' }, { key: 'in', value: 'header' }] }, 'apikey');`,
apiKeyQuery: `insomnia.request.auth.update({ type: 'apikey', apikey: [{ key: 'key', value: '${apiKeyName}' }, { key: 'value', value: '${apiKeyValue}' }, { key: 'in', value: 'queryParams' }] }, 'apikey');`,
awsV4: `insomnia.request.auth.update({ type: 'awsv4', awsv4: [{ key: 'accessKey', value: '${accessKey}' }, { key: 'secretKey', value: '${secretKey}' }, { key: 'region', value: '${region}' }, { key: 'service', value: '${service}' }] }, 'awsv4');`,
hawk: `insomnia.request.auth.update({ type: 'hawk', hawk: [{ key: 'authId', value: '${hawkId}' }, { key: 'authKey', value: '${hawkKey}' }, { key: 'algorithm', value: 'sha256' }] }, 'hawk');`,
oauth1: `insomnia.request.auth.update({ type: 'oauth1', oauth1: [{ key: 'consumerKey', value: '${consumerKey}' }, { key: 'consumerSecret', value: '${consumerSecret}' }, { key: 'signatureMethod', value: 'HMAC-SHA1' }] }, 'oauth1');`,
};
const responses: Record<string, Awaited<ReturnType<typeof httpRequestFlow.send>>> = {};
for (const [authName, preRequestScript] of Object.entries(authScripts)) {
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
preRequestScript,
});
responses[authName] = await httpRequestFlow.send(request);
}
const headersOf = (name: string) => (responses[name].body as { headers: Record<string, string> }).headers;
expect(headersOf('apiKeyHeader')).toMatchObject({
[apiKeyName.toLowerCase()]: apiKeyValue,
});
expect(responses.apiKeyQuery.body).toMatchObject({
args: { [apiKeyName]: apiKeyValue },
});
expect(headersOf('awsV4').authorization).toContain(`AWS4-HMAC-SHA256 Credential=${accessKey}/`);
expect(headersOf('awsV4').authorization).toContain(`/${region}/${service}/`);
expect(headersOf('hawk').authorization).toContain(`Hawk id="${hawkId}"`);
expect(headersOf('oauth1').authorization).toContain(`oauth_consumer_key="${consumerKey}"`);
expect(headersOf('oauth1').authorization).toContain('oauth_signature_method="HMAC-SHA1"');
});
@@ -0,0 +1,71 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify pre-request script's sendRequest serializes raw, urlencoded, graphql, and formdata bodies correctly", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const rawValue = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
body: {
mimeType: ContentType.JSON,
text: `{"results": {{ results }}}`,
},
preRequestScript: `
const results = {};
const modes = [
{ key: 'raw', body: { mode: 'raw', raw: '${rawValue}' } },
{ key: 'urlencoded', body: { mode: 'urlencoded', urlencoded: [{ key: 'a', value: '1' }, { key: 'b', value: '2' }] } },
{ key: 'graphql', body: { mode: 'graphql', graphql: { query: '{ __typename }', variables: {} } } },
{ key: 'formdata', body: { mode: 'formdata', formdata: [{ key: 'c', value: '3' }] } },
];
for (const m of modes) {
const resp = await insomnia.sendRequest({ url: '${url}', method: 'POST', body: m.body });
results[m.key] = resp.body;
}
insomnia.environment.set('results', JSON.stringify(results));
`,
});
const responseView = await httpRequestFlow.send(request);
const results = (
responseView.body as { json: { results: Record<string, string> } }
).json.results;
const raw = JSON.parse(results.raw);
const urlencoded = JSON.parse(results.urlencoded);
const graphql = JSON.parse(results.graphql);
const formdata = JSON.parse(results.formdata);
expect(responseView.statusCode).toBe(200);
expect(raw.data).toBe(rawValue);
expect(urlencoded.data).toBe("a=1&b=2");
expect(graphql.json).toMatchObject({
query: "{ __typename }",
variables: {},
});
expect(formdata.data).toContain("--X-INSOMNIA-BOUNDARY");
expect(formdata.data).toContain('Content-Disposition: form-data; name="c"');
expect(formdata.data).toContain("3");
expect(formdata.data.trimEnd()).toMatch(/--X-INSOMNIA-BOUNDARY--$/);
});
@@ -0,0 +1,42 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { CurlCommand } from "../../models/curl-command";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
const body = `{"title": "${faker.string.alphanumeric(8)}"}`;
const command = `curl -X QUERY "${url}" -H "Content-Type: application/json" -d '${body}'`;
test("Verify sending a QUERY request with a body", async ({ user }) => {
const { httpRequestFlow, importFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const curl: CurlCommand = { command };
await importFlow.importCurl(project, collection, curl);
const imported = await httpRequestFlow.get(url);
const responseView = await httpRequestFlow.send(imported!);
expect(imported).toMatchObject({
name: url,
url,
method: HttpMethod.Query,
body: { mimeType: ContentType.JSON, text: body },
} satisfies HttpRequest);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({ data: body });
});
@@ -0,0 +1,79 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { EnvironmentKvPairDataType } from "../../models/environment";
import { Project } from "../../models/project";
test("Verify query params from the URL, template tags, and the Parameters tab are merged and special characters are escaped correctly", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow, environmentFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const fromUrlValue = faker.string.alphanumeric(10);
const fromEditorValue = faker.string.alphanumeric(10);
const environment = await environmentFlow.createBaseEnvironment(project, {
name: faker.string.alphanumeric(10),
kvPairData: [
{
id: "",
name: "fromUrlValue",
value: fromUrlValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
{
id: "",
name: "fromEditorValue",
value: fromEditorValue,
type: EnvironmentKvPairDataType.STRING,
enabled: true,
},
],
});
await environmentFlow.link(collection, environment);
const spaceValue = `${faker.string.alphanumeric(4)} ${faker.string.alphanumeric(4)}`;
const ampersandValue = `${faker.string.alphanumeric(4)}&${faker.string.alphanumeric(4)}`;
const equalsValue = `${faker.string.alphanumeric(4)}=${faker.string.alphanumeric(4)}`;
const hashValue = `${faker.string.alphanumeric(4)}#${faker.string.alphanumeric(4)}`;
const chineseValue = `测试${faker.string.alphanumeric(4)}参数`;
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post?key=fromUrl&key={{ fromUrlValue }}`,
params: [
{ name: "key", value: "{{ fromEditorValue }}" },
{ name: "key", value: "/" },
{ name: "space", value: spaceValue },
{ name: "ampersand", value: ampersandValue },
{ name: "equals", value: equalsValue },
{ name: "hash", value: hashValue },
{ name: "chinese", value: chineseValue },
],
});
const responseView = await httpRequestFlow.send(request);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
args: {
key: ["fromUrl", fromUrlValue, fromEditorValue, "/"],
space: spaceValue,
ampersand: ampersandValue,
equals: equalsValue,
hash: hashValue,
chinese: chineseValue,
},
});
});
@@ -0,0 +1,76 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { DEFAULT_TIMEOUT, HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify insomnia.environment.replaceIn resolves and returns a string synchronously", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const variableName = faker.string.alpha(8);
const variableValue = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
preRequestScript: `
insomnia.environment.set('${variableName}', '${variableValue}');
const v = insomnia.environment.replaceIn('{{ ${variableName} }}');
console.log(typeof v, v);
`,
});
const responseView = await httpRequestFlow.send(request);
await expect
.poll(() => responseView.console?.(), { timeout: DEFAULT_TIMEOUT })
.toContain(`log: string ${variableValue}`);
const consoleText = await responseView.console?.();
expect(consoleText).not.toContain("Promise");
});
test("Verify a script that awaits insomnia.environment.replaceIn as a workaround still resolves correctly", async ({
user,
}) => {
const { httpRequestFlow, workspaceFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const variableName = faker.string.alpha(8);
const variableValue = faker.string.alphanumeric(10);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
preRequestScript: `
insomnia.environment.set('${variableName}', '${variableValue}');
const v = await insomnia.environment.replaceIn('{{ ${variableName} }}');
console.log(typeof v, v);
`,
});
const responseView = await httpRequestFlow.send(request);
await expect
.poll(() => responseView.console?.(), { timeout: DEFAULT_TIMEOUT })
.toContain(`log: string ${variableValue}`);
});
@@ -0,0 +1,38 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
test("Verify the cookie Tag Reads a Value from a Linked Cookie", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow, cookieFlow, templateTagFlow } =
user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const cookieTag = `{% cookie '${HTTP_SERVER}', 'session' %}`;
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${HTTP_SERVER}/${cookieTag}`,
});
const cookieValue = faker.string.alphanumeric(10);
await cookieFlow.link(collection, [
{ key: "session", value: cookieValue, domain: "localhost", path: "/" },
]);
await httpRequestFlow.get(request!.name);
const tag = await templateTagFlow.get(cookieTag);
expect(tag.preview).toBe(cookieValue);
});
@@ -0,0 +1,45 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
test("Verify Switching an Existing Tag's Argument Updates its Live Preview", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow, templateTagFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const hashTag = "{% hash 'md5', 'hex', 'hello' %}";
await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${HTTP_SERVER}/${hashTag}`,
});
const before = await templateTagFlow.get(hashTag);
const after = await templateTagFlow.edit(hashTag, {
functionName: "hash",
algorithm: "sha256",
digestEncoding: "hex",
input: "hello",
preview: "",
});
expect(before.functionName).toBe("hash");
expect(before.algorithm).toBe("md5");
expect(before.preview).toBe("5d41402abc4b2a76b9719d911017c592");
expect(after.algorithm).toBe("sha256");
expect(after.preview).toBe(
"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
);
});
@@ -0,0 +1,110 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import {
AWSCredentialType,
HashiCorpCredentialType,
HashiCorpVaultAuthMethod,
} from "insomnia-data";
import { ContentType } from "../../enums/content-type";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import type { HttpRequest } from "../../models/http-request";
import { Project } from "../../models/project";
test("Verify AWS/GCP/HashiCorp Cloud Credentials Resolve via the Vault Template Tag", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow, templateTagFlow, preferencesFlow } =
user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const awsCredentialName = faker.string.alphanumeric(10);
const gcpCredentialName = faker.string.alphanumeric(10);
const hashicorpCredentialName = faker.string.alphanumeric(10);
await preferencesFlow.set({
// Live Preview masks vault values as •••••• by default; the spec asserts the resolved value.
hideSecretValuesInPreviewAndConsole: false,
cloudCredentials: [
{
provider: "aws",
name: awsCredentialName,
credentials: {
type: AWSCredentialType.file,
section: faker.string.alphanumeric(8),
region: faker.string.alphanumeric(8),
},
},
{
provider: "gcp",
name: gcpCredentialName,
credentials: { serviceAccountKeyFilePath: faker.system.filePath() },
},
{
provider: "hashicorp",
name: hashicorpCredentialName,
credentials: {
type: HashiCorpCredentialType.onPrem,
authMethod: HashiCorpVaultAuthMethod.appRole,
serverAddress: "http://127.0.0.1",
role_id: faker.string.alphanumeric(8),
secret_id: faker.string.alphanumeric(8),
},
},
],
});
const awsTag = "{% vault 'aws', '', '{}' %}";
const gcpTag = "{% vault 'gcp', '', '{}' %}";
const hashicorpTag = "{% vault 'hashicorp', '', '{}' %}";
const request = {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post`,
body: {
mimeType: ContentType.Plain,
text: `${awsTag}\n${gcpTag}\n${hashicorpTag}`,
},
} satisfies HttpRequest;
await httpRequestFlow.create(collection, request);
const awsResult = await templateTagFlow.edit(awsTag, {
functionName: "vault",
credentialName: awsCredentialName,
preview: "",
});
const gcpResult = await templateTagFlow.edit(gcpTag, {
functionName: "vault",
credentialName: gcpCredentialName,
preview: "",
});
const hashicorpResult = await templateTagFlow.edit(hashicorpTag, {
functionName: "vault",
credentialName: hashicorpCredentialName,
preview: "",
});
const responseView = await httpRequestFlow.send(request);
const secondResponse = await httpRequestFlow.send(request);
expect(awsResult.preview).toBe("aws-secret-value");
expect(gcpResult.preview).toBe("gcp-secret-value");
expect(hashicorpResult.preview).toBe("hashicorp-secret-value");
expect((responseView.body as { data: string }).data).toContain("aws-secret-value");
expect((responseView.body as { data: string }).data).toContain("gcp-secret-value");
expect((responseView.body as { data: string }).data).toContain(
"hashicorp-secret-value",
);
expect((secondResponse.body as { data: string }).data).toContain(
"aws-secret-value",
);
});
@@ -0,0 +1,39 @@
import path from "node:path";
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../../enums/http-method";
import { ProjectType } from "../../../enums/project-types";
import { test } from "../../../misc/fixtures";
import { Collection } from "../../../models/collection";
import { Project } from "../../../models/project";
const filePath = path.join(__dirname, "fixture.txt");
test("Verify the file Tag Reads Contents from an Allowed Folder", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow, preferencesFlow, templateTagFlow } =
user.flowManager;
await preferencesFlow.set({ dataFolders: [__dirname] });
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const fileTag = `{% file '${filePath}' %}`;
await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: fileTag,
});
const result = await templateTagFlow.get(fileTag);
expect(result.preview).toBe("hello-from-file-tag");
});
@@ -0,0 +1 @@
hello-from-file-tag
@@ -0,0 +1,54 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
test("Verify Inserting a Template Tag and Reading its Live Preview", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow, templateTagFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const uuidTag = "{% uuid 'v4' %}";
const base64Tag = "{% base64 'encode', 'normal', 'hello' %}";
const nowTag = "{% now 'unix' %}";
const fakerTag = "{% faker 'randomFirstName' %}";
const jsonpathTag = "{% jsonpath '{\"a\":{\"b\":42}}', '$.a.b' %}";
const osTag = "{% os 'platform' %}";
const requestTag = "{% request 'name' %}";
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Get,
url: `${uuidTag}${base64Tag}${nowTag}${fakerTag}${jsonpathTag}${osTag}${requestTag}`,
});
const uuidResult = await templateTagFlow.get(uuidTag);
const base64Result = await templateTagFlow.get(base64Tag);
const nowResult = await templateTagFlow.get(nowTag);
const fakerResult = await templateTagFlow.get(fakerTag);
const jsonpathResult = await templateTagFlow.get(jsonpathTag);
const osResult = await templateTagFlow.get(osTag);
const requestResult = await templateTagFlow.get(requestTag);
expect(uuidResult.preview).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
);
expect(base64Result.preview).toBe("aGVsbG8=");
expect(nowResult.preview).toMatch(/^\d+$/);
expect(fakerResult.preview).toMatch(/^[A-Za-z'-]+$/);
expect(jsonpathResult.preview).toBe("42");
expect(osResult.preview).toBe(process.platform);
expect(requestResult.preview).toBe(request!.name);
});
@@ -0,0 +1,42 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
test("Verify a Header With a Templated Name Resolves and Sends Correctly", async ({
user,
}) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url: `${HTTP_SERVER}/post`,
headers: [
{
name: "X-{% hash 'md5', 'hex', 'header-name' %}",
value: "plain-value",
},
],
});
const responseView = await httpRequestFlow.send(request!);
expect(responseView.statusCode).toBe(200);
expect(responseView.body).toMatchObject({
headers: expect.objectContaining({
"x-7cd8e9f98e9104085ea06e39b87faf36": "plain-value",
}),
});
});
@@ -0,0 +1,41 @@
import { faker } from "@faker-js/faker";
import { expect } from "@playwright/test";
import { HttpMethod } from "../../enums/http-method";
import { ProjectType } from "../../enums/project-types";
import { HTTP_SERVER, test } from "../../misc/fixtures";
import { Collection } from "../../models/collection";
import { Project } from "../../models/project";
const url = `${HTTP_SERVER}/post`;
test("Verify a Header With a Template Tag in Its Value", async ({ user }) => {
const { workspaceFlow, httpRequestFlow } = user.flowManager;
const project = await workspaceFlow.createProject(
new Project(faker.string.alphanumeric(10), ProjectType.Local),
);
const collection = await workspaceFlow.createCollection(
project,
new Collection(faker.string.alphanumeric(10)),
);
const request = await httpRequestFlow.create(collection, {
name: faker.string.alphanumeric(10),
method: HttpMethod.Post,
url,
headers: [
{
name: "X-Header-Name",
value: "{% base64 'encode', 'normal', 'header-value' %}",
},
],
});
const responseView = await httpRequestFlow.send(request!);
expect(responseView.body).toMatchObject({
headers: expect.objectContaining({
"x-header-name": "aGVhZGVyLXZhbHVl",
}),
});
});