Remove Cypress and update scripts to use Playwright for E2E testing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 16:44:58 +08:00
parent 6e7d010c54
commit f828bd0423
42 changed files with 6 additions and 5115 deletions

5
.gitignore vendored
View File

@@ -15,11 +15,6 @@ coverage
*.local
/dist
# Cypress
cypress.env.json
/cypress/videos/
/cypress/screenshots/
# Playwright
/test-results/
/playwright-report/

View File

@@ -1,25 +0,0 @@
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/1/31
// cindy.chang@dsp.im (Cindy Chang), 2024/8/12
// imacat.yang@dsp.im (imacat), 2026/3/5
/**
* @module cypress.config
* Cypress E2E test configuration with viewport
* settings and base URL.
*/
const { defineConfig } = require("cypress");
module.exports = defineConfig({
defaultCommandTimeout: 6000,
viewportWidth: 1280,
viewportHeight: 720,
e2e: {
baseUrl: "http://localhost:4173",
specPattern: "cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}",
},
includeShadowDom: true,
env: {},
});

View File

@@ -1,32 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Account Management", () => {
beforeEach(() => {
loginWithFixtures();
});
it("displays user list on account admin page", () => {
cy.visit("/account-admin");
// Should display users from fixture
cy.contains("Test Admin").should("exist");
cy.contains("Alice Wang").should("exist");
cy.contains("Bob Chen").should("exist");
});
it("shows active/inactive status badges", () => {
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
// The user list should show status indicators
cy.contains("testadmin").should("exist");
});
it("navigates to my-account page", () => {
cy.visit("/my-account");
cy.url().should("include", "/my-account");
});
});

View File

@@ -1,72 +0,0 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/03
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../../support/intercept";
const MSG_ACCOUNT_NOT_UNIQUE = "Account has already been registered.";
describe("Account duplication check.", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
});
it("When an account already exists, show error message on confirm.", () => {
const testAccountName = "000000";
// First creation: account doesn't exist yet — override via MSW
cy.window().then((win) => {
const { http, HttpResponse } = win.__msw__;
win.__mswWorker__.use(
http.get("/api/users/000000", () =>
HttpResponse.json(
{ detail: "Not found" },
{ status: 404 },
)),
);
});
cy.contains("button", "Create New").should("be.visible").click();
cy.get("#input_account_field").type(testAccountName);
cy.get("#input_name_field").type(testAccountName);
cy.get("#input_first_pwd").type(testAccountName);
cy.get(".checkbox-and-text").first().find("div").first().click();
cy.contains("button", "Confirm")
.should("be.visible")
.and("be.enabled")
.click();
cy.contains("Account added").should("be.visible");
// Second creation: now account exists — override to return 200 via MSW
cy.window().then((win) => {
const { http, HttpResponse } = win.__msw__;
win.__mswWorker__.use(
http.get("/api/users/000000", () =>
HttpResponse.json({
username: "000000",
name: "000000",
is_admin: false,
is_active: true,
roles: [],
})),
);
});
cy.contains("button", "Create New").should("be.visible").click();
cy.get("#input_account_field").type(testAccountName);
cy.get("#input_name_field").type(testAccountName);
cy.get("#input_first_pwd").type(testAccountName);
cy.get(".checkbox-and-text").first().find("div").first().click();
cy.contains("button", "Confirm")
.should("be.visible")
.and("be.enabled")
.click();
cy.contains(MSG_ACCOUNT_NOT_UNIQUE).should("be.visible");
});
});

View File

@@ -1,36 +0,0 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/02
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../../support/intercept";
describe("Password validation on create account.", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
});
it("When password is too short, confirm button stays disabled.", () => {
cy.contains("button", "Create New").should("be.visible").click();
cy.get("#input_account_field").type("unit-test-0001");
cy.get("#input_name_field").type("unit-test-0001");
// Password shorter than 6 characters
cy.get("#input_first_pwd").type("aaa");
cy.contains("button", "Confirm").should("be.disabled");
});
it("When password meets minimum length, confirm button enables.", () => {
cy.contains("button", "Create New").should("be.visible").click();
cy.get("#input_account_field").type("unit-test-0001");
cy.get("#input_name_field").type("unit-test-0001");
cy.get("#input_first_pwd").type("aaaaaa");
cy.contains("button", "Confirm").should("be.enabled");
});
});

View File

@@ -1,50 +0,0 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/02
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../../support/intercept";
describe("Create an Account", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
// Override: new usernames should return 404 (account doesn't exist yet)
cy.window().then((win) => {
const { http, HttpResponse } = win.__msw__;
win.__mswWorker__.use(
http.get("/api/users/:username", ({ params }) => {
if (params.username.startsWith("unit-test-")) {
return HttpResponse.json(
{ detail: "Not found" },
{ status: 404 },
);
}
}),
);
});
});
it("Create a new account with admin role; should show saved message.", () => {
cy.contains("button", "Create New").should("be.visible").click();
cy.get("#input_account_field").type("unit-test-0001");
cy.get("#input_name_field").type("unit-test-0001");
cy.get("#input_first_pwd").type("aaaaaa");
cy.get(".checkbox-and-text").first().find("div").first().click();
cy.contains("button", "Confirm")
.should("be.visible")
.and("be.enabled")
.click();
cy.contains("Account added").should("be.visible");
});
it("Confirm button is disabled when required fields are empty.", () => {
cy.contains("button", "Create New").should("be.visible").click();
cy.get("#input_account_field").type("test");
cy.contains("button", "Confirm").should("be.disabled");
});
});

View File

@@ -1,29 +0,0 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/03
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../../support/intercept";
describe("Delete an Account", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
});
it("Delete button opens confirmation modal and deletes on confirm.", () => {
cy.get("img.delete-account").first().click();
cy.contains("ARE YOU SURE TO DELETE").should("be.visible");
cy.get("#sure_to_delete_acct_btn").click();
cy.contains("Account deleted").should("be.visible");
});
it("Cancel button closes the delete confirmation modal.", () => {
cy.get("img.delete-account").first().click();
cy.contains("ARE YOU SURE TO DELETE").should("be.visible");
cy.get("#calcel_delete_acct_btn").click();
cy.contains("ARE YOU SURE TO DELETE").should("not.exist");
});
});

View File

@@ -1,29 +0,0 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/07/03
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../../support/intercept";
const MODAL_TITLE_ACCOUNT_EDIT = "Account Edit";
const MSG_ACCOUNT_EDITED = "Saved";
describe("Edit an account", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
});
it("Edit an account; modify name and see saved message.", () => {
cy.get(".btn-edit").first().click();
cy.contains("h1", MODAL_TITLE_ACCOUNT_EDIT).should("exist");
cy.get("#input_name_field").clear();
cy.get("#input_name_field").type("Updated Name");
cy.contains("button", "Confirm").should("be.visible").and("be.enabled");
cy.contains("button", "Confirm").click();
cy.contains(MSG_ACCOUNT_EDITED).should("be.visible");
});
});

View File

