| 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; |
| 3 | |
| 4 | import { connectorsFor } from "@g1t/contracts/connectors"; |
| 5 | |
| 6 | import { arrange, askHref, categoriesWith, categoryCounts, categoryFilter, groupByCategory, matchesQuery, monogram, tileColor } from "./connectors.ts"; |
| 7 | |
| 8 | const workspace = connectorsFor("workspace"); |
| 9 | const personal = connectorsFor("personal"); |
| 10 | const none = new Set<string>(); |
| 11 | |
| 12 | test("the two contexts list different connectors", () => { |
| 13 | const ids = (views: typeof workspace) => new Set(views.map((view) => view.id)); |
| 14 | assert.ok(ids(personal).has("google-calendar")); |
| 15 | assert.ok(!ids(workspace).has("google-calendar"), "a calendar is your own"); |
| 16 | assert.ok(ids(workspace).has("sentry")); |
| 17 | assert.ok(!ids(personal).has("sentry"), "alerts are the workspace's"); |
| 18 | assert.ok(ids(workspace).has("github") && ids(personal).has("github"), "GitHub is both"); |
| 19 | }); |
| 20 | |
| 21 | test("a category shows only its own connectors, sorted into connected, available and soon", () => { |
| 22 | const found = arrange(workspace, { category: "monitoring", query: "", connected: new Set(["sentry"]) }); |
| 23 | assert.deepEqual( |
| 24 | found.connected.map((view) => view.id), |
| 25 | ["sentry"], |
| 26 | ); |
| 27 | assert.ok(found.available.some((view) => view.id === "datadog")); |
| 28 | assert.ok(!found.available.some((view) => view.id === "sentry"), "connected is not also available"); |
| 29 | assert.ok(found.soon.some((view) => view.id === "pagerduty")); |
| 30 | for (const view of [...found.connected, ...found.available, ...found.soon]) assert.equal(view.category, "monitoring"); |
| 31 | }); |
| 32 | |
| 33 | test("all shows everything once", () => { |
| 34 | const found = arrange(workspace, { category: "all", query: "", connected: none }); |
| 35 | assert.equal(found.available.length + found.soon.length, workspace.length); |
| 36 | }); |
| 37 | |
| 38 | test("search finds by name, description, tag and keyword, across every category", () => { |
| 39 | const found = arrange(workspace, { category: "design", query: "resolve", connected: none }); |
| 40 | assert.deepEqual( |
| 41 | found.available.map((view) => view.id), |
| 42 | ["sentry"], |
| 43 | "a search is not held to the category", |
| 44 | ); |
| 45 | assert.deepEqual( |
| 46 | found.soon.map((view) => view.id), |
| 47 | ["pagerduty"], |
| 48 | "what is coming sorts after what works", |
| 49 | ); |
| 50 | assert.ok(matchesQuery(personal.find((view) => view.id === "google-calendar")!, "in a meeting")); |
| 51 | assert.ok(matchesQuery(workspace.find((view) => view.id === "incident-io")!, "incidentio")); |
| 52 | assert.ok(matchesQuery(workspace.find((view) => view.id === "pagerduty")!, "opens WORK ITEMS")); |
| 53 | assert.ok(!matchesQuery(workspace.find((view) => view.id === "miro")!, "kubernetes")); |
| 54 | }); |
| 55 | |
| 56 | test("the navigation counts each category and leaves out empty ones", () => { |
| 57 | const counts = categoryCounts(workspace); |
| 58 | assert.equal(counts.all, workspace.length); |
| 59 | // AI providers are the workspace's AI settings, not connectors. |
| 60 | assert.equal(counts.ai, 0); |
| 61 | const mine = categoriesWith(personal).map((category) => category.id); |
| 62 | assert.ok(mine.includes("calendar")); |
| 63 | const groups = groupByCategory(personal); |
| 64 | assert.equal( |
| 65 | groups.reduce((sum, group) => sum + group.views.length, 0), |
| 66 | personal.length, |
| 67 | ); |
| 68 | }); |
| 69 | |
| 70 | test("an unknown category is all of them", () => { |
| 71 | assert.equal(categoryFilter("ai"), "ai"); |
| 72 | assert.equal(categoryFilter("nope"), "all"); |
| 73 | assert.equal(categoryFilter(null), "all"); |
| 74 | }); |
| 75 | |
| 76 | test("a tile has the connector's letters and a steady colour", () => { |
| 77 | assert.equal(monogram("PagerDuty"), "PD"); |
| 78 | assert.equal(monogram("Google Calendar"), "GC"); |
| 79 | assert.equal(monogram("Sentry"), "S"); |
| 80 | assert.equal(monogram("incident.io"), "II"); |
| 81 | assert.equal(monogram("1Password"), "1P"); |
| 82 | assert.equal(monogram("GitHub (MCP)"), "GM", "punctuation is not a letter"); |
| 83 | assert.equal(monogram("Linear (MCP)"), "LM"); |
| 84 | assert.equal(monogram("Atlassian (Jira and Confluence)"), "AJ"); |
| 85 | assert.equal(tileColor("figma"), tileColor("figma")); |
| 86 | }); |
| 87 | |
| 88 | test("asking for a connector names it and who it is for", () => { |
| 89 | const href = askHref({ connector: { id: "slack", name: "Slack" }, scope: "workspace", workspace: "acme", address: "hey@example.com" }); |
| 90 | assert.ok(href.startsWith("mailto:hey@example.com?subject=Integration%20request%3A%20Slack")); |
| 91 | assert.ok(decodeURIComponent(href).includes("For the workspace: acme")); |
| 92 | const mine = askHref({ connector: { id: "google-calendar", name: "Google Calendar" }, scope: "personal", workspace: null, address: "hey@example.com" }); |
| 93 | assert.ok(decodeURIComponent(mine).includes("For my own account.")); |
| 94 | }); |