feat(studio): recover matching Nitro sources and persist import phases

This commit is contained in:
2026-09-11 10:22:06 +02:00
parent 00e33623f7
commit 13bd3695cb
45 changed files with 903 additions and 28 deletions
+28 -1
View File
@@ -4,6 +4,8 @@ import { MySqlDialect } from "drizzle-orm/mysql-core";
import { beforeEach, describe, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({
nitroExists: true,
write: vi.fn(),
official: vi.fn(),
download: vi.fn(),
execute: vi.fn(),
@@ -24,9 +26,10 @@ vi.mock("@/lib/db", () => ({
CatalogPages: {},
}));
vi.mock("node:fs", () => ({
existsSync: () => true,
existsSync: (path: string) => !path.endsWith(".nitro") || mocks.nitroExists,
promises: {
stat: mocks.stat,
writeFile: mocks.write,
readFile: vi.fn().mockResolvedValue(Buffer.alloc(256)),
},
}));
@@ -57,6 +60,9 @@ vi.mock("@/lib/services/import/core/download", () => ({
vi.mock("@/lib/services/swf-to-nitro", () => ({
parseNitroBundle: () => ({ json: {} }),
extractIconFromSwfAsync: async () => null,
convertSwfToNitroAsync: async () => {
throw Error("Source conversion failed");
},
}));
import { importSingleFurni } from "./furni-import";
@@ -78,6 +84,10 @@ function queries() {
describe("completion of existing furniture", () => {
beforeEach(() => {
vi.clearAllMocks();
mocks.nitroExists = true;
mocks.write.mockImplementation(async () => {
mocks.nitroExists = true;
});
mocks.official.mockResolvedValue(null);
mocks.download.mockResolvedValue(false);
const rows = [
@@ -92,6 +102,23 @@ describe("completion of existing furniture", () => {
mocks.execute.mockResolvedValue([[{ id: 123, page_id: "15" }], []]);
mocks.build.mockImplementation((value) => value);
});
it("recovers missing Nitro before completing the existing item without changing its IDs", async () => {
mocks.nitroExists = false;
const recover = vi.fn(async () => Buffer.alloc(256));
const result = await importSingleFurni({
...input,
resolveMissingNitro: recover,
});
expect(recover).toHaveBeenCalledWith(1);
expect(mocks.write).toHaveBeenCalledWith(
expect.stringContaining("recycler_scrapbookA.nitro"),
expect.any(Buffer),
{ flag: "wx" },
);
expect(result.ok).toBe(true);
expect(result.itemId).toBe(2000037257);
});
it("reuses local item and sprite IDs without rewriting SQL settings or offers", async () => {
const result = await importSingleFurni(input);
expect(result.ok).toBe(true);