@@ -1,96 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Account Management CRUD", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
});
it("shows Create New button", () => {
cy.get("#create_new_acct_btn").should("exist");
cy.get("#create_new_acct_btn").should("contain", "Create New");
});
it("opens create new account modal", () => {
cy.get("#create_new_acct_btn").click();
cy.get("#modal_container").should("be.visible");
cy.get("#modal_account_edit_or_create_new").should("be.visible");
// Should show account, name, password fields
cy.get("#input_account_field").should("exist");
cy.get("#input_name_field").should("exist");
cy.get("#input_first_pwd").should("exist");
});
it("create account confirm is disabled when fields are empty", () => {
cy.get("#create_new_acct_btn").click();
cy.get(".confirm-btn").should("be.disabled");
});
it("create account confirm enables when fields are filled", () => {
cy.get("#create_new_acct_btn").click();
cy.get("#input_account_field").type("newuser");
cy.get("#input_name_field").type("New User");
cy.get("#input_first_pwd").type("password1234");
cy.get(".confirm-btn").should("not.be.disabled");
});
it("cancel button closes the modal", () => {
cy.get("#create_new_acct_btn").click();
cy.get("#modal_container").should("be.visible");
cy.get(".cancel-btn").click();
cy.get("#modal_container").should("not.exist");
});
it("close (X) button closes the modal", () => {
cy.get("#create_new_acct_btn").click();
cy.get("#modal_container").should("be.visible");
cy.get('img[alt="X"]').click();
cy.get("#modal_container").should("not.exist");
});
it("double-click username opens account info modal", () => {
// Double-click on the first account username
cy.get(".account-cell").first().dblclick();
cy.get("#modal_container").should("be.visible");
});
it("delete button opens delete confirmation modal", () => {
// Click the delete icon for a non-current user
cy.get(".delete-account").first().click();
cy.get("#modal_container").should("be.visible");
cy.get("#modal_delete_acct_alert").should("be.visible");
});
it("delete modal has Yes and No buttons", () => {
cy.get(".delete-account").first().click();
cy.get("#calcel_delete_acct_btn").should("exist");
cy.get("#sure_to_delete_acct_btn").should("exist");
});
it("delete modal No button closes the modal", () => {
cy.get(".delete-account").first().click();
cy.get("#calcel_delete_acct_btn").click();
cy.get("#modal_container").should("not.exist");
});
it("shows checkboxes for Set as Admin and Activate in create modal", () => {
cy.get("#create_new_acct_btn").click();
cy.get("#account_create_checkboxes_section").should("be.visible");
cy.contains("Set as admin.").should("exist");
cy.contains("Activate now.").should("exist");
});
it("search bar filters user list", () => {
// Search filters by username, not display name
cy.get("#input_search").type("user1");
cy.get('img[alt="search"]').click();
// Should only show user1 (Alice Wang)
cy.contains("user1").should("exist");
});
});

View File

@@ -1,40 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Account Info Modal", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
});
it("double-click username opens info modal with user data", () => {
cy.get(".account-cell").first().dblclick();
cy.get("#modal_container").should("be.visible");
cy.get("#acct_info_user_name").should("exist");
});
it("info modal shows Account Information header", () => {
cy.get(".account-cell").first().dblclick();
cy.get("#modal_container").should("be.visible");
cy.contains("Account Information").should("exist");
});
it("info modal shows account visit info", () => {
cy.get(".account-cell").first().dblclick();
cy.get("#modal_container").should("be.visible");
cy.get("#account_visit_info").should("exist");
cy.get("#account_visit_info").should("contain", "Account:");
});
it("info modal can be closed via X button", () => {
cy.get(".account-cell").first().dblclick();
cy.get("#modal_container").should("be.visible");
cy.get('img[alt="X"]').click();
cy.get("#modal_container").should("not.exist");
});
});

View File

@@ -1,87 +0,0 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2024/02/22
// cindy.chang@dsp.im (Cindy Chang), 2024/05/30
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Compare", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
cy.contains("li", "COMPARE").click();
});
it("Compare dropdown sorting options", () => {
const expectedOptions = [
"By File Name (A to Z)",
"By File Name (Z to A)",
"By Dependency (A to Z)",
"By Dependency (Z to A)",
"By File Type (A to Z)",
"By File Type (Z to A)",
"By Last Update (A to Z)",
"By Last Update (Z to A)",
];
cy.get(".p-select").click();
cy.get(".p-select-list")
.find(".p-select-option")
.then(($options) => {
const actualOptions = $options
.map((index, elem) =>
Cypress.$(elem).find(".p-select-option-label").text(),
)
.get();
expect(actualOptions).to.deep.equal(expectedOptions);
});
});
it("Grid cards are rendered for compare file selection", () => {
cy.get("#compareGridCards").find("li").should("have.length.greaterThan", 0);
});
it("Compare button is disabled until two files are dragged", () => {
cy.contains("button", "Compare").should("be.disabled");
cy.get("#compareFile0").drag("#primaryDragCard");
cy.get("#compareFile1").drag("#secondaryDragCard");
cy.contains("button", "Compare").should("be.enabled");
});
it("Enter Compare dashboard and see charts", () => {
cy.get("#compareFile0").drag("#primaryDragCard");
cy.get("#compareFile1").drag("#secondaryDragCard");
cy.contains("button", "Compare").click();
cy.url().should("include", "compare");
// Assert chart title spans are visible
cy.contains("span", "Average Cycle Time").should("exist");
cy.contains("span", "Cycle Efficiency").should("exist");
cy.contains("span", "Average Processing Time").should("exist");
cy.contains("span", "Average Processing Time by Activity").should("exist");
cy.contains("span", "Average Waiting Time").should("exist");
cy.contains("span", "Average Waiting Time between Activity").should(
"exist",
);
});
it("Compare State button exists on dashboard", () => {
cy.get("#compareFile0").drag("#primaryDragCard");
cy.get("#compareFile1").drag("#secondaryDragCard");
cy.contains("button", "Compare").click();
cy.get("#compareState").should("exist").and("be.visible");
});
it("Sidebar shows time usage and frequency sections", () => {
cy.get("#compareFile0").drag("#primaryDragCard");
cy.get("#compareFile1").drag("#secondaryDragCard");
cy.contains("button", "Compare").click();
cy.get("aside").should("exist");
cy.get("aside li").should("have.length.greaterThan", 0);
});
});

View File

@@ -1,55 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Discover Conformance Page", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/discover/log/297310264/conformance");
cy.get(".p-radiobutton, [class*=conformance]").first().should("exist");
});
it("page loads and loading overlay disappears", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
});
it("displays Rule Settings sidebar", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Rule Settings").should("be.visible");
});
it("displays Conformance Checking Results heading", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Conformance Checking Results").should("be.visible");
});
it("displays rule type radio options", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Have activity").should("be.visible");
cy.contains("Activity sequence").should("be.visible");
cy.contains("Activity duration").should("be.visible");
cy.contains("Processing time").should("be.visible");
cy.contains("Waiting time").should("be.visible");
cy.contains("Cycle time").should("be.visible");
});
it("displays Clear and Apply buttons", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("button", "Clear").should("be.visible");
cy.contains("button", "Apply").should("exist");
});
it("displays Activity list area", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Activity list").should("be.visible");
});
it("displays default placeholder values in results", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Conformance Rate").should("be.visible");
cy.contains("Cases").should("be.visible");
});
});

