f30acef101
Deploy / deploy (push) Successful in 5m17s
A built package used to become DELIVERED on one click with nothing behind it, and nothing recorded what a client had asked for. - Marking delivered is now two recorded steps: Record upload (the link on the client's portal, contents confirmed) then Share link (who it was sent to). The second is refused until the first is on record. - Delivery requests log a client's ask by episode, pasted shot codes or a Shot Status selection. A line closes only when its shot goes out with evidence after the request was logged; a request can otherwise only be cancelled with a reason. - Delivered Outside Pipeline takes an upload link and recipient, required for shots on an open request. - The dashboard gains an Awaiting delivery section listing open requests and built packages the client does not have yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
73 lines
2.7 KiB
TypeScript
73 lines
2.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { buildShareMessage, handoffStage, recordShareSchema, recordUploadSchema } from "./delivery-handoff";
|
|
|
|
describe("handoffStage", () => {
|
|
const ready = { kind: "EXR_DELIVERY", status: "READY", uploadedAt: null };
|
|
|
|
it("waits on the upload first, then on the share", () => {
|
|
expect(handoffStage(ready)).toBe("AWAITING_UPLOAD");
|
|
expect(handoffStage({ ...ready, uploadedAt: new Date() })).toBe("AWAITING_SHARE");
|
|
});
|
|
|
|
it("waits on nothing before the build or after delivery", () => {
|
|
expect(handoffStage({ ...ready, status: "BUILDING" })).toBeNull();
|
|
expect(handoffStage({ ...ready, status: "FAILED" })).toBeNull();
|
|
expect(handoffStage({ ...ready, status: "DELIVERED", uploadedAt: new Date() })).toBeNull();
|
|
});
|
|
|
|
it("never asks for a review package to be delivered", () => {
|
|
expect(handoffStage({ ...ready, kind: "MOV_REVIEW" })).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("recordUploadSchema", () => {
|
|
const url = "https://contenthub.example.com/folders/abc";
|
|
|
|
it("accepts a link with the contents confirmed", () => {
|
|
expect(recordUploadSchema.safeParse({ uploadUrl: url, contentsConfirmed: true }).success).toBe(true);
|
|
});
|
|
|
|
it("refuses an unconfirmed upload", () => {
|
|
expect(recordUploadSchema.safeParse({ uploadUrl: url, contentsConfirmed: false }).success).toBe(false);
|
|
expect(recordUploadSchema.safeParse({ uploadUrl: url }).success).toBe(false);
|
|
});
|
|
|
|
it("refuses anything that is not a web link", () => {
|
|
for (const uploadUrl of ["", "uploaded", "//SAN/DELIVERY/ACME/101", "javascript:alert(1)"]) {
|
|
expect(recordUploadSchema.safeParse({ uploadUrl, contentsConfirmed: true }).success).toBe(false);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("recordShareSchema", () => {
|
|
it("needs a recipient", () => {
|
|
expect(recordShareSchema.safeParse({ sharedWith: " " }).success).toBe(false);
|
|
expect(recordShareSchema.safeParse({ sharedWith: "Sam (post super)" }).success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("buildShareMessage", () => {
|
|
it("lists the packaged versions under the client's own shot codes", () => {
|
|
const message = buildShareMessage({
|
|
projectCode: "UNG",
|
|
episode: "116",
|
|
name: "20260930_Delivery",
|
|
uploadUrl: "https://contenthub.example.com/folders/abc",
|
|
items: [
|
|
{ shotCode: "UNG_116_020", clientCode: null, versionString: "v002" },
|
|
{ shotCode: "UNG_116_010", clientCode: "116_A_0010", versionString: "v004" },
|
|
],
|
|
});
|
|
expect(message).toBe(
|
|
[
|
|
"Delivery: UNG · episode 116 · 20260930_Delivery",
|
|
"2 shots",
|
|
"https://contenthub.example.com/folders/abc",
|
|
"",
|
|
"116_A_0010 v004",
|
|
"UNG_116_020 v002",
|
|
].join("\n")
|
|
);
|
|
});
|
|
});
|