mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2026-01-01 18:47:20 +01:00
- Move upgrade-verification.spec.ts from test/e2e/ to test/upgrade/ - This prevents the test from running during normal E2E CI runs - The upgrade test is only meant for the upgrade-test workflow - Update workflow and documentation to reflect new location Co-authored-by: katosdev <7927609+katosdev@users.noreply.github.com>
419 lines
14 KiB
TypeScript
419 lines
14 KiB
TypeScript
/**
|
|
* HomeBox Upgrade Verification Tests
|
|
*
|
|
* NOTE: These tests are ONLY meant to run in the upgrade-test workflow.
|
|
* They require test data to be pre-created by the create-test-data.sh script.
|
|
* These tests are stored in test/upgrade/ (not test/e2e/) to prevent them
|
|
* from running during normal E2E test runs.
|
|
*/
|
|
|
|
import { expect, test } from "@playwright/test";
|
|
import * as fs from "fs";
|
|
|
|
// Load test data created by the setup script
|
|
const testDataPath = process.env.TEST_DATA_FILE || "/tmp/test-users.json";
|
|
|
|
interface TestUser {
|
|
email: string;
|
|
password: string;
|
|
token: string;
|
|
group: string;
|
|
}
|
|
|
|
interface TestData {
|
|
users?: TestUser[];
|
|
locations?: Record<string, string[]>;
|
|
labels?: Record<string, string[]>;
|
|
items?: Record<string, string[]>;
|
|
notifiers?: Record<string, string[]>;
|
|
}
|
|
|
|
let testData: TestData = {};
|
|
|
|
test.beforeAll(() => {
|
|
if (fs.existsSync(testDataPath)) {
|
|
const rawData = fs.readFileSync(testDataPath, "utf-8");
|
|
testData = JSON.parse(rawData);
|
|
console.log("Loaded test data:", JSON.stringify(testData, null, 2));
|
|
} else {
|
|
console.error(`Test data file not found at ${testDataPath}`);
|
|
throw new Error("Test data file not found");
|
|
}
|
|
});
|
|
|
|
test.describe("HomeBox Upgrade Verification", () => {
|
|
test("verify all users can log in", async ({ page }) => {
|
|
// Test each user from the test data
|
|
for (const user of testData.users || []) {
|
|
await page.goto("/");
|
|
await expect(page).toHaveURL("/");
|
|
|
|
// Wait for login form to be ready
|
|
await page.waitForSelector("input[type='text']", { state: "visible" });
|
|
|
|
// Fill in login form
|
|
await page.fill("input[type='text']", user.email);
|
|
await page.fill("input[type='password']", user.password);
|
|
await page.click("button[type='submit']");
|
|
|
|
// Wait for navigation to home page
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
console.log(`✓ User ${user.email} logged in successfully`);
|
|
|
|
// Navigate back to login for next user
|
|
await page.goto("/");
|
|
await page.waitForSelector("input[type='text']", { state: "visible" });
|
|
}
|
|
});
|
|
|
|
test("verify application version is displayed", async ({ page }) => {
|
|
// Login as first user
|
|
const firstUser = testData.users?.[0];
|
|
if (!firstUser) {
|
|
throw new Error("No users found in test data");
|
|
}
|
|
|
|
await page.goto("/");
|
|
await page.fill("input[type='text']", firstUser.email);
|
|
await page.fill("input[type='password']", firstUser.password);
|
|
await page.click("button[type='submit']");
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
// Look for version in footer or about section
|
|
// The version might be in the footer or a settings page
|
|
// Check if footer exists and contains version info
|
|
const footer = page.locator("footer");
|
|
if ((await footer.count()) > 0) {
|
|
const footerText = await footer.textContent();
|
|
console.log("Footer text:", footerText);
|
|
|
|
// Version should be present in some form
|
|
// This is a basic check - the version format may vary
|
|
expect(footerText).toBeTruthy();
|
|
}
|
|
|
|
console.log("✓ Application version check complete");
|
|
});
|
|
|
|
test("verify locations are present", async ({ page }) => {
|
|
const firstUser = testData.users?.[0];
|
|
if (!firstUser) {
|
|
throw new Error("No users found in test data");
|
|
}
|
|
|
|
await page.goto("/");
|
|
await page.fill("input[type='text']", firstUser.email);
|
|
await page.fill("input[type='password']", firstUser.password);
|
|
await page.click("button[type='submit']");
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
// Wait for page to load
|
|
await page.waitForSelector("body", { state: "visible" });
|
|
|
|
// Try to find locations link in navigation
|
|
const locationsLink = page.locator("a[href*='location'], button:has-text('Locations')").first();
|
|
|
|
if ((await locationsLink.count()) > 0) {
|
|
await locationsLink.click();
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
// Check if locations are displayed
|
|
// The exact structure depends on the UI, but we should see location names
|
|
const pageContent = await page.textContent("body");
|
|
|
|
// Verify some of our test locations exist
|
|
expect(pageContent).toContain("Living Room");
|
|
console.log("✓ Locations verified");
|
|
} else {
|
|
console.log("! Could not find locations navigation - skipping detailed check");
|
|
}
|
|
});
|
|
|
|
test("verify labels are present", async ({ page }) => {
|
|
const firstUser = testData.users?.[0];
|
|
if (!firstUser) {
|
|
throw new Error("No users found in test data");
|
|
}
|
|
|
|
await page.goto("/");
|
|
await page.fill("input[type='text']", firstUser.email);
|
|
await page.fill("input[type='password']", firstUser.password);
|
|
await page.click("button[type='submit']");
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
await page.waitForSelector("body", { state: "visible" });
|
|
|
|
// Try to find labels link in navigation
|
|
const labelsLink = page.locator("a[href*='label'], button:has-text('Labels')").first();
|
|
|
|
if ((await labelsLink.count()) > 0) {
|
|
await labelsLink.click();
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const pageContent = await page.textContent("body");
|
|
|
|
// Verify some of our test labels exist
|
|
expect(pageContent).toContain("Electronics");
|
|
console.log("✓ Labels verified");
|
|
} else {
|
|
console.log("! Could not find labels navigation - skipping detailed check");
|
|
}
|
|
});
|
|
|
|
test("verify items are present", async ({ page }) => {
|
|
const firstUser = testData.users?.[0];
|
|
if (!firstUser) {
|
|
throw new Error("No users found in test data");
|
|
}
|
|
|
|
await page.goto("/");
|
|
await page.fill("input[type='text']", firstUser.email);
|
|
await page.fill("input[type='password']", firstUser.password);
|
|
await page.click("button[type='submit']");
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
await page.waitForSelector("body", { state: "visible" });
|
|
|
|
// Navigate to items list
|
|
// This might be the home page or a separate items page
|
|
const itemsLink = page.locator("a[href*='item'], button:has-text('Items')").first();
|
|
|
|
if ((await itemsLink.count()) > 0) {
|
|
await itemsLink.click();
|
|
await page.waitForLoadState("networkidle");
|
|
}
|
|
|
|
const pageContent = await page.textContent("body");
|
|
|
|
// Verify some of our test items exist
|
|
expect(pageContent).toContain("Laptop Computer");
|
|
console.log("✓ Items verified");
|
|
});
|
|
|
|
test("verify notifier is present", async ({ page }) => {
|
|
const firstUser = testData.users?.[0];
|
|
if (!firstUser) {
|
|
throw new Error("No users found in test data");
|
|
}
|
|
|
|
await page.goto("/");
|
|
await page.fill("input[type='text']", firstUser.email);
|
|
await page.fill("input[type='password']", firstUser.password);
|
|
await page.click("button[type='submit']");
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
await page.waitForSelector("body", { state: "visible" });
|
|
|
|
// Navigate to settings or profile
|
|
// Notifiers are typically in settings
|
|
const settingsLink = page.locator("a[href*='setting'], a[href*='profile'], button:has-text('Settings')").first();
|
|
|
|
if ((await settingsLink.count()) > 0) {
|
|
await settingsLink.click();
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
// Look for notifiers section
|
|
const notifiersLink = page.locator("a:has-text('Notif'), button:has-text('Notif')").first();
|
|
|
|
if ((await notifiersLink.count()) > 0) {
|
|
await notifiersLink.click();
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const pageContent = await page.textContent("body");
|
|
|
|
// Verify our test notifier exists
|
|
expect(pageContent).toContain("TESTING");
|
|
console.log("✓ Notifier verified");
|
|
} else {
|
|
console.log("! Could not find notifiers section - skipping detailed check");
|
|
}
|
|
} else {
|
|
console.log("! Could not find settings navigation - skipping notifier check");
|
|
}
|
|
});
|
|
|
|
test("verify attachments are present for items", async ({ page }) => {
|
|
const firstUser = testData.users?.[0];
|
|
if (!firstUser) {
|
|
throw new Error("No users found in test data");
|
|
}
|
|
|
|
await page.goto("/");
|
|
await page.fill("input[type='text']", firstUser.email);
|
|
await page.fill("input[type='password']", firstUser.password);
|
|
await page.click("button[type='submit']");
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
await page.waitForSelector("body", { state: "visible" });
|
|
|
|
// Search for "Laptop Computer" which should have attachments
|
|
const searchInput = page.locator("input[type='search'], input[placeholder*='Search']").first();
|
|
|
|
if ((await searchInput.count()) > 0) {
|
|
await searchInput.fill("Laptop Computer");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
// Click on the laptop item
|
|
const laptopItem = page.locator("text=Laptop Computer").first();
|
|
await laptopItem.click();
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
// Look for attachments section
|
|
const pageContent = await page.textContent("body");
|
|
|
|
// Check for attachment indicators (could be files, documents, attachments, etc.)
|
|
const hasAttachments =
|
|
pageContent?.includes("laptop-receipt") ||
|
|
pageContent?.includes("laptop-warranty") ||
|
|
pageContent?.includes("attachment") ||
|
|
pageContent?.includes("Attachment") ||
|
|
pageContent?.includes("document");
|
|
|
|
expect(hasAttachments).toBeTruthy();
|
|
console.log("✓ Attachments verified");
|
|
} else {
|
|
console.log("! Could not find search - trying direct navigation");
|
|
|
|
// Try alternative: look for items link and browse
|
|
const itemsLink = page.locator("a[href*='item'], button:has-text('Items')").first();
|
|
if ((await itemsLink.count()) > 0) {
|
|
await itemsLink.click();
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const laptopLink = page.locator("text=Laptop Computer").first();
|
|
if ((await laptopLink.count()) > 0) {
|
|
await laptopLink.click();
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const pageContent = await page.textContent("body");
|
|
const hasAttachments =
|
|
pageContent?.includes("laptop-receipt") ||
|
|
pageContent?.includes("laptop-warranty") ||
|
|
pageContent?.includes("attachment");
|
|
|
|
expect(hasAttachments).toBeTruthy();
|
|
console.log("✓ Attachments verified via direct navigation");
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
test("verify theme can be adjusted", async ({ page }) => {
|
|
const firstUser = testData.users?.[0];
|
|
if (!firstUser) {
|
|
throw new Error("No users found in test data");
|
|
}
|
|
|
|
await page.goto("/");
|
|
await page.fill("input[type='text']", firstUser.email);
|
|
await page.fill("input[type='password']", firstUser.password);
|
|
await page.click("button[type='submit']");
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
await page.waitForSelector("body", { state: "visible" });
|
|
|
|
// Look for theme toggle (usually a sun/moon icon or settings)
|
|
// Common selectors for theme toggles
|
|
const themeToggle = page
|
|
.locator(
|
|
"button[aria-label*='theme'], button[aria-label*='Theme'], " +
|
|
"button:has-text('Dark'), button:has-text('Light'), " +
|
|
"[data-theme-toggle], .theme-toggle"
|
|
)
|
|
.first();
|
|
|
|
if ((await themeToggle.count()) > 0) {
|
|
// Get initial theme state (could be from class, attribute, or computed style)
|
|
const bodyBefore = page.locator("body");
|
|
const classNameBefore = (await bodyBefore.getAttribute("class")) || "";
|
|
|
|
// Click theme toggle
|
|
await themeToggle.click();
|
|
// Wait for theme change to complete
|
|
await page.waitForTimeout(500);
|
|
|
|
// Get theme state after toggle
|
|
const classNameAfter = (await bodyBefore.getAttribute("class")) || "";
|
|
|
|
// Verify that something changed
|
|
expect(classNameBefore).not.toBe(classNameAfter);
|
|
|
|
console.log(`✓ Theme toggle working (${classNameBefore} -> ${classNameAfter})`);
|
|
} else {
|
|
// Try to find theme in settings
|
|
const settingsLink = page.locator("a[href*='setting'], a[href*='profile']").first();
|
|
|
|
if ((await settingsLink.count()) > 0) {
|
|
await settingsLink.click();
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const themeOption = page.locator("select[name*='theme'], button:has-text('Theme')").first();
|
|
|
|
if ((await themeOption.count()) > 0) {
|
|
console.log("✓ Theme settings found");
|
|
} else {
|
|
console.log("! Could not find theme toggle - feature may not be easily accessible");
|
|
}
|
|
} else {
|
|
console.log("! Could not find theme controls");
|
|
}
|
|
}
|
|
});
|
|
|
|
test("verify data counts match expectations", async ({ page }) => {
|
|
const firstUser = testData.users?.[0];
|
|
if (!firstUser) {
|
|
throw new Error("No users found in test data");
|
|
}
|
|
|
|
await page.goto("/");
|
|
await page.fill("input[type='text']", firstUser.email);
|
|
await page.fill("input[type='password']", firstUser.password);
|
|
await page.click("button[type='submit']");
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
await page.waitForSelector("body", { state: "visible" });
|
|
|
|
// Check that we have the expected number of items for group 1 (5 items)
|
|
const pageContent = await page.textContent("body");
|
|
|
|
// Look for item count indicators
|
|
// This is dependent on the UI showing counts
|
|
console.log("✓ Logged in and able to view dashboard");
|
|
|
|
// Verify at least that the page loaded and shows some content
|
|
expect(pageContent).toBeTruthy();
|
|
if (pageContent) {
|
|
expect(pageContent.length).toBeGreaterThan(100);
|
|
}
|
|
});
|
|
|
|
test("verify second group users and data isolation", async ({ page }) => {
|
|
// Login as user from group 2
|
|
const group2User = testData.users?.find(u => u.group === "2");
|
|
if (!group2User) {
|
|
console.log("! No group 2 users found - skipping isolation test");
|
|
return;
|
|
}
|
|
|
|
await page.goto("/");
|
|
await page.fill("input[type='text']", group2User.email);
|
|
await page.fill("input[type='password']", group2User.password);
|
|
await page.click("button[type='submit']");
|
|
await expect(page).toHaveURL("/home", { timeout: 10000 });
|
|
|
|
await page.waitForSelector("body", { state: "visible" });
|
|
|
|
const pageContent = await page.textContent("body");
|
|
|
|
// Verify group 2 can see their items
|
|
expect(pageContent).toContain("Monitor");
|
|
|
|
// Verify group 2 cannot see group 1 items
|
|
expect(pageContent).not.toContain("Laptop Computer");
|
|
|
|
console.log("✓ Data isolation verified between groups");
|
|
});
|
|
});
|