View File

@@ -1,55 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Discover Map Page", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/discover/log/297310264/map");
cy.get("#cy").should("exist");
});
it("page loads and cytoscape container exists", () => {
cy.get("#cy").should("exist");
});
it("displays left sidebar buttons", () => {
// Visualization Setting, Filter, Traces buttons
cy.get(".material-symbols-outlined")
.contains("track_changes")
.should("exist");
cy.get(".material-symbols-outlined").contains("tornado").should("exist");
cy.get(".material-symbols-outlined").contains("rebase").should("exist");
});
it("displays right sidebar Summary button", () => {
cy.get("#sidebar_state").should("exist");
cy.get("#iconState").should("exist");
});
it("clicking Visualization Setting button toggles sidebar", () => {
// Click the track_changes icon (Visualization Setting)
cy.contains("span.material-symbols-outlined", "track_changes")
.parent("li")
.click();
// SidebarView should open
cy.contains("Visualization Setting").should("be.visible");
});
it("clicking Summary button toggles sidebar", () => {
cy.get("#iconState").click();
// SidebarState should open with insights/stats
cy.contains("Summary").should("be.visible");
});
it("clicking Traces button toggles sidebar", () => {
cy.contains("span.material-symbols-outlined", "rebase")
.parent("li")
.click();
// SidebarTraces should open
cy.contains("Traces").should("be.visible");
});
});

View File

@@ -1,66 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Discover Performance Page", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/discover/log/297310264/performance");
cy.get(".chart-container, canvas").should("exist");
});
it("page loads and loading overlay disappears", () => {
// Loading overlay should not be visible after data loads
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
});
it("displays Time Usage sidebar section", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Time Usage").should("be.visible");
});
it("displays Frequency sidebar section", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Frequency").should("be.visible");
});
it("displays sidebar navigation items", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Cycle Time & Efficiency").should("be.visible");
cy.contains("Processing Time").should("be.visible");
cy.contains("Waiting Time").should("be.visible");
cy.contains("Number of Cases").should("be.visible");
});
it("displays chart titles", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Average Cycle Time").should("be.visible");
cy.contains("Cycle Efficiency").should("be.visible");
cy.contains("Average Processing Time").should("be.visible");
cy.contains("Average Processing Time by Activity").should("be.visible");
cy.contains("Average Waiting Time").should("be.visible");
});
it("displays frequency chart titles", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("New Cases").should("be.visible");
cy.contains("Number of Cases by Activity").should("be.visible");
});
it("renders canvas elements for charts", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
// Chart.js renders into canvas elements
cy.get("canvas").should("have.length.at.least", 5);
});
it("sidebar navigation scrolls to section", () => {
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
// Click on "Waiting Time" in sidebar
cy.contains("li", "Waiting Time").click();
// The Waiting Time section should be in view
cy.get("#waitingTime").should("exist");
});
});

View File

@@ -1,88 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Discover Tab Navigation", () => {
beforeEach(() => {
loginWithFixtures();
});
describe("navigating from Map page", () => {
beforeEach(() => {
cy.visit("/discover/log/297310264/map");
cy.get("#cy").should("exist");
});
it("shows DISCOVER heading and MAP/CONFORMANCE/PERFORMANCE tabs", () => {
cy.get("#nav_bar").contains("DISCOVER").should("be.visible");
cy.get(".nav-item").should("have.length", 3);
cy.get(".nav-item").eq(0).should("contain", "MAP");
cy.get(".nav-item").eq(1).should("contain", "CONFORMANCE");
cy.get(".nav-item").eq(2).should("contain", "PERFORMANCE");
});
it("clicking PERFORMANCE tab navigates to performance page", () => {
cy.get(".nav-item").contains("PERFORMANCE").click();
cy.url().should("include", "/performance");
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Time Usage").should("be.visible");
});
it("clicking CONFORMANCE tab navigates to conformance page", () => {
cy.get(".nav-item").contains("CONFORMANCE").click();
cy.url().should("include", "/conformance");
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Rule Settings").should("be.visible");
});
it("shows back arrow to return to Files", () => {
cy.get("#backPage").should("exist");
cy.get("#backPage").should("have.attr", "href", "/files");
});
});
describe("navigating from Performance page", () => {
beforeEach(() => {
cy.visit("/discover/log/297310264/performance");
cy.get(".chart-container, canvas").should("exist");
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
});
it("clicking MAP tab navigates to map page", () => {
cy.get(".nav-item").contains("MAP").click();
cy.url().should("include", "/map");
cy.get("#cy").should("exist");
});
it("clicking CONFORMANCE tab navigates to conformance page", () => {
cy.get(".nav-item").contains("CONFORMANCE").click();
cy.url().should("include", "/conformance");
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Rule Settings").should("be.visible");
});
});
describe("navigating from Conformance page", () => {
beforeEach(() => {
cy.visit("/discover/log/297310264/conformance");
cy.get(".p-radiobutton, [class*=conformance]").first().should("exist");
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
});
it("clicking MAP tab navigates to map page", () => {
cy.get(".nav-item").contains("MAP").click();
cy.url().should("include", "/map");
cy.get("#cy").should("exist");
});
it("clicking PERFORMANCE tab navigates to performance page", () => {
cy.get(".nav-item").contains("PERFORMANCE").click();
cy.url().should("include", "/performance");
cy.get(String.raw`.z-\[9999\]`, { timeout: 10000 }).should("not.exist");
cy.contains("Time Usage").should("be.visible");
});
});
});

View File

