galaxis-po/frontend/e2e/signal-cancel.spec.ts
머니페니 2ad2f56d31 docs: add project config docs, analysis report, and e2e signal cancel test
Add CLAUDE.md and AGENTS.md for AI-assisted development guidance,
analysis report with screenshots, and Playwright-based e2e test for
signal cancellation flow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 23:18:16 +09:00

153 lines
4.7 KiB
TypeScript

import { test, expect, Page } from "@playwright/test";
const TEST_USER = { username: "testuser", password: "testpass123" };
async function login(page: Page) {
await page.goto("/login");
await page.locator("#username").fill(TEST_USER.username);
await page.locator("#password").fill(TEST_USER.password);
await page.locator('button[type="submit"]').click();
await page.waitForURL("**/", { timeout: 10000 });
}
test.describe("Signal Cancel & Related Pages", () => {
test.beforeEach(async ({ page }) => {
await login(page);
});
test("should access signals page and see signal table", async ({ page }) => {
await page.goto("/signals");
// Wait for page title to appear
await expect(page.getByText("KJB 매매 신호")).toBeVisible({
timeout: 10000,
});
// Signal table should be visible
await expect(page.locator("table").first()).toBeVisible();
// Summary cards should be visible
await expect(page.getByText("매수 신호")).toBeVisible();
await expect(page.getByText("매도 신호", { exact: true })).toBeVisible();
await page.screenshot({
path: "../docs/screenshots/signals-page.png",
fullPage: true,
});
});
test("should show cancel button for EXECUTED signals", async ({ page }) => {
await page.goto("/signals");
await expect(page.getByText("KJB 매매 신호")).toBeVisible({
timeout: 10000,
});
// Switch to history view for executed signals
const historyButton = page.getByText("신호 이력");
if (await historyButton.isVisible()) {
await historyButton.click();
await page.waitForTimeout(2000);
}
// Check if any executed signal rows exist
const executedBadges = page.locator('text="실행됨"');
const count = await executedBadges.count();
if (count > 0) {
// There should be a cancel button near the executed signal
const cancelButtons = page.locator('button:has-text("취소")');
const cancelCount = await cancelButtons.count();
expect(cancelCount).toBeGreaterThan(0);
await page.screenshot({
path: "../docs/screenshots/signals-executed-with-cancel.png",
fullPage: true,
});
} else {
// No executed signals - verify the page structure is correct
console.log(
"No EXECUTED signals found - cancel button test skipped (no data)"
);
await expect(page.locator("table").first()).toBeVisible();
await page.screenshot({
path: "../docs/screenshots/signals-history.png",
fullPage: true,
});
}
});
test("should show realized/unrealized PnL cards on portfolio detail page", async ({
page,
}) => {
// First check if any portfolio exists
await page.goto("/portfolio");
await page.waitForTimeout(2000);
// Try to find a portfolio link
const portfolioLinks = page.locator('a[href^="/portfolio/"]');
const linkCount = await portfolioLinks.count();
if (linkCount > 0) {
await portfolioLinks.first().click();
await page.waitForTimeout(3000);
} else {
await page.goto("/portfolio/1");
await page.waitForTimeout(3000);
}
// Check for realized/unrealized PnL cards
const realizedPnlLabel = page.getByText("실현 수익");
const unrealizedPnlLabel = page.getByText("미실현 수익");
const hasRealizedCard = await realizedPnlLabel
.isVisible()
.catch(() => false);
const hasUnrealizedCard = await unrealizedPnlLabel
.isVisible()
.catch(() => false);
if (hasRealizedCard && hasUnrealizedCard) {
await expect(realizedPnlLabel).toBeVisible();
await expect(unrealizedPnlLabel).toBeVisible();
await expect(page.getByText("매도 확정 손익")).toBeVisible();
await expect(page.getByText("보유 중 평가 손익")).toBeVisible();
} else {
console.log(
"Portfolio detail page may not have data - PnL cards not visible"
);
}
await page.screenshot({
path: "../docs/screenshots/portfolio-detail.png",
fullPage: true,
});
});
test("should render strategy compare page", async ({ page }) => {
await page.goto("/strategy/compare");
// Wait for page title
await expect(
page.getByRole("heading", { name: "전략 비교" })
).toBeVisible({
timeout: 10000,
});
// Check description text
await expect(
page.getByText("멀티팩터, 퀄리티, 밸류모멘텀")
).toBeVisible();
// Check the compare execution button
const runButton = page.getByText("전략 비교 실행");
await expect(runButton).toBeVisible();
await page.screenshot({
path: "../docs/screenshots/strategy-compare.png",
fullPage: true,
});
});
});