Skip to content
108 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import type { InstallRequest } from "@g1t/contracts";
5import { connectorsFor } from "@g1t/contracts/connectors";
6
7import { FIRST_PARTY_EXTENSIONS, extensionById } from "@g1t/contracts/marketplace";
8
9import { STARTER_KITS, addPath, comingIntegrations, extensionListings, integrationListings, integrationMatches, isConnectedSystem, marketplaceForm } from "./marketplace.ts";
10import { modeOf } from "./workspace-nav.ts";
11
12const request = (listing: string, by: string, status: InstallRequest["status"] = "open"): InstallRequest => ({
13 id: `ins_${listing}_${by}`,
14 listing,
15 kind: listing.startsWith("extension:") ? "extension" : "integration",
16 name: listing,
17 note: null,
18 requested_by: by,
19 requested_at: "2026-10-10T12:00:00Z",
20 status,
21 resolved_by: null,
22 resolved_at: null,
23});
24
25test("only integrations a workspace can connect today are listed, connected first", () => {
26 const views = connectorsFor("workspace");
27 const listings = integrationListings(views, { sentry: { detail: "acme", problem: null, manage: "/acme/-/integrations/alerts" } }, [], "ana", "acme");
28 assert.ok(listings.every((l) => l.view.status === "available"));
29 assert.equal(listings[0]!.view.id, "sentry");
30 assert.equal(listings[0]!.href, "/acme/-/integrations/alerts", "managed where it is managed");
31 const linear = listings.find((l) => l.view.id === "linear")!;
32 assert.equal(linear.href, "/acme/-/integrations/trackers?add=linear#add", "connected on its setup page");
33 assert.ok(!listings.some((l) => l.view.id === "slack"));
34 assert.ok(comingIntegrations(views).some((v) => v.id === "slack"));
35 assert.ok(integrationMatches(linear, "tracker"));
36 assert.ok(!integrationMatches(linear, "deploys"));
37});
38
39test("an owner adds what a request asks for where it is added", () => {
40 const views = connectorsFor("workspace");
41 assert.equal(addPath({ listing: "agent:qa" }, "acme", views), null, "agents aren't added from the Marketplace");
42 assert.equal(addPath({ listing: "integration:jira" }, "acme", views), "/acme/-/integrations/trackers?add=jira#add");
43 assert.equal(addPath({ listing: "nonsense" }, "acme", views), null);
44});
45
46test("the Marketplace's forms are read strictly", () => {
47 const form = (fields: Record<string, string>) => {
48 const data = new FormData();
49 for (const [k, v] of Object.entries(fields)) data.set(k, v);
50 return data;
51 };
52 assert.deepEqual(marketplaceForm(form({ intent: "request", listing: "integration:jira", note: " flaky " })), { intent: "request", listing: "integration:jira", note: "flaky" });
53 assert.deepEqual(marketplaceForm(form({ intent: "request", listing: "extension:support" })), { intent: "request", listing: "extension:support", note: null });
54 assert.equal(marketplaceForm(form({ intent: "request", listing: "agent:qa" })), null, "agents start from templates in Agents");
55 assert.equal(marketplaceForm(form({ intent: "request", listing: "app:qa" })), null);
56 assert.deepEqual(marketplaceForm(form({ intent: "resolve", id: "ins_1", status: "declined" })), { intent: "resolve", id: "ins_1", status: "declined" });
57 assert.equal(marketplaceForm(form({ intent: "resolve", id: "ins_1", status: "open" })), null);
58 assert.equal(marketplaceForm(form({ intent: "install" })), null);
59});
60
61test("extensions list published ones first, each with its install", () => {
62 const published = { ...FIRST_PARTY_EXTENSIONS[1]!, id: "standup", status: "available" as const, source: { repo: "flagon-io/standup", tag: "v1.0.0" }, version: "1.0.0" };
63 const install = { id: "ins_1", listing: "extension:standup", version: "1.0.0", plan: "free", installed_by: "chase", installed_at: "2026-10-10T00:00:00Z", enabled: true, disabled_by: null, disabled_at: null, budget_monthly_micros: null };
64 const listings = extensionListings([...FIRST_PARTY_EXTENSIONS, published], [install], [request("extension:support", "ana")], "ana");
65 assert.equal(listings[0]!.manifest.id, "standup");
66 assert.equal(listings[0]!.install?.version, "1.0.0");
67 assert.equal(listings.find((l) => l.manifest.id === "support")!.requested, true);
68 assert.equal(listings.find((l) => l.manifest.id === "mail")!.install, null);
69});
70
71test("coming integrations include the ones each person connects, once", () => {
72 const workspace = connectorsFor("workspace");
73 const personal = connectorsFor("personal");
74 const coming = comingIntegrations(workspace, personal).map((v) => v.id);
75 assert.ok(coming.includes("slack"));
76 assert.ok(coming.includes("gmail"), "Gmail is each person's");
77 assert.ok(coming.includes("google-calendar"));
78 assert.equal(new Set(coming).size, coming.length);
79});
80
81test("installing, switching and removing an extension are read from forms", () => {
82 const form = (fields: Record<string, string>) => {
83 const data = new FormData();
84 for (const [k, v] of Object.entries(fields)) data.set(k, v);
85 return data;
86 };
87 assert.deepEqual(marketplaceForm(form({ intent: "install", extension: "support" })), { intent: "install", extension: "support" });
88 assert.deepEqual(marketplaceForm(form({ intent: "switch", listing: "extension:support", enabled: "off" })), { intent: "switch", listing: "extension:support", enabled: false });
89 assert.equal(marketplaceForm(form({ intent: "switch", listing: "integration:sentry", enabled: "off" })), null);
90 assert.deepEqual(marketplaceForm(form({ intent: "uninstall", listing: "extension:support" })), { intent: "uninstall", listing: "extension:support" });
91 assert.equal(addPath({ listing: "extension:mail" }, "acme", []), "/acme/-/marketplace/extensions/mail");
92});
93
94test("starter kits name extensions that are listed, and connected systems are told apart", () => {
95 for (const kit of STARTER_KITS) {
96 assert.ok(kit.extensions.length > 0, kit.id);
97 for (const id of kit.extensions) assert.ok(extensionById(id), `${kit.id}: ${id}`);
98 }
99 const systems = FIRST_PARTY_EXTENSIONS.filter(isConnectedSystem).map((m) => m.id);
100 assert.deepEqual(systems, ["helpdesk-bridge", "crm-bridge", "erp-bridge"]);
101 assert.ok(FIRST_PARTY_EXTENSIONS.filter(isConnectedSystem).every((m) => m.bridges), "a connected system says what it bridges");
102});
103
104test("the Marketplace is part of Apps, not a mode of its own", () => {
105 assert.equal(modeOf("/acme/-/marketplace", "acme"), "apps");
106 assert.equal(modeOf("/acme/-/marketplace/extensions/mail", "acme"), "apps");
107 assert.equal(modeOf("/acme/-/agents/templates", "acme"), "agents", "agent templates are Agents'");
108});