修复了2个bug
This commit is contained in:
1 parent
ce8372e878
commit
2a64dc7395
64 files changed
+1050
-39
No files matched your search
@@ -1,7 +1,21 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { hasCompleteSeedreamLayerMetadata } from "@/lib/seedream/layer-composition";
|
||||
|
||||
describe("Seedream layer composition persistence contract", () => {
|
||||
it("only enables the editable layer project for complete provider layer metadata", () => {
|
||||
expect(hasCompleteSeedreamLayerMetadata([
|
||||
{ z_index: 0, size: "2048x2048" },
|
||||
{ z_index: 1, size: "600x300" }
|
||||
], 2)).toBe(true);
|
||||
expect(hasCompleteSeedreamLayerMetadata([
|
||||
{ size: "2048x2048" },
|
||||
{ size: "600x300" }
|
||||
], 2)).toBe(false);
|
||||
expect(hasCompleteSeedreamLayerMetadata([{ z_index: 0 }], 2)).toBe(false);
|
||||
expect(hasCompleteSeedreamLayerMetadata([{ z_index: 0 }], 1)).toBe(false);
|
||||
});
|
||||
|
||||
it("ships a versioned PostgreSQL document table that follows generation-job deletion", async () => {
|
||||
const migration = await readFile(new URL("../database/migrations/0005_seedream_layer_compositions.sql", import.meta.url), "utf8");
|
||||
|
||||
|
||||
@@ -38,6 +38,28 @@ describe("Seedream layer edit result synchronization", () => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it("uses the supported asset collection when production rejects platform item GET", async () => {
|
||||
vi.useFakeTimers();
|
||||
vi.stubGlobal("window", { setTimeout, clearTimeout });
|
||||
const job = { ...succeededBeforeOutputSync, outputAssetIds: [resultAsset.id] };
|
||||
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
|
||||
const url = String(input);
|
||||
if (url === "/api/generations/image/job-edit-1") return Response.json({ job });
|
||||
if (url === "/api/assets/asset-result") return new Response(null, { status: 405 });
|
||||
if (url === "/api/assets") return Response.json({ assets: [resultAsset] });
|
||||
return Response.json({ error: "unexpected request" }, { status: 404 });
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const pending = waitForJobOutputAssets(job, new AbortController().signal);
|
||||
const assertion = expect(pending).resolves.toEqual([resultAsset]);
|
||||
await vi.runAllTimersAsync();
|
||||
|
||||
await assertion;
|
||||
expect(fetchMock).toHaveBeenCalledWith("/api/assets", expect.objectContaining({ cache: "no-store" }));
|
||||
expect(fetchMock).not.toHaveBeenCalledWith("/api/assets/asset-result", expect.anything());
|
||||
});
|
||||
|
||||
it("refreshes a succeeded job whose output IDs arrive after the terminal status", async () => {
|
||||
vi.useFakeTimers();
|
||||
vi.stubGlobal("window", { setTimeout, clearTimeout });
|
||||
@@ -46,7 +68,7 @@ describe("Seedream layer edit result synchronization", () => {
|
||||
if (url === "/api/generations/image/job-edit-1") {
|
||||
return Response.json({ job: { ...succeededBeforeOutputSync, outputAssetIds: [resultAsset.id] } });
|
||||
}
|
||||
if (url === "/api/assets/asset-result") return Response.json({ asset: resultAsset });
|
||||
if (url === "/api/assets") return Response.json({ assets: [resultAsset] });
|
||||
return Response.json({ error: "unexpected request" }, { status: 404 });
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
@@ -56,10 +78,10 @@ describe("Seedream layer edit result synchronization", () => {
|
||||
|
||||
await expect(pending).resolves.toEqual([resultAsset]);
|
||||
expect(fetchMock).toHaveBeenCalledWith("/api/generations/image/job-edit-1", expect.objectContaining({ cache: "no-store" }));
|
||||
expect(fetchMock).toHaveBeenCalledWith("/api/assets/asset-result", expect.objectContaining({ cache: "no-store" }));
|
||||
expect(fetchMock).toHaveBeenCalledWith("/api/assets", expect.objectContaining({ cache: "no-store" }));
|
||||
});
|
||||
|
||||
it("retries the direct asset lookup while the registered result is not readable yet", async () => {
|
||||
it("retries the asset collection while the registered result is not readable yet", async () => {
|
||||
vi.useFakeTimers();
|
||||
vi.stubGlobal("window", { setTimeout, clearTimeout });
|
||||
let assetReads = 0;
|
||||
@@ -67,11 +89,11 @@ describe("Seedream layer edit result synchronization", () => {
|
||||
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
|
||||
const url = String(input);
|
||||
if (url === "/api/generations/image/job-edit-1") return Response.json({ job });
|
||||
if (url === "/api/assets/asset-result") {
|
||||
if (url === "/api/assets") {
|
||||
assetReads += 1;
|
||||
return assetReads === 1
|
||||
? Response.json({ error: "资产不存在" }, { status: 404 })
|
||||
: Response.json({ asset: resultAsset });
|
||||
? Response.json({ assets: [] })
|
||||
: Response.json({ assets: [resultAsset] });
|
||||
}
|
||||
return Response.json({ error: "unexpected request" }, { status: 404 });
|
||||
});
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const styles = read("../app/globals.css");
|
||||
const workspaceSource = read("../components/seedream-workspace.tsx");
|
||||
|
||||
function read(relativePath: string): string {
|
||||
return readFileSync(fileURLToPath(new URL(relativePath, import.meta.url)), "utf8").replace(/\r\n/g, "\n");
|
||||
}
|
||||
|
||||
function cssRule(selector: string): string {
|
||||
const escapedSelector = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
const match = styles.match(new RegExp(`${escapedSelector}\\s*\\{([^}]*)\\}`));
|
||||
if (!match) throw new Error(`CSS rule not found: ${selector}`);
|
||||
return match[1];
|
||||
}
|
||||
|
||||
describe("Seedream workspace layout contract", () => {
|
||||
it("keeps vertical scrolling on the workspace instead of nesting it inside the canvas", () => {
|
||||
const workspace = cssRule(".seedream-workspace");
|
||||
const viewport = cssRule(".seedream-canvas-viewport");
|
||||
|
||||
expect(workspace).toMatch(/overflow-x\s*:\s*hidden/);
|
||||
expect(workspace).toMatch(/overflow-y\s*:\s*auto/);
|
||||
expect(workspace).not.toMatch(/overflow\s*:\s*auto/);
|
||||
expect(viewport).toMatch(/overflow\s*:\s*hidden/);
|
||||
expect(viewport).not.toMatch(/overflow\s*:\s*(?:auto|scroll)/);
|
||||
});
|
||||
|
||||
it("caps the annotation canvas without making it consume the remaining column height", () => {
|
||||
const viewport = cssRule(".seedream-canvas-viewport");
|
||||
const image = cssRule(".seedream-canvas-stage > img");
|
||||
|
||||
expect(viewport).toMatch(/--seedream-canvas-height\s*:\s*clamp\(280px,\s*38vh,\s*460px\)/);
|
||||
expect(viewport).toMatch(/height\s*:\s*var\(--seedream-canvas-height\)/);
|
||||
expect(viewport).toMatch(/flex\s*:\s*0\s+0\s+auto/);
|
||||
expect(image).toMatch(/max-height\s*:\s*calc\(var\(--seedream-canvas-height\)\s*-\s*22px\)/);
|
||||
});
|
||||
|
||||
it("does not render the redundant source picker for single-image layer decomposition", () => {
|
||||
expect(workspaceSource).toMatch(/\{mode === "interactive" && sources\.length \? \(\s*<div className="seedream-source-picker">/);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user