Files
pleno-vue/tests/unit/self-serve-studio-task-scope.spec.js
T

150 lines
8.0 KiB
JavaScript

import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
const readSource = (relativePath) => readFileSync(join(process.cwd(), relativePath), "utf8");
describe("self-serve studio task editing", () => {
const studioSource = () =>
readSource("src/views/dashboards/departmentDashboard/modules/self-serve/DepartmentSelfServeStudio.vue");
it("creates tasks with scoped runtime fields and dynamic image defaults", () => {
const source = studioSource();
expect(source).toContain("const createNode = async (kind) => {");
expect(source).toContain('task: "New task"');
expect(source).toContain('gate_type: "ALWAYS"');
expect(source).toContain("lane: parseNullableInt(filters.value.lane_id) || 0");
expect(source).toContain("product: parseNullableInt(filters.value.vehicle_type_id) || 0");
expect(source).toContain("machine_type_id: parseNullableInt(filters.value.machine_type_id)");
expect(source).toContain("services: []");
expect(source).toContain("buttons: []");
});
it("normalizes task services and mapped buttons before saving inspector edits", () => {
const source = studioSource();
expect(source).toContain('inspectorForm.value.gate_type ||= "ALWAYS"');
expect(source).toContain("inspectorForm.value.services = normalizeServiceList(inspectorForm.value.services)");
expect(source).toContain("inspectorForm.value.buttons = normalizeButtonList(inspectorForm.value.buttons)");
expect(source).toContain("data.services = normalizeServiceList(data.services)");
expect(source).toContain("data.buttons = normalizeButtonList(data.buttons)");
});
it("renders mapped dynamic image task buttons in the inspector", () => {
const source = studioSource();
expect(source).toContain("SELF_SERVE_TASK_BUTTON_OPTIONS");
expect(source).toContain('data-testid="studio-task-button-picker"');
expect(source).toContain('v-model="inspectorForm.buttons"');
expect(source).toContain("taskButtonIsSelected(inspectorForm.buttons, option.id)");
expect(source).toContain("taskButtonSummary(rawFor(data).buttons)");
});
it("renders dynamic image previews in simulator results", () => {
const source = studioSource();
expect(source).toContain("getSelfServeDynamicImageButtonsToPress(simulatorPreviewTasks.value)");
expect(source).toContain(
"const simulatorDynamicImageCurrentStep = computed(() => getSelfServeCompletedDynamicImageStep("
);
expect(source).toContain("const simulatorDynamicImageUrl = computed(() => {");
expect(source).toContain("buildSelfServeDynamicImageUrl({");
expect(source).toContain("currentStep: simulatorDynamicImageCurrentStep.value");
expect(source).toContain("const buildSimulatorPayload = () => {");
expect(source).toContain('const scheduleSimulatorRun = (reason = "change", delayMs = 250) => {');
expect(source).toContain('data-testid="studio-simulator-steps"');
expect(source).toContain('data-testid="studio-simulator-dynamic-image"');
expect(source).toContain('data-testid="studio-simulator-dynamic-image-reason"');
expect(source).toContain('@error="onSimulatorDynamicImageError"');
});
it("renders the simulator as an auto-running full-width workspace", () => {
const source = studioSource();
expect(source).toContain("'is-simulator-panel': activePanel === 'simulator'");
expect(source).toContain('data-testid="studio-simulator-workspace"');
expect(source).toContain("const focusSimulatorNodes = async (nodeIds = [], openInspector = false) => {");
expect(source).toContain('activePanel.value = openInspector ? "inspector" : "flow";');
expect(source).toContain('const scheduleSimulatorRun = (reason = "change", delayMs = 250) => {');
expect(source).toContain('aria-label="Simulator controls"');
expect(source).not.toContain("<span>Run</span>");
expect(source).not.toContain('@submit.prevent="runSimulator');
});
it("requires lane and vehicle scope with URL and simulator local persistence", () => {
const source = studioSource();
expect(source).toContain("const scopeFiltersFromRoute = () => ({");
expect(source).toContain("const showScopeGuide = computed(() => (");
expect(source).toContain("const applyScopeGuideSelection = () => {");
expect(source).toContain("const writeScopeToRoute = () => {");
expect(source).toContain("const simulatorStorageKey = computed(() => [");
expect(source).toContain("const restoreSimulatorStateFromStorage = () => {");
expect(source).toContain("const persistSimulatorStateToStorage = () => {");
expect(source).toContain('data-testid="studio-scope-guide"');
expect(source).toContain('data-testid="studio-scope-apply"');
expect(source).toContain('<option value="" disabled>Select lane</option>');
expect(source).toContain('<option value="" disabled>Select vehicle type</option>');
});
it("renders task attachments in the flow nodes and simulator without saving them into draft tasks", () => {
const source = studioSource();
expect(source).toContain("const taskAttachmentList = (dataOrRaw) => {");
expect(source).toContain("const selectedTaskAttachments = computed(() => (");
expect(source).toContain("const uploadSelectedTaskAttachment = async (event) => {");
expect(source).toContain("const deleteSelectedTaskAttachment = async (attachment) => {");
expect(source).toContain('data-testid="studio-task-node-attachments"');
expect(source).toContain('data-testid="studio-task-attachment-manager"');
expect(source).toContain('data-testid="studio-task-attachment-upload"');
expect(source).toContain('class="studio-debug-attachment-list"');
expect(source).toContain('@click.stop="openTaskAttachment(attachment)"');
expect(source).toContain("delete data.attachments");
});
it("renders machine type and dynamic image filters in the studio toolbar", () => {
const source = studioSource();
expect(source).toContain('dynamic_image_id: ""');
expect(source).toContain('data-testid="studio-filter-machine-type"');
expect(source).toContain('data-testid="studio-filter-dynamic-image"');
expect(source).toContain("lookupRows('dynamic_images')");
expect(source).toContain(
'matchesScopeFilter(node, "machine_type", normalizeFilterValue(filters.value.machine_type_id))'
);
expect(source).toContain(
'matchesScopeFilter(node, "dynamic_image", normalizeFilterValue(filters.value.dynamic_image_id))'
);
expect(source).toContain("laneLookupForNode(node)?.machine_type_id");
expect(source).toContain("laneLookupForNode(node)?.dynamic_image_id");
});
it("manages lanes and previews the selected lane dynamic image", () => {
const source = studioSource();
expect(source).toContain('{ id: "lanes", label: "Lanes"');
expect(source).toContain("const saveLane = async () => {");
expect(source).toContain('entity: "lane"');
expect(source).toContain("selfserve_enabled: true");
expect(source).toContain("selfserve_enabled: normalizeSelfServeEnabledFlag(form?.selfserve_enabled)");
expect(source).toContain("const buildLaneDynamicImagePreviewUrl = (laneId, dynamicImageId) => {");
expect(source).toContain("dynamicImageId: normalizedDynamicImageId");
expect(source).toContain('data-testid="studio-lane-selfserve-enabled"');
expect(source).toContain('data-testid="studio-inspector-lane-selfserve-enabled"');
expect(source).toContain('data-testid="studio-lane-dynamic-image"');
expect(source).toContain('data-testid="studio-lane-dynamic-image-preview"');
expect(source).toContain('data-testid="studio-inspector-lane-dynamic-image-preview"');
});
it("supports task priority reordering from the task panel", () => {
const source = studioSource();
expect(source).toContain("const reorderTask = async (taskNode, direction) => {");
expect(source).toContain("order_priority: index + 1");
expect(source).toContain('action: "reorder"');
expect(source).toContain('@click="reorderTask(node, -1)"');
expect(source).toContain('@click="reorderTask(node, 1)"');
});
});