@@ -1,126 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Edge Cases", () => {
describe("Empty states", () => {
it("files page handles empty file list", () => {
loginWithFixtures();
// Visit any page first to load the app and MSW
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
// Override files endpoint with empty array via MSW
cy.window().then((win) => {
const { http, HttpResponse } = win.__msw__;
win.__mswWorker__.use(
http.get("/api/files", () => HttpResponse.json([])),
);
});
// Revisit to trigger the new empty response
cy.visit("/files");
// Table should exist but have no file data
cy.get("table").should("exist");
cy.contains("sample-process.xes").should("not.exist");
});
it("account admin handles empty user list", () => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
// Override users endpoint with empty array via MSW
cy.window().then((win) => {
const { http, HttpResponse } = win.__msw__;
win.__mswWorker__.use(
http.get("/api/users", () => HttpResponse.json([])),
);
});
cy.visit("/account-admin");
// Create New button should exist even with no users
cy.get("#create_new_acct_btn").should("exist");
cy.contains("Test Admin").should("not.exist");
});
it("unauthenticated user is redirected to login", () => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
// Override my-account to return 401
cy.window().then((win) => {
const { http, HttpResponse } = win.__msw__;
win.__mswWorker__.use(
http.get("/api/my-account", () =>
new HttpResponse(null, { status: 401 }),
),
);
});
// Clear cookies to simulate logged out
cy.clearCookies();
cy.visit("/files");
cy.url().should("include", "/login");
});
it("unauthenticated user cannot access account-admin", () => {
cy.visit("/account-admin");
cy.url().should("include", "/login");
});
it("unauthenticated user cannot access my-account", () => {
cy.visit("/my-account");
cy.url().should("include", "/login");
});
});
describe("Login validation", () => {
it("shows error on failed login", () => {
// Visit login page first to load the app
cy.visit("/login");
cy.get("#login_btn_main_btn").should("exist");
// Override token endpoint to return 401
cy.window().then((win) => {
const { http, HttpResponse } = win.__msw__;
win.__mswWorker__.use(
http.post("/api/oauth/token", () =>
HttpResponse.json(
{ detail: "Invalid credentials" },
{ status: 401 },
),
),
);
});
cy.get("#account").type("wronguser");
cy.get("#password").type("wrongpass");
cy.get("#login_btn_main_btn").click();
cy.url().should("include", "/login");
});
it("confirm stays disabled with only account field filled", () => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
cy.contains("button", "Create New").click();
cy.get("#input_account_field").type("onlyaccount");
cy.contains("button", "Confirm").should("be.disabled");
});
it("confirm stays disabled with only name field filled", () => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
cy.contains("button", "Create New").click();
cy.get("#input_name_field").type("onlyname");
cy.contains("button", "Confirm").should("be.disabled");
});
it("confirm stays disabled with only password field filled", () => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
cy.contains("button", "Create New").click();
cy.get("#input_first_pwd").type("onlypassword");
cy.contains("button", "Confirm").should("be.disabled");
});
});
});

View File

@@ -1,74 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("File Operations", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
});
it("file list table has sortable columns", () => {
// Check that table headers exist with expected columns
cy.get("table").within(() => {
cy.contains("th", "Name").should("exist");
cy.contains("th", "Dependency").should("exist");
cy.contains("th", "File Type").should("exist");
cy.contains("th", "Owner").should("exist");
cy.contains("th", "Last Update").should("exist");
});
});
it("clicking column header sorts the table", () => {
// Click "Name" header to sort
cy.contains("th", "Name").click();
// After sorting, table should still have data
cy.get("table tbody tr").should("have.length.greaterThan", 0);
});
it("table rows show file data from fixture", () => {
cy.get("table tbody").within(() => {
cy.contains("sample-process.xes").should("exist");
cy.contains("filtered-sample").should("exist");
cy.contains("production-log.csv").should("exist");
});
});
it("table shows owner names", () => {
cy.get("table tbody").within(() => {
cy.contains("Test Admin").should("exist");
cy.contains("Alice Wang").should("exist");
});
});
it("table shows file types", () => {
cy.get("table tbody").within(() => {
cy.contains("log").should("exist");
});
});
it("right-click on file row shows context menu", () => {
// PrimeVue DataTable with contextmenu
cy.get("table tbody tr").first().rightclick();
// Context menu behavior depends on implementation
// Just verify the right-click doesn't break anything
cy.get("table tbody tr").should("have.length.greaterThan", 0);
});
it("grid view shows file cards", () => {
// Switch to grid view
cy.get("svg").parent("li.cursor-pointer").last().click();
// Grid cards should be visible
cy.get("li[title]").should("have.length.greaterThan", 0);
});
it("Import button opens upload modal", () => {
cy.get("#import_btn").click();
// Upload modal should appear
cy.get("#import_btn").should("exist");
});
});

View File

@@ -1,60 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Files Page", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/files");
});
it("displays the file list after login", () => {
cy.contains("sample-process.xes").should("exist");
cy.contains("h2", "All Files").should("exist");
// Should display file names from fixture
cy.contains("sample-process.xes").should("exist");
cy.contains("filtered-sample").should("exist");
cy.contains("production-log.csv").should("exist");
});
it("shows Recently Used section", () => {
cy.contains("sample-process.xes").should("exist");
cy.contains("h2", "Recently Used").should("exist");
});
it("switches to DISCOVER tab", () => {
cy.contains("sample-process.xes").should("exist");
cy.contains(".nav-item", "DISCOVER").click();
// DISCOVER tab shows filtered file types
cy.contains("h2", "All Files").should("exist");
});
it("switches to COMPARE tab and shows drag zones", () => {
cy.contains("sample-process.xes").should("exist");
cy.contains(".nav-item", "COMPARE").click();
cy.contains("Performance Comparison").should("exist");
cy.contains("Drag and drop a file here").should("exist");
});
it("shows Import button on FILES tab", () => {
cy.contains("sample-process.xes").should("exist");
cy.get("#import_btn").should("contain", "Import");
});
it("can switch between list and grid view", () => {
cy.contains("sample-process.xes").should("exist");
// DataTable (list view) should be visible by default
cy.get("table").should("exist");
});
it("double-click file navigates to discover page", () => {
cy.contains("sample-process.xes").should("exist");
// Double-click the first file row in the table
// The actual route depends on file type (log→map, log-check→conformance, etc.)
cy.get("table tbody tr").first().dblclick();
cy.url().should("include", "/discover");
});
});

View File

@@ -1,49 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Files Page - COMPARE Tab", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
// Switch to COMPARE tab
cy.contains("li", "COMPARE").click();
});
it("shows Performance Comparison heading", () => {
cy.contains("h2", "Performance Comparison").should("be.visible");
});
it("shows two drag-and-drop slots", () => {
cy.get("#primaryDragCard").should("exist");
cy.get("#secondaryDragCard").should("exist");
});
it("drag slots show placeholder text", () => {
cy.get("#primaryDragCard").should("contain", "Drag and drop a file here");
cy.get("#secondaryDragCard").should("contain", "Drag and drop a file here");
});
it("Compare button is disabled when no files are dragged", () => {
cy.contains("button", "Compare").should("be.disabled");
});
it("shows sorting dropdown", () => {
cy.get(".p-select").should("exist");
});
it("grid cards display file names", () => {
cy.get("#compareGridCards").should("exist");
cy.get("#compareGridCards li").should("have.length.greaterThan", 0);
});
it("clicking sorting dropdown shows sort options", () => {
cy.get(".p-select").click();
cy.get(".p-select-list").should("be.visible");
cy.contains(".p-select-option", "By File Name").should("exist");
});
});

View File

