Skip to content
Source
Sign inSign up

NativeAppIconResolver.test.ts

62 lines2.9 KB

1import * as NodeCrypto from "@effect/platform-node/NodeCrypto";
2import * as NodeServices from "@effect/platform-node/NodeServices";
3import { expect, it } from "@effect/vitest";
4import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";
6import * as Layer from "effect/Layer";
7import * as Path from "effect/Path";
8import { ChildProcessSpawner } from "effect/process";
9import * as HostProcess from "@t3tools/shared/HostProcess";
10​
11import * as ServerConfig from "../config.ts";
12import * as NativeAppIconResolver from "./NativeAppIconResolver.ts";
13​
14it.effect("resolves the exact bundle path without Spotlight and caches the converted icon", () =>
15 Effect.gen(function* () {
16 const fs = yield* FileSystem.FileSystem;
17 const path = yield* Path.Path;
18 const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-bundle-icon-" });
19 const bundle = path.join(root, "Build Output", "My App.app");
20 const resources = path.join(bundle, "Contents", "Resources");
21 yield* fs.makeDirectory(resources, { recursive: true });
22 yield* fs.writeFileString(path.join(resources, "AppIcon.icns"), "icon");
23 const commands: string[] = [];
24 const spawner = Layer.mock(ChildProcessSpawner.ChildProcessSpawner)({
25 string: (command) =>
26 Effect.gen(function* () {
27 if (command._tag !== "StandardCommand") return "";
28 commands.push(command.command);
29 if (command.command === "/usr/bin/plutil") return "AppIcon";
30 if (command.command === "/usr/bin/sips") {
31 yield* fs.writeFileString(String(command.args.at(-1)), "converted icon");
32 }
33 return "";
34 }),
35 });
36 yield* Effect.gen(function* () {
37 const resolver = yield* NativeAppIconResolver.make;
38 const reference = { _tag: "app-path" as const, path: bundle };
39 const icon = yield* resolver.resolve(reference);
40 expect(icon).not.toBeNull();
41 if (icon === null) return;
42 expect(yield* fs.readFileString(icon)).toBe("converted icon");
43 expect(yield* resolver.resolve(reference)).toBe(icon);
44 expect(yield* resolver.resolve({ _tag: "app-path", path: "~/Build Output/My App.app" })).toBe(
45 icon,
46 );
47 expect(commands.filter((command) => command === "/usr/bin/sips")).toHaveLength(1);
48 expect(commands).not.toContain("/usr/bin/mdfind");
49 expect(yield* resolver.resolve({ _tag: "app-path", path: "relative.app" })).toBeNull();
50 expect(yield* resolver.resolve({ _tag: "app-path", path: root })).toBeNull();
51 }).pipe(
52 Effect.provide(
53 Layer.mergeAll(
54 spawner,
55 ServerConfig.ServerConfig.layerTest(root, { prefix: "t3-native-icon-config-" }),
56 ),
57 ),
58 Effect.provideService(HostProcess.Platform, "darwin"),
59 Effect.provideService(HostProcess.HomeDirectory, root),
60 );
61 }).pipe(Effect.provide(Layer.mergeAll(NodeServices.layer, NodeCrypto.layer))),
62);