aboutsummaryrefslogtreecommitdiff
path: root/tests/session-io.test.ts
diff options
context:
space:
mode:
authornetop://ウィビ <paul@webb.page>2026-04-24 16:37:33 -0700
committernetop://ウィビ <paul@webb.page>2026-04-24 16:37:33 -0700
commit510fd8cbe53abb39cba2c7cbaaefcf2783dc0066 (patch)
tree8f753a33c475b285f2a297785d34cda3b0a8faed /tests/session-io.test.ts
parent261f3bdb77799009344aab4a60686b7186ebd3b0 (diff)
downloadgraphiql-510fd8cbe53abb39cba2c7cbaaefcf2783dc0066.tar.gz
graphiql-510fd8cbe53abb39cba2c7cbaaefcf2783dc0066.zip
Implement v0.6-1.0: shortcuts, format, export/import, splitter, timing, APQ
- v0.6: matchShortcut + format(); Cmd+Shift+Enter/W/F + Cmd+Alt+arrows - v0.7: SessionStore.exportAll/importTabs with version-1 validator - v0.8: Splitter component + four resize handles persisted under layout.* - v0.10: createApqFetcher (HTTP-only) wrapping shared http-body helpers - Drop .svelte re-exports from index.ts for multi-entry JSR/npm publishing
Diffstat (limited to 'tests/session-io.test.ts')
-rw-r--r--tests/session-io.test.ts201
1 files changed, 201 insertions, 0 deletions
diff --git a/tests/session-io.test.ts b/tests/session-io.test.ts
new file mode 100644
index 0000000..6de919b
--- /dev/null
+++ b/tests/session-io.test.ts
@@ -0,0 +1,201 @@
+
+
+
+
+/*** IMPORT ------------------------------------------- ***/
+
+import { expect, test } from "vitest";
+
+/*** UTILITY ------------------------------------------ ***/
+
+import {
+ tabToExport,
+ validateSessionExport,
+ type SessionExport
+} from "../source/library/state/session-io.ts";
+
+type TabInput = Parameters<typeof tabToExport>[0];
+
+function validExport(): SessionExport {
+ return {
+ exportedAt: "2026-04-24T00:00:00.000Z",
+ tabs: [
+ {
+ headers: "{}",
+ operationName: "MyOp",
+ query: "query MyOp { hello }",
+ title: "MyOp",
+ variables: "{}"
+ }
+ ],
+ version: 1
+ };
+}
+
+function isError(result: unknown): result is { error: string } {
+ return typeof result === "object" &&
+ result !== null &&
+ "error" in result;
+}
+
+/*** TESTS -------------------------------------------- ***/
+
+test("validateSessionExport round-trips a valid payload unchanged", () => {
+ const data = validExport();
+ const result = validateSessionExport(data);
+
+ expect(isError(result)).toBe(false);
+ expect(result).toEqual(data);
+});
+
+test("validateSessionExport rejects non-object input", () => {
+ expect(isError(validateSessionExport(null))).toBe(true);
+ expect(isError(validateSessionExport("nope"))).toBe(true);
+ expect(isError(validateSessionExport(42))).toBe(true);
+ expect(isError(validateSessionExport([]))).toBe(true);
+});
+
+test("validateSessionExport rejects wrong version", () => {
+ const zero = validateSessionExport({ ...validExport(), version: 0 });
+ const two = validateSessionExport({ ...validExport(), version: 2 });
+ const missing = validateSessionExport({
+ exportedAt: "2026-04-24T00:00:00.000Z",
+ tabs: []
+ });
+
+ expect(isError(zero)).toBe(true);
+ expect(isError(two)).toBe(true);
+ expect(isError(missing)).toBe(true);
+});
+
+test("validateSessionExport rejects missing or non-string exportedAt", () => {
+ const missing = validateSessionExport({ tabs: [], version: 1 });
+ const wrongType = validateSessionExport({ exportedAt: 0, tabs: [], version: 1 });
+
+ expect(isError(missing)).toBe(true);
+ expect(isError(wrongType)).toBe(true);
+});
+
+test("validateSessionExport rejects non-array tabs", () => {
+ const result = validateSessionExport({
+ exportedAt: "2026-04-24T00:00:00.000Z",
+ tabs: "not-an-array",
+ version: 1
+ });
+
+ expect(isError(result)).toBe(true);
+});
+
+test("validateSessionExport rejects tab with non-string query", () => {
+ const result = validateSessionExport({
+ exportedAt: "2026-04-24T00:00:00.000Z",
+ tabs: [
+ {
+ headers: "{}",
+ operationName: null,
+ query: 42,
+ title: "t",
+ variables: "{}"
+ }
+ ],
+ version: 1
+ });
+
+ expect(isError(result)).toBe(true);
+});
+
+test("validateSessionExport rejects tab with wrong-typed operationName", () => {
+ const result = validateSessionExport({
+ exportedAt: "2026-04-24T00:00:00.000Z",
+ tabs: [
+ {
+ headers: "{}",
+ operationName: 42,
+ query: "",
+ title: "t",
+ variables: "{}"
+ }
+ ],
+ version: 1
+ });
+
+ expect(isError(result)).toBe(true);
+});
+
+test("validateSessionExport accepts null operationName", () => {
+ const result = validateSessionExport({
+ exportedAt: "2026-04-24T00:00:00.000Z",
+ tabs: [
+ {
+ headers: "{}",
+ operationName: null,
+ query: "",
+ title: "t",
+ variables: "{}"
+ }
+ ],
+ version: 1
+ });
+
+ expect(isError(result)).toBe(false);
+});
+
+test("validateSessionExport rejects string field > 1 MB", () => {
+ const big = "x".repeat(1024 * 1024 + 1);
+ const result = validateSessionExport({
+ exportedAt: "2026-04-24T00:00:00.000Z",
+ tabs: [
+ {
+ headers: "{}",
+ operationName: null,
+ query: big,
+ title: "t",
+ variables: "{}"
+ }
+ ],
+ version: 1
+ });
+
+ expect(isError(result)).toBe(true);
+});
+
+test("validateSessionExport rejects > 50 tabs", () => {
+ const tabs = Array.from({ length: 51 }, () => ({
+ headers: "{}",
+ operationName: null,
+ query: "",
+ title: "t",
+ variables: "{}"
+ }));
+ const result = validateSessionExport({
+ exportedAt: "2026-04-24T00:00:00.000Z",
+ tabs,
+ version: 1
+ });
+
+ expect(isError(result)).toBe(true);
+});
+
+test("tabToExport strips id, result, operations, titleDirty", () => {
+ const tab: TabInput = {
+ headers: "{\"x\":1}",
+ id: "abc-123",
+ operationName: "MyOp",
+ operations: [{ name: "MyOp", type: "query" }],
+ query: "query MyOp { hello }",
+ result: "{\"data\":{}}",
+ streamIntervals: [],
+ timing: null,
+ title: "MyOp",
+ titleDirty: true,
+ variables: "{}"
+ };
+
+ expect(tabToExport(tab)).toEqual({
+ headers: "{\"x\":1}",
+ operationName: "MyOp",
+ query: "query MyOp { hello }",
+ title: "MyOp",
+ variables: "{}"
+ });
+});