@@ -1,69 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Files to Discover Entry Flow", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
});
describe("double-click table row to enter Discover", () => {
it("double-click log file navigates to Map page", () => {
// Target the Name column (has class .fileName) to avoid matching Dependency column
cy.contains("td.fileName", "sample-process.xes").parent("tr").dblclick();
cy.url().should("include", "/discover/log/1/map");
cy.get("#cy").should("exist");
});
it("double-click filter file navigates to Map page", () => {
cy.contains("td.fileName", "filtered-sample").parent("tr").dblclick();
cy.url().should("include", "/discover/filter/10/map");
cy.get("#cy").should("exist");
});
});
describe("double-click grid card to enter Discover", () => {
beforeEach(() => {
// Switch to grid view
cy.get("svg").parent("li.cursor-pointer").last().click();
});
it("double-click log file grid card navigates to Map page", () => {
// Use last() to target the All Files grid section (not Recently Used)
cy.get('li[title="sample-process.xes"]').last().dblclick();
cy.url().should("include", "/discover/log/1/map");
cy.get("#cy").should("exist");
});
});
describe("DISCOVER tab filters files", () => {
it("clicking DISCOVER tab shows only Log, Filter, and Rule files", () => {
cy.get(".nav-item").contains("DISCOVER").click();
cy.contains("td.fileName", "sample-process.xes").should("exist");
cy.contains("td.fileName", "filtered-sample").should("exist");
cy.contains("td.fileName", "conformance-check-1").should("exist");
});
});
describe("Navbar state after entering Discover", () => {
it("shows DISCOVER heading and tabs after entering from Files", () => {
cy.contains("td.fileName", "sample-process.xes").parent("tr").dblclick();
cy.url().should("include", "/discover/");
cy.get("#nav_bar").contains("DISCOVER").should("be.visible");
cy.get(".nav-item").contains("MAP").should("exist");
cy.get(".nav-item").contains("CONFORMANCE").should("exist");
cy.get(".nav-item").contains("PERFORMANCE").should("exist");
});
it("shows back arrow pointing to /files", () => {
cy.contains("td.fileName", "sample-process.xes").parent("tr").dblclick();
cy.url().should("include", "/discover/");
cy.get("#backPage").should("have.attr", "href", "/files");
});
});
});

View File

@@ -1,13 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
},
"include": [
"./**/*",
"../support/**/*",
"/node_modules/cypress",
"cypress/**/*.js",],
"experimentalShadowDomSupport": true
}

View File

@@ -1,82 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { setupApiIntercepts } from "../support/intercept";
describe("Login Flow", () => {
beforeEach(() => {
setupApiIntercepts();
});
it("renders the login form", () => {
cy.visit("/login");
cy.get("h2").should("contain", "LOGIN");
cy.get("#account").should("exist");
cy.get("#password").should("exist");
cy.get("#login_btn_main_btn").should("be.disabled");
});
it("login button is disabled when fields are empty", () => {
cy.visit("/login");
cy.get("#login_btn_main_btn").should("be.disabled");
// Only username filled — still disabled
cy.get("#account").type("testuser");
cy.get("#login_btn_main_btn").should("be.disabled");
});
it("login button enables when both fields are filled", () => {
cy.visit("/login");
cy.get("#account").type("testadmin");
cy.get("#password").type("password123");
cy.get("#login_btn_main_btn").should("not.be.disabled");
});
it("successful login redirects to /files", () => {
cy.visit("/login");
cy.get("#account").type("testadmin");
cy.get("#password").type("password123");
cy.get("#login_btn_main_btn").click();
cy.url().should("include", "/files");
});
it("failed login shows error message", () => {
// Visit login first to load app + MSW
cy.visit("/login");
cy.get("#login_btn_main_btn").should("exist");
// Override the token endpoint to return 401 via MSW
cy.window().then((win) => {
const { http, HttpResponse } = win.__msw__;
win.__mswWorker__.use(
http.post("/api/oauth/token", () =>
HttpResponse.json(
{ detail: "Incorrect username or password" },
{ status: 401 },
)),
);
});
cy.get("#account").type("wronguser");
cy.get("#password").type("wrongpass");
cy.get("#login_btn_main_btn").click();
cy.contains("Incorrect account or password").should("be.visible");
});
it("toggles password visibility", () => {
cy.visit("/login");
cy.get("#password").type("secret123");
cy.get("#password").should("have.attr", "type", "password");
// Click the eye icon to show password
cy.get('label[for="passwordt"] span.cursor-pointer').click();
cy.get("#password").should("have.attr", "type", "text");
// Click again to hide
cy.get('label[for="passwordt"] span.cursor-pointer').click();
cy.get("#password").should("have.attr", "type", "password");
});
});

View File

@@ -1,67 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Logout Flow", () => {
beforeEach(() => {
loginWithFixtures();
});
it("shows account menu when head icon is clicked", () => {
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
// Click the head icon to open account menu
cy.get("#acct_mgmt_button").click();
cy.get("#account_menu").should("be.visible");
cy.get("#greeting").should("contain", "Test Admin");
});
it("account menu shows admin management link for admin user", () => {
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
cy.get("#acct_mgmt_button").click();
cy.get("#account_menu").should("be.visible");
// Admin user should see account management option
cy.get("#btn_acct_mgmt").should("exist");
});
it("account menu has logout button", () => {
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
cy.get("#acct_mgmt_button").click();
cy.get("#btn_logout_in_menu").should("exist");
});
it("clicking My Account navigates to /my-account", () => {
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
cy.get("#acct_mgmt_button").click();
cy.get("#btn_mang_ur_acct").click();
cy.url().should("include", "/my-account");
});
it("clicking Account Management navigates to /account-admin", () => {
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
cy.get("#acct_mgmt_button").click();
cy.get("#btn_acct_mgmt").click();
cy.url().should("include", "/account-admin");
});
it("logout redirects to login page", () => {
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
cy.get("#acct_mgmt_button").click();
cy.get("#btn_logout_in_menu").click();
cy.url().should("include", "/login");
});
});

View File

@@ -1,73 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("My Account Page", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/my-account");
cy.contains("Test Admin").should("exist");
});
it("displays user name heading", () => {
cy.get("#general_acct_info_user_name").should("exist");
cy.get("#general_acct_info_user_name").should("contain", "Test Admin");
});
it("shows Admin badge for admin user", () => {
cy.contains("Admin").should("exist");
});
it("shows visit count info", () => {
cy.get("#general_account_visit_info").should("exist");
cy.get("#general_account_visit_info").should("contain", "Total visits");
});
it("displays account username (read-only)", () => {
cy.contains("Test Admin").should("exist");
});
it("shows Edit button for name field", () => {
cy.contains("button", "Edit").should("exist");
});
it("clicking Edit shows input field and Save/Cancel buttons", () => {
cy.contains("button", "Edit").first().click();
cy.get("#input_name_field").should("exist");
cy.contains("button", "Save").should("exist");
cy.contains("button", "Cancel").should("exist");
});
it("clicking Cancel reverts name field to read-only", () => {
cy.contains("button", "Edit").first().click();
cy.get("#input_name_field").should("exist");
cy.contains("button", "Cancel").click();
cy.get("#input_name_field").should("not.exist");
});
it("shows Reset button for password field", () => {
cy.contains("button", "Reset").should("exist");
});
it("clicking Reset shows password input and Save/Cancel", () => {
cy.contains("button", "Reset").click();
cy.get('input[type="password"]').should("exist");
cy.contains("button", "Save").should("exist");
cy.contains("button", "Cancel").should("exist");
});
it("clicking Cancel on password field hides the input", () => {
cy.contains("button", "Reset").click();
cy.get('input[type="password"]').should("exist");
// The Cancel button for password is the second one
cy.get(".cancel-btn").click();
cy.get('input[type="password"]').should("not.exist");
});
it("shows Session section", () => {
cy.contains("Session").should("exist");
});
});

