feat(FN-4091): fix stale blocker in WorkflowResultsTab
The branch delivers a fix for stale blockers in the WorkflowResultsTab component, with the primary logic change in the component file and comprehensive test coverage added in the companion test suite. Fusion-Task-Id: FN-4091
This commit is contained in:
@@ -305,11 +305,38 @@ describe("getTaskCompletionBlocker", () => {
|
||||
await expect(getTaskCompletionBlocker(baseCompletionTask)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("returns a reason when task has blockedBy", async () => {
|
||||
it("returns a reason when task has blockedBy without resolveTask", async () => {
|
||||
await expect(getTaskCompletionBlocker({ ...baseCompletionTask, blockedBy: "FN-123" }))
|
||||
.resolves.toBe("task is blocked by FN-123");
|
||||
});
|
||||
|
||||
it("ignores blockedBy when resolveTask reports the blocker missing", async () => {
|
||||
const resolveTask = async () => null;
|
||||
|
||||
await expect(getTaskCompletionBlocker({
|
||||
...baseCompletionTask,
|
||||
blockedBy: "FN-4054",
|
||||
}, { resolveTask })).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it.each(["done", "archived"] as const)("ignores blockedBy when resolveTask reports the blocker is %s", async (column) => {
|
||||
const resolveTask = async () => ({ id: "FN-4054", column });
|
||||
|
||||
await expect(getTaskCompletionBlocker({
|
||||
...baseCompletionTask,
|
||||
blockedBy: "FN-4054",
|
||||
}, { resolveTask })).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it.each(["todo", "in-progress", "in-review"] as const)("returns a reason when resolveTask reports an active blocker in %s", async (column) => {
|
||||
const resolveTask = async () => ({ id: "FN-123", column });
|
||||
|
||||
await expect(getTaskCompletionBlocker({
|
||||
...baseCompletionTask,
|
||||
blockedBy: "FN-123",
|
||||
}, { resolveTask })).resolves.toBe("task is blocked by FN-123");
|
||||
});
|
||||
|
||||
it("returns a reason when a dependency is unresolved", async () => {
|
||||
const resolveTask = async (taskId: string) => {
|
||||
if (taskId === "FN-001") {
|
||||
|
||||
@@ -123,6 +123,11 @@ export function isTaskReadyForMerge(
|
||||
}
|
||||
|
||||
export interface TaskCompletionBlockerOptions {
|
||||
/**
|
||||
* Resolves a task reference so completion gating can distinguish live blockers
|
||||
* from stale `blockedBy` markers. Missing tasks and blockers already in
|
||||
* `done`/`archived` are treated as non-blocking.
|
||||
*/
|
||||
resolveTask?: (taskId: string) => Promise<Pick<Task, "id" | "column"> | null | undefined>;
|
||||
}
|
||||
|
||||
@@ -138,8 +143,16 @@ export async function getTaskCompletionBlocker(
|
||||
task: Pick<Task, "blockedBy" | "dependencies">,
|
||||
options: TaskCompletionBlockerOptions = {},
|
||||
): Promise<string | undefined> {
|
||||
if (task.blockedBy?.trim()) {
|
||||
return `task is blocked by ${task.blockedBy.trim()}`;
|
||||
const blockedBy = task.blockedBy?.trim();
|
||||
if (blockedBy) {
|
||||
if (!options.resolveTask) {
|
||||
return `task is blocked by ${blockedBy}`;
|
||||
}
|
||||
|
||||
const blocker = await options.resolveTask(blockedBy);
|
||||
if (blocker && blocker.column !== "done" && blocker.column !== "archived") {
|
||||
return `task is blocked by ${blockedBy}`;
|
||||
}
|
||||
}
|
||||
|
||||
const dependencies = task.dependencies ?? [];
|
||||
|
||||
Reference in New Issue
Block a user