

























@@ -6,6 +6,7 @@ import plugin from "./index.js";
66import {
77extractGoogleMeetUriFromCalendarEvent,
88findGoogleMeetCalendarEvent,
9+listGoogleMeetCalendarEvents,
910} from "./src/calendar.js";
1011import { resolveGoogleMeetConfig, resolveGoogleMeetConfigWithEnv } from "./src/config.js";
1112import {
@@ -186,6 +187,18 @@ function stubMeetArtifactsApi() {
186187],
187188});
188189}
190+if (url.pathname === "/drive/v3/files/doc-1/export") {
191+return new Response("Transcript document body.", {
192+status: 200,
193+headers: { "Content-Type": "text/plain" },
194+});
195+}
196+if (url.pathname === "/drive/v3/files/doc-2/export") {
197+return new Response("Smart note document body.", {
198+status: 200,
199+headers: { "Content-Type": "text/plain" },
200+});
201+}
189202return new Response(`unexpected ${url.pathname}`, { status: 404 });
190203});
191204vi.stubGlobal("fetch", fetchMock);
@@ -347,6 +360,7 @@ describe("google-meet plugin", () => {
347360"resolve_space",
348361"preflight",
349362"latest",
363+"calendar_events",
350364"artifacts",
351365"attendance",
352366"recover_current_tab",
@@ -400,6 +414,21 @@ describe("google-meet plugin", () => {
400414meetingUri: "https://meet.google.com/abc-defg-hij",
401415event: { summary: "Project sync" },
402416});
417+await expect(
418+listGoogleMeetCalendarEvents({
419+accessToken: "token",
420+now: new Date("2026-04-25T09:50:00Z"),
421+timeMin: "2026-04-25T00:00:00Z",
422+timeMax: "2026-04-26T00:00:00Z",
423+}),
424+).resolves.toMatchObject({
425+events: [
426+{
427+meetingUri: "https://meet.google.com/abc-defg-hij",
428+selected: true,
429+},
430+],
431+});
403432const calendarCall = fetchMock.mock.calls.find(([input]) => {
404433const url = requestUrl(input);
405434return url.pathname === "/calendar/v3/calendars/primary/events";
@@ -418,6 +447,28 @@ describe("google-meet plugin", () => {
418447);
419448});
420449450+it("adds a reauth hint for missing Calendar scopes", async () => {
451+vi.stubGlobal(
452+"fetch",
453+vi.fn(async () => new Response("insufficientPermissions", { status: 403 })),
454+);
455+456+await expect(
457+findGoogleMeetCalendarEvent({
458+accessToken: "token",
459+timeMin: "2026-04-25T00:00:00Z",
460+timeMax: "2026-04-26T00:00:00Z",
461+}),
462+).rejects.toThrow("calendar.events.readonly");
463+await expect(
464+findGoogleMeetCalendarEvent({
465+accessToken: "token",
466+timeMin: "2026-04-25T00:00:00Z",
467+timeMax: "2026-04-26T00:00:00Z",
468+}),
469+).rejects.toThrow("googlemeet auth login");
470+});
471+421472it("fetches Meet spaces without percent-encoding the spaces path separator", async () => {
422473const fetchMock = vi.fn(async () => {
423474return new Response(
@@ -567,6 +618,33 @@ describe("google-meet plugin", () => {
567618expect(listUrl.searchParams.get("filter")).toBe('space.name = "spaces/abc-defg-hij"');
568619});
569620621+it("exports linked Google Docs bodies when requested", async () => {
622+const fetchMock = stubMeetArtifactsApi();
623+624+await expect(
625+fetchGoogleMeetArtifacts({
626+accessToken: "token",
627+conferenceRecord: "rec-1",
628+includeDocumentBodies: true,
629+}),
630+).resolves.toMatchObject({
631+artifacts: [
632+{
633+transcripts: [{ documentText: "Transcript document body." }],
634+smartNotes: [{ documentText: "Smart note document body." }],
635+},
636+],
637+});
638+const driveCalls = fetchMock.mock.calls
639+.map(([input]) => requestUrl(input))
640+.filter((url) => url.pathname.startsWith("/drive/v3/files/"));
641+expect(driveCalls.map((url) => url.pathname)).toEqual([
642+"/drive/v3/files/doc-1/export",
643+"/drive/v3/files/doc-2/export",
644+]);
645+expect(driveCalls.every((url) => url.searchParams.get("mimeType") === "text/plain")).toBe(true);
646+});
647+570648it("fetches only the latest Meet conference record for a meeting", async () => {
571649const fetchMock = stubMeetArtifactsApi();
572650@@ -854,6 +932,31 @@ describe("google-meet plugin", () => {
854932});
855933});
856934935+it("reports calendar event previews through the tool", async () => {
936+stubMeetArtifactsApi();
937+const { tools } = setup();
938+const tool = tools[0] as {
939+execute: (
940+id: string,
941+params: unknown,
942+) => Promise<{ details: { events?: Array<{ selected?: boolean; meetingUri?: string }> } }>;
943+};
944+945+const result = await tool.execute("id", {
946+action: "calendar_events",
947+accessToken: "token",
948+expiresAt: Date.now() + 120_000,
949+today: true,
950+});
951+952+expect(result.details.events).toEqual([
953+expect.objectContaining({
954+selected: true,
955+meetingUri: "https://meet.google.com/abc-defg-hij",
956+}),
957+]);
958+});
959+857960it("fails setup status when the configured Chrome node is not connected", async () => {
858961const { tools } = setup(
859962{
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。