View File

@@ -1,62 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures, setupApiIntercepts } from "../support/intercept";
describe("Navigation and Routing", () => {
it("redirects / to /files when logged in", () => {
loginWithFixtures();
cy.visit("/");
cy.url().should("include", "/files");
});
it("shows 404 page for unknown routes", () => {
loginWithFixtures();
cy.visit("/nonexistent-page");
cy.contains("404").should("exist");
});
it("navbar shows correct view name", () => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
cy.get("#nav_bar").should("exist");
cy.get("#nav_bar h2").should("contain", "FILES");
});
it("navbar shows back arrow on non-files pages", () => {
loginWithFixtures();
cy.visit("/discover/log/1/map");
// Back arrow should be visible on discover pages
cy.get("#backPage").should("exist");
});
it("navbar tabs are clickable on discover page", () => {
loginWithFixtures();
cy.visit("/discover/log/1/map");
// Discover navbar should show MAP, CONFORMANCE, PERFORMANCE tabs
cy.contains(".nav-item", "MAP").should("exist");
cy.contains(".nav-item", "CONFORMANCE").should("exist");
cy.contains(".nav-item", "PERFORMANCE").should("exist");
// Click CONFORMANCE tab
cy.contains(".nav-item", "CONFORMANCE").click();
cy.url().should("include", "/conformance");
// Click PERFORMANCE tab
cy.contains(".nav-item", "PERFORMANCE").click();
cy.url().should("include", "/performance");
// Click MAP tab to go back
cy.contains(".nav-item", "MAP").click();
cy.url().should("include", "/map");
});
it("login page is accessible at /login", () => {
setupApiIntercepts();
cy.visit("/login");
cy.get("h2").should("contain", "LOGIN");
});
});

View File

@@ -1,36 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("404 Not Found Page", () => {
it("displays 404 page for non-existent route", () => {
loginWithFixtures();
cy.visit("/this-page-does-not-exist");
cy.contains("404").should("be.visible");
cy.contains("The page you are looking for does not exist.").should(
"be.visible",
);
});
it("has a link back to Files page", () => {
loginWithFixtures();
cy.visit("/some/random/path");
cy.contains("a", "Go to Files")
.should("be.visible")
.should("have.attr", "href", "/files");
});
it("displays 404 for unauthenticated user on invalid route", () => {
cy.visit("/not-a-real-page");
cy.url().then((url) => {
if (url.includes("/login")) {
cy.url().should("include", "/login");
} else {
cy.contains("404").should("be.visible");
}
});
});
});

View File

@@ -1,38 +0,0 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/06/03
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("Discover page navigation tabs", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
});
it("Double-clicking a log file enters the MAP page.", () => {
cy.contains("td.fileName", "sample-process.xes").dblclick();
cy.url().should("include", "map");
// MAP tab should exist in the navbar
cy.contains(".nav-item", "MAP").should("exist");
});
it("Clicking CONFORMANCE tab switches active page.", () => {
cy.contains("td.fileName", "sample-process.xes").dblclick();
cy.url().should("include", "map");
cy.contains(".nav-item", "CONFORMANCE").click();
cy.url().should("include", "conformance");
cy.contains(".nav-item", "CONFORMANCE").should("have.class", "active");
});
it("Clicking PERFORMANCE tab switches active page.", () => {
cy.contains("td.fileName", "sample-process.xes").dblclick();
cy.url().should("include", "map");
cy.contains(".nav-item", "PERFORMANCE").click();
cy.url().should("include", "performance");
cy.contains(".nav-item", "PERFORMANCE").should("have.class", "active");
});
});

View File

@@ -1,64 +0,0 @@
// The Lucia project.
// Copyright 2024-2026 DSP, inc. All rights reserved.
// Authors:
// cindy.chang@dsp.im (Cindy Chang), 2024/06/11
// imacat.yang@dsp.im (imacat), 2026/03/05
import { setupApiIntercepts } from "../support/intercept";
describe("Paste URL login redirect", () => {
it("After login with return-to param, redirects to the remembered page", () => {
setupApiIntercepts();
// Visit login page with a return-to query param (base64-encoded URL)
const targetUrl =
"http://localhost:4173/discover/conformance/log/1/conformance";
const encodedUrl = btoa(targetUrl);
cy.visit(`/login?return-to=${encodedUrl}`);
// Fill in login form
cy.get("#account").type("testadmin");
cy.get("#password").type("password123");
cy.get("form").submit();
// After login, the app should attempt to redirect to the return-to URL.
// Since window.location.href is used (not router.push), we verify the
// login form disappears and the token cookie is set.
cy.getCookie("luciaToken").should("exist");
});
it("Login without return-to param redirects to /files", () => {
setupApiIntercepts();
cy.visit("/login");
cy.get("#account").type("testadmin");
cy.get("#password").type("password123");
cy.get("form").submit();
cy.url().should("include", "/files");
});
it("Unauthenticated user cannot access inner pages", () => {
// Visit login first to load the app + MSW
cy.visit("/login");
cy.get("#login_btn_main_btn").should("exist");
// Override my-account to return 401 (simulate logged-out state) via MSW
cy.window().then((win) => {
const { http, HttpResponse } = win.__msw__;
win.__mswWorker__.use(
http.get("/api/my-account", () =>
HttpResponse.json(
{ detail: "Not authenticated" },
{ status: 401 },
)),
);
});
cy.visit("/files");
// Should be redirected to login page
cy.url().should("include", "/login");
cy.get("#account").should("exist");
cy.get("#password").should("exist");
});
});

View File

