| ... | ... | @@ -3,10 +3,13 @@ import type { RepositoryIdentity } from "@t3tools/contracts"; |
| 3 | 3 | import * as Deferred from "effect/Deferred"; |
| 4 | 4 | import * as Effect from "effect/Effect"; |
| 5 | 5 | import * as Layer from "effect/Layer"; |
| 6 | import * as Logger from "effect/Logger"; |
| 6 | 7 | import * as PubSub from "effect/PubSub"; |
| 7 | 8 | import * as Ref from "effect/Ref"; |
| 8 | 9 | import { TestClock } from "effect/testing"; |
| 9 | 10 | |
| 11 | import * as WorkspacePaths from "../workspace/WorkspacePaths.ts"; |
| 12 | |
| 10 | 13 | import * as ProjectEnrichment from "./ProjectEnrichmentService.ts"; |
| 11 | 14 | import * as ProjectFaviconResolver from "./ProjectFaviconResolver.ts"; |
| 12 | 15 | import * as RepositoryIdentityResolver from "./RepositoryIdentityResolver.ts"; |
| ... | ... | @@ -95,6 +98,58 @@ it.effect("preserves either enrichment field when the other resolver fails", () |
| 95 | 98 | }), |
| 96 | 99 | ); |
| 97 | 100 | |
| 101 | it.effect("does not warn about favicons for workspace roots that no longer exist", () => |
| 102 | Effect.gen(function* () { |
| 103 | const warnings: Array<unknown> = []; |
| 104 | const logger = Logger.make(({ message }) => { |
| 105 | warnings.push(message); |
| 106 | }); |
| 107 | const metadataLayer = Layer.merge( |
| 108 | Layer.succeed(RepositoryIdentityResolver.RepositoryIdentityResolver, { |
| 109 | resolve: (workspaceRoot) => Effect.succeed(identity(workspaceRoot)), |
| 110 | }), |
| 111 | Layer.succeed(ProjectFaviconResolver.ProjectFaviconResolver, { |
| 112 | resolvePath: (workspaceRoot) => |
| 113 | Effect.fail( |
| 114 | workspaceRoot === "/missing" |
| 115 | ? new ProjectFaviconResolver.ProjectFaviconResolutionError({ |
| 116 | operation: "normalize-workspace", |
| 117 | workspaceRoot, |
| 118 | cause: new WorkspacePaths.WorkspaceRootNotExistsError({ |
| 119 | workspaceRoot, |
| 120 | normalizedWorkspaceRoot: workspaceRoot, |
| 121 | }), |
| 122 | }) |
| 123 | : new ProjectFaviconResolver.ProjectFaviconResolutionError({ |
| 124 | operation: "stat-candidate", |
| 125 | workspaceRoot, |
| 126 | cause: "favicon resolver failed", |
| 127 | }), |
| 128 | ), |
| 129 | }), |
| 130 | ); |
| 131 | |
| 132 | yield* Effect.gen(function* () { |
| 133 | const service = yield* ProjectEnrichment.ProjectEnrichmentService; |
| 134 | yield* service.request("/missing"); |
| 135 | yield* service.request("/broken"); |
| 136 | |
| 137 | for (let attempt = 0; attempt < 100 && warnings.length === 0; attempt += 1) { |
| 138 | yield* Effect.yieldNow; |
| 139 | } |
| 140 | |
| 141 | assert.lengthOf(warnings, 1); |
| 142 | assert.nestedPropertyVal(warnings[0], "[1].workspaceRoot", "/broken"); |
| 143 | }).pipe( |
| 144 | Effect.provide( |
| 145 | layer(metadataLayer, { concurrency: 1 }).pipe( |
| 146 | Layer.provide(Logger.layer([logger], { mergeWithExisting: false })), |
| 147 | ), |
| 148 | ), |
| 149 | ); |
| 150 | }), |
| 151 | ); |
| 152 | |
| 98 | 153 | it.effect("publishes repository completion while favicon enrichment is still pending", () => |
| 99 | 154 | Effect.gen(function* () { |
| 100 | 155 | const releaseFavicon = yield* Deferred.make<void>(); |