diff --git a/packages/cli/src/server/desktopRoutes.test.ts b/packages/cli/src/server/desktopRoutes.test.ts index c583de0aac..eaa8f0d974 100644 --- a/packages/cli/src/server/desktopRoutes.test.ts +++ b/packages/cli/src/server/desktopRoutes.test.ts @@ -45,10 +45,10 @@ describe("open-in-desktop routes", () => { }); }); - it("shows the button where the app is installed even without a download (Windows)", async () => { + it("shows the button where the app is installed even without a download (FreeBSD)", async () => { const get = async (installed: boolean) => ( - await server(true, { platform: "win32", installed: () => installed }).app.request( + await server(true, { platform: "freebsd", installed: () => installed }).app.request( "/api/open-in-desktop", ) ).json(); @@ -56,12 +56,30 @@ describe("open-in-desktop routes", () => { available: true, handoff: true, downloadUrl: null, - os: "win32", + os: "freebsd", installed: true, }); expect(await get(false)).toMatchObject({ available: false }); }); + it("offers the Windows download, and the hand-off once the app is installed", async () => { + const get = async (installed: boolean) => + ( + await server(true, { platform: "win32", installed: () => installed }).app.request( + "/api/open-in-desktop", + ) + ).json(); + const downloadUrl = "https://hyperframes.dev/studio/download?os=windows"; + expect(await get(false)).toEqual({ + available: true, + handoff: false, + downloadUrl, + os: "win32", + installed: false, + }); + expect(await get(true)).toMatchObject({ available: true, handoff: true, downloadUrl }); + }); + it("offers the hand-off only where the app is installed, so a press without it goes to the download", async () => { const get = async (installed: boolean) => ( diff --git a/packages/cli/src/utils/desktopApp.test.ts b/packages/cli/src/utils/desktopApp.test.ts index 038a6de2be..32298ca899 100644 --- a/packages/cli/src/utils/desktopApp.test.ts +++ b/packages/cli/src/utils/desktopApp.test.ts @@ -143,7 +143,7 @@ describe("openInDesktop on Windows", () => { expect(missing).toEqual({ opened: false, reason: "not-installed", - downloadUrl: "https://hyperframes.dev/studio", + downloadUrl: `${MAC_DOWNLOAD}?os=windows`, }); const failed = openInDesktop(FILM, { ...WIN, exists: () => true, launch: () => false }); expect(failed).toMatchObject({ opened: false, reason: "open-failed" }); @@ -327,12 +327,20 @@ describe("desktopHint", () => { expect(desktopHint(process.cwd(), { ...mac, ready: true, installed: false })).toBe(MAC_HINT); }); - it("offers the Linux build on Linux, and nothing on Windows without the app", () => { + it("offers the Linux and Windows builds there, and nothing where there is no build", () => { expect(desktopHint(process.cwd(), { env: {}, platform: "linux", installed: false })).toBe( `Keep editing by chatting with Framey in the HyperFrames desktop app → ${MAC_DOWNLOAD}?os=linux`, ); - expect(desktopHint(process.cwd(), { env: {}, platform: "win32", installed: false })).toBeNull(); - expect(desktopHint(process.cwd(), { env: {}, platform: "win32", ready: true })).toBeNull(); + const windowsHint = `Keep editing by chatting with Framey in the HyperFrames desktop app → ${MAC_DOWNLOAD}?os=windows`; + expect(desktopHint(process.cwd(), { env: {}, platform: "win32", installed: false })).toBe( + windowsHint, + ); + expect(desktopHint(process.cwd(), { env: {}, platform: "win32", ready: true })).toBe( + windowsHint, + ); + expect( + desktopHint(process.cwd(), { env: {}, platform: "freebsd", installed: false }), + ).toBeNull(); }); it("points an installed Windows app to `hyperframes open`", () => { diff --git a/packages/cli/src/utils/desktopApp.ts b/packages/cli/src/utils/desktopApp.ts index 64cd7dcdfa..652577fd77 100644 --- a/packages/cli/src/utils/desktopApp.ts +++ b/packages/cli/src/utils/desktopApp.ts @@ -15,9 +15,10 @@ const STUDIO_PAGE = "https://hyperframes.dev/studio"; const DOWNLOADS: Partial> = { darwin: `${STUDIO_PAGE}/download`, linux: `${STUDIO_PAGE}/download?os=linux`, + win32: `${STUDIO_PAGE}/download?os=windows`, }; -/** This machine's build of the app; null where there is none yet (Windows). */ +/** This machine's build of the app; null where there is none. */ export const desktopDownloadUrl = (platform = process.platform): string | null => DOWNLOADS[platform] ?? null; diff --git a/packages/studio/src/components/DesktopGuideCard.tsx b/packages/studio/src/components/DesktopGuideCard.tsx index cc5c76dfde..9971905a30 100644 --- a/packages/studio/src/components/DesktopGuideCard.tsx +++ b/packages/studio/src/components/DesktopGuideCard.tsx @@ -15,7 +15,7 @@ export type DesktopRoute = { /** The OS for the download, and what "this …" calls the machine. */ const platformName = (os: string): string => - os === "darwin" ? "Mac" : os === "linux" ? "Linux" : "your computer"; + os === "darwin" ? "Mac" : os === "linux" ? "Linux" : os === "win32" ? "Windows" : "your computer"; const deviceName = (os: string): string => (os === "darwin" ? "Mac" : "computer"); const NOTE = "mt-0.5 text-step-12 text-text-2 text-pretty"; diff --git a/packages/studio/src/components/OpenInDesktopButton.dom.test.tsx b/packages/studio/src/components/OpenInDesktopButton.dom.test.tsx index 7dfc264655..86f07f131a 100644 --- a/packages/studio/src/components/OpenInDesktopButton.dom.test.tsx +++ b/packages/studio/src/components/OpenInDesktopButton.dom.test.tsx @@ -103,19 +103,19 @@ it("stays hidden where the server has no hand-off (the desktop's own Studio)", a expect(button()).toBeNull(); }); -it("stays hidden when the app has no build for this machine (Windows)", async () => { +it("stays hidden when the app has no build for this machine (FreeBSD)", async () => { serve(Response.json({ available: false, handoff: true, downloadUrl: null })); await mount(); expect(button()).toBeNull(); }); -it("with the app installed but no download (Windows), shows only once the app can take the project", async () => { +it("with the app installed but no download (FreeBSD), shows only once the app can take the project", async () => { serve(Response.json({ available: true, handoff: false, downloadUrl: null })); await mount(); expect(button()).toBeNull(); }); -it("opens the project in an installed app that has no download (Windows)", async () => { +it("opens the project in an installed app that has no download (FreeBSD)", async () => { serve(Response.json({ available: true, handoff: true, downloadUrl: null }), { opened: true, app: "the HyperFrames desktop app", @@ -381,6 +381,28 @@ it("where the app is installed but cannot take a project (Linux), step 3 shows t expect(posts).toBe(0); }); +it("on Windows, step 1 names the Windows download and opens it tagged", async () => { + const opened: string[] = []; + vi.stubGlobal("open", (url: string) => (opened.push(url), { opener: {} })); + serve( + Response.json({ + available: true, + handoff: false, + downloadUrl: `${DOWNLOAD}?os=windows`, + os: "win32", + installed: false, + }), + ); + await mount(); + expect(button()).not.toBeNull(); + await act(async () => button()!.click()); + await act(async () => cardButton("Download for Windows")!.click()); + expect(opened).toEqual([tagged(`${DOWNLOAD}?os=windows`)]); + expect(events("desktop_cta_eligibility")).toEqual([ + { eligibility: "download", os: "win32", app_installed: false, download_available: true }, + ]); +}); + it("counts where the button can show, the app here, and platforms with no app", async () => { serve( Response.json({ @@ -402,7 +424,7 @@ it("counts where the button can show, the app here, and platforms with no app", available: false, handoff: false, downloadUrl: null, - os: "win32", + os: "freebsd", installed: false, }), ); @@ -411,7 +433,7 @@ it("counts where the button can show, the app here, and platforms with no app", expect(events("desktop_cta_eligibility")).toEqual([ { eligibility: "no_app_for_platform", - os: "win32", + os: "freebsd", app_installed: false, download_available: false, },