@@ -1,116 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
import { loginWithFixtures } from "../support/intercept";
describe("SweetAlert2 Modals", () => {
describe("File Context Menu - Rename", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
});
it("right-click on table row shows context menu with Rename", () => {
cy.get("table tbody tr").first().rightclick();
cy.contains("Rename").should("be.visible");
});
it("right-click context menu shows Download option", () => {
cy.get("table tbody tr").first().rightclick();
cy.contains("Download").should("be.visible");
});
it("right-click context menu shows Delete option", () => {
cy.get("table tbody tr").first().rightclick();
cy.contains("Delete").should("be.visible");
});
it("clicking Rename opens SweetAlert rename dialog", () => {
cy.get("table tbody tr").first().rightclick();
cy.contains("Rename").click();
// SweetAlert popup should appear with RENAME title
cy.get(".swal2-popup").should("be.visible");
cy.get(".swal2-title").should("contain", "RENAME");
cy.get(".swal2-input").should("exist");
});
it("rename dialog has pre-filled file name", () => {
cy.get("table tbody tr").first().rightclick();
cy.contains("Rename").click();
cy.get(".swal2-input").should("not.have.value", "");
});
it("rename dialog can be cancelled", () => {
cy.get("table tbody tr").first().rightclick();
cy.contains("Rename").click();
cy.get(".swal2-popup").should("be.visible");
cy.get(".swal2-cancel").click();
cy.get(".swal2-popup").should("not.exist");
});
it("clicking Delete opens SweetAlert delete confirmation", () => {
cy.get("table tbody tr").first().rightclick();
cy.contains("Delete").click();
// SweetAlert popup should appear with CONFIRM DELETION
cy.get(".swal2-popup").should("be.visible");
cy.get(".swal2-title").should("contain", "CONFIRM DELETION");
});
it("delete confirmation shows file name", () => {
cy.get("table tbody tr").first().rightclick();
cy.contains("Delete").click();
cy.get(".swal2-popup").should("be.visible");
cy.get(".swal2-html-container").should("contain", "delete");
});
it("delete confirmation can be cancelled", () => {
cy.get("table tbody tr").first().rightclick();
cy.contains("Delete").click();
cy.get(".swal2-popup").should("be.visible");
cy.get(".swal2-cancel").click();
cy.get(".swal2-popup").should("not.exist");
});
});
describe("File Context Menu on Grid View", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/files");
cy.contains("sample-process.xes").should("exist");
// Switch to grid view
cy.get("svg").parent("li.cursor-pointer").last().click();
});
it("right-click on grid card shows context menu", () => {
cy.get("li[title]").first().rightclick();
cy.contains("Rename").should("be.visible");
cy.contains("Delete").should("be.visible");
});
it("grid card rename opens SweetAlert dialog", () => {
cy.get("li[title]").first().rightclick();
cy.contains("Rename").click();
cy.get(".swal2-popup").should("be.visible");
cy.get(".swal2-title").should("contain", "RENAME");
});
});
describe("Account Delete Confirmation", () => {
beforeEach(() => {
loginWithFixtures();
cy.visit("/account-admin");
cy.contains("Test Admin").should("exist");
});
it("delete confirmation Yes button triggers delete API", () => {
cy.get(".delete-account").first().click();
cy.get("#modal_container").should("be.visible");
cy.get("#sure_to_delete_acct_btn").click();
// Modal should close after deletion
cy.get("#modal_container").should("not.exist");
});
});
});

View File

@@ -1,5 +0,0 @@
時間,案號,居住區域,學區,事件名稱,事件序號,狀態 ,時段,溫度,數量,未知,完成,預期時間
2022/05/13 09:25:21,案一,63,富山,事件甲,事件一,Start,早上,95,27,,TRUE,2022/5/14 09:25:21
2022/05/13 09:25:21,案一,,,事件甲,事件一,Complete,中午,135,442,,false,2022/5/14 09:25:21
2022/05/13 09:30:01,案一,,仁德,事件乙,事件四,Start,中午,110.6,-6, ,,2022/5/14 09:30:01
2022/05/13 09:30:01,案一,,,事件乙,事件四,Complete,晚上,-65,4,,true ,2022/5/14 09:30:01
1 時間 案號 居住區域 學區 事件名稱 事件序號 狀態 時段 溫度 數量 未知 完成 預期時間
2 2022/05/13 09:25:21 案一 63 富山 事件甲 事件一 Start 早上 95 27 TRUE 2022/5/14 09:25:21
3 2022/05/13 09:25:21 案一 事件甲 事件一 Complete 中午 135 442 false 2022/5/14 09:25:21
4 2022/05/13 09:30:01 案一 仁德 事件乙 事件四 Start 中午 110.6 -6 2022/5/14 09:30:01
5 2022/05/13 09:30:01 案一 事件乙 事件四 Complete 晚上 -65 4 true 2022/5/14 09:30:01

Binary file not shown.
1 timestamp,case id,name,instance,status
2 2022/05/13 09:25:21,編號1,步驟a,步驟a#1,start
3 2022/05/13 09:25:21,編號1,步驟a,步驟a#1,complete
4 2022/05/13 09:30:01,編號1,步驟b,步驟b#1,start
5 2022/05/13 09:30:01,編號1,步驟b,ŸSze©%ï0†¤SzŠÇÔ6MíÍρθ ¥‰òºˆ(ä–{.bÁÖwÈN�¥Å÷8ôd¬'›„ £<ŸƒÛ°àRž`\g8u/)!ëÂ˶þÀ§æn{Z\¥DRðíÑdÈ

View File

@@ -1 +0,0 @@
timestamp,case id,name,instance,status
1 timestamp case id name instance status

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,9 +0,0 @@
timestamp,case id,name,status
2022/05/13 09:25:21,c1,a,1,start
2022/05/13 09:25:21,c1,a,1,complete
2022/05/13 09:30:01,c1,b,2,start
2022/05/13 09:30:01,c1,b,2,complete
2022/05/13 09:48:33,c2,a,6,start
2022/05/13 09:48:33,c2,a,6,complete
2022/05/13 09:54:27,c2,c,7,start
2022/05/13 09:54:27,c2,c,7,complete
1 timestamp,case id,name,status
2 2022/05/13 09:25:21,c1,a,1,start
3 2022/05/13 09:25:21,c1,a,1,complete
4 2022/05/13 09:30:01,c1,b,2,start
5 2022/05/13 09:30:01,c1,b,2,complete
6 2022/05/13 09:48:33,c2,a,6,start
7 2022/05/13 09:48:33,c2,a,6,complete
8 2022/05/13 09:54:27,c2,c,7,start
9 2022/05/13 09:54:27,c2,c,7,complete

View File

@@ -1,30 +0,0 @@
CaseID,Activity,Timestamp,Status,Activity_Instance
CID_1,檢傷,2023-01-12 15:32:31,start,1
CID_1,檢傷,2023-01-12 15:32:31,complete,1
CID_1,第一次醫囑,2023-01-12 15:49:01,start,2
CID_1,第一次醫囑,2023-01-12 15:49:01,complete,2
CID_1,出院,2023-01-13 03:32:00,start,3
CID_1,出院,2023-01-13 03:32:00,complete,3
CID_2,檢傷,2023-07-26 08:44:17,start,4
CID_2,檢傷,2023-07-26 08:44:17,complete,4
CID_2,第一次醫囑,2023-07-26 08:48:05,start,5
CID_2,第一次醫囑,2023-07-26 08:48:05,complete,5
CID_2,出院,2023-07-26 17:00:49,start,6
CID_2,出院,2023-07-26 17:00:49,complete,6
CID_3,檢傷,2023-11-27 06:20:48,start,7
CID_3,檢傷,2023-11-27 06:20:48,complete,7
CID_3,第一次醫囑,2023-11-27 06:40:30,start,8
CID_3,第一次醫囑,2023-11-27 06:40:30,complete,8
CID_3,出院,2023-11-27 07:21:53,start,9
CID_3,出院,2023-11-27 07:21:53,complete,9
CID_4,檢傷,2023-11-01 01:20:19,start,10
CID_4,檢傷,2023-11-01 01:20:19,complete,10
CID_4,第一次醫囑,2023-11-01 01:34:54,start,11
CID_4,第一次醫囑,2023-11-01 01:34:54,complete,11
CID_4,住院,2023-11-02 06:36:36,start,12
CID_4,住院,2023-11-10 02:35:39,complete,12
CID_4,出院,2023-11-10 02:35:39,start,13
CID_4,出院,2023-11-10 02:35:39,complete,13
CID_5,檢傷,2023-07-13 02:49:36,start,14
CID_5,檢傷,2023-07-13 02:49:36,complete,14
CID_5,第一次醫囑,2023-07-13 03:07:01,start,15
1 CaseID Activity Timestamp Status Activity_Instance
2 CID_1 檢傷 2023-01-12 15:32:31 start 1
3 CID_1 檢傷 2023-01-12 15:32:31 complete 1
4 CID_1 第一次醫囑 2023-01-12 15:49:01 start 2
5 CID_1 第一次醫囑 2023-01-12 15:49:01 complete 2
6 CID_1 出院 2023-01-13 03:32:00 start 3
7 CID_1 出院 2023-01-13 03:32:00 complete 3
8 CID_2 檢傷 2023-07-26 08:44:17 start 4
9 CID_2 檢傷 2023-07-26 08:44:17 complete 4
10 CID_2 第一次醫囑 2023-07-26 08:48:05 start 5
11 CID_2 第一次醫囑 2023-07-26 08:48:05 complete 5
12 CID_2 出院 2023-07-26 17:00:49 start 6
13 CID_2 出院 2023-07-26 17:00:49 complete 6
14 CID_3 檢傷 2023-11-27 06:20:48 start 7
15 CID_3 檢傷 2023-11-27 06:20:48 complete 7
16 CID_3 第一次醫囑 2023-11-27 06:40:30 start 8
17 CID_3 第一次醫囑 2023-11-27 06:40:30 complete 8
18 CID_3 出院 2023-11-27 07:21:53 start 9
19 CID_3 出院 2023-11-27 07:21:53 complete 9
20 CID_4 檢傷 2023-11-01 01:20:19 start 10
21 CID_4 檢傷 2023-11-01 01:20:19 complete 10
22 CID_4 第一次醫囑 2023-11-01 01:34:54 start 11
23 CID_4 第一次醫囑 2023-11-01 01:34:54 complete 11
24 CID_4 住院 2023-11-02 06:36:36 start 12
25 CID_4 住院 2023-11-10 02:35:39 complete 12
26 CID_4 出院 2023-11-10 02:35:39 start 13
27 CID_4 出院 2023-11-10 02:35:39 complete 13
28 CID_5 檢傷 2023-07-13 02:49:36 start 14
29 CID_5 檢傷 2023-07-13 02:49:36 complete 14
30 CID_5 第一次醫囑 2023-07-13 03:07:01 start 15

View File

@@ -1,9 +0,0 @@
timestamp,case id,name,instance,status
2022/05/13 09:25:21,c1,a,1,start
2022/05/13 09:25:21,c1,a,1,
2022/05/13 09:30:01,c1,b,2,begin
2022/05/13 09:30:01,c1,b,,complete
2022/05/13 09:48:33,,,6,start
2022;05;13 09;48;33,c2,a,6,complete
2022/05/13 09:54:27,c2,c,7,start
,c2,c,7,complete
1 timestamp case id name instance status
2 2022/05/13 09:25:21 c1 a 1 start
3 2022/05/13 09:25:21 c1 a 1
4 2022/05/13 09:30:01 c1 b 2 begin
5 2022/05/13 09:30:01 c1 b complete
6 2022/05/13 09:48:33 6 start
7 2022;05;13 09;48;33 c2 a 6 complete
8 2022/05/13 09:54:27 c2 c 7 start
9 c2 c 7 complete

View File

@@ -1,4 +0,0 @@
{
"username": " test ",
"password": " test "
}

View File

@@ -1,39 +0,0 @@
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/01/31
// imacat.yang@dsp.im (imacat), 2026/03/06
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
// -- This is a parent command --
import "@4tw/cypress-drag-drop";
/**
* Sets authentication cookies to simulate a logged-in user.
*
* @returns {void}
*/
Cypress.Commands.add("login", () => {
cy.setCookie("luciaToken", "fake-access-token-for-testing");
cy.setCookie("isLuciaLoggedIn", "true");
});
// Usage: cy.login()
// -- This is a child command --
// Click a blank area to close an opened modal: cy.closePopup()
/**
* Closes the active popup by clicking the top-left area of the page.
*
* @returns {void}
*/
Cypress.Commands.add("closePopup", () => {
// Trigger a forced click to close modal overlays consistently.
cy.get("body").click({ position: "topLeft" });
});

View File

@@ -1,26 +0,0 @@
// The Lucia project.
// Copyright 2023-2026 DSP, inc. All rights reserved.
// Authors:
// chiayin.kuo@dsp.im (chiayin), 2023/01/31
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import "./commands";
// Alternatively you can use CommonJS syntax:
// require('./commands')
require("cypress-xpath"); // Enables xpath helpers used in pointer event checks.

View File

@@ -1,21 +0,0 @@
// The Lucia project.
// Copyright 2026-2026 DSP, inc. All rights reserved.
// Authors:
// imacat.yang@dsp.im (imacat), 2026/03/05
/**
* API mocking is now handled by MSW (Mock Service Worker).
* This function is kept for backward compatibility but does nothing.
*/
export function setupApiIntercepts() {
// MSW handles all API interception via service worker.
}
/**
* Sets the luciaToken cookie and isLuciaLoggedIn cookie to simulate
* a logged-in state. API interception is handled by MSW.
*/
export function loginWithFixtures() {
cy.setCookie("luciaToken", "fake-access-token-for-testing");
cy.setCookie("isLuciaLoggedIn", "true");
}

3271
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,9 @@
"preview": "vite preview",
"test": "vitest",
"coverage": "vitest run --coverage",
"cy:run": "cypress run",
"test:unit": "vitest --environment jsdom",
"test:e2e": "start-server-and-test 'vite preview --port 4173' :4173 'cypress run --e2e'",
"test:e2e:dev": "start-server-and-test 'vite dev --port 4173' :4173 'cypress open --e2e'",
"test:unit": "vitest run",
"test:e2e": "playwright test --config tests/e2e/playwright.config.ts",
"test:e2e:ui": "playwright test --config tests/e2e/playwright.config.ts --ui",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs",
"lint:fix": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix",
"docs": "typedoc"
@@ -49,7 +48,6 @@
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@4tw/cypress-drag-drop": "^2.3.1",
"@eslint/js": "^10.0.1",
"@playwright/test": "^1.58.2",
"@types/cytoscape": "^3.21.9",
@@ -60,17 +58,13 @@
"@vue/eslint-config-prettier": "^10.2.0",
"@vue/test-utils": "^2.4.6",
"chartjs-plugin-dragdata": "^2.3.1",
"cypress": "^15.11.0",
"cypress-xpath": "^2.0.1",
"eslint": "^10.0.2",
"eslint-plugin-cypress": "^6.1.0",
"eslint-plugin-vue": "^10.8.0",
"jsdom": "^28.1.0",
"msw": "^2.12.14",
"postcss": "^8.5.8",
"prettier": "^3.8.1",
"sass": "^1.97.3",
"start-server-and-test": "^2.1.5",
"tailwindcss": "^4.2.1",
"ts-node": "^10.9.2",
"typedoc": "^0.28.17",