todays product advirories implemented
This commit is contained in:
215
src/Web/StellaOps.Web/tests/e2e/binary-diff-panel.spec.ts
Normal file
215
src/Web/StellaOps.Web/tests/e2e/binary-diff-panel.spec.ts
Normal file
@@ -0,0 +1,215 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// binary-diff-panel.spec.ts
|
||||
// Sprint: SPRINT_20260117_018_FE_ux_components
|
||||
// Task: UXC-008 - Integration tests with Playwright
|
||||
// Description: Playwright e2e tests for Binary-Diff Panel component
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { policyAuthorSession } from '../../src/app/testing';
|
||||
|
||||
const mockConfig = {
|
||||
authority: {
|
||||
issuer: 'https://authority.local',
|
||||
clientId: 'stellaops-ui',
|
||||
authorizeEndpoint: 'https://authority.local/connect/authorize',
|
||||
tokenEndpoint: 'https://authority.local/connect/token',
|
||||
logoutEndpoint: 'https://authority.local/connect/logout',
|
||||
redirectUri: 'http://127.0.0.1:4400/auth/callback',
|
||||
postLogoutRedirectUri: 'http://127.0.0.1:4400/',
|
||||
scope: 'openid profile email ui.read findings:read binary:read',
|
||||
audience: 'https://scanner.local',
|
||||
dpopAlgorithms: ['ES256'],
|
||||
refreshLeewaySeconds: 60,
|
||||
},
|
||||
apiBaseUrls: {
|
||||
authority: 'https://authority.local',
|
||||
scanner: 'https://scanner.local',
|
||||
policy: 'https://scanner.local',
|
||||
concelier: 'https://concelier.local',
|
||||
attestor: 'https://attestor.local',
|
||||
},
|
||||
quickstartMode: true,
|
||||
};
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.addInitScript((session) => {
|
||||
try {
|
||||
window.sessionStorage.clear();
|
||||
} catch {
|
||||
// ignore storage errors in restricted contexts
|
||||
}
|
||||
(window as any).__stellaopsTestSession = session;
|
||||
}, policyAuthorSession);
|
||||
|
||||
await page.route('**/config.json', (route) =>
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(mockConfig),
|
||||
})
|
||||
);
|
||||
|
||||
await page.route('https://authority.local/**', (route) => route.abort());
|
||||
});
|
||||
|
||||
test.describe('Binary-Diff Panel Component', () => {
|
||||
test('renders header with base and candidate info', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Verify header shows base and candidate
|
||||
await expect(page.getByText('Base')).toBeVisible();
|
||||
await expect(page.getByText('Candidate')).toBeVisible();
|
||||
|
||||
// Verify diff stats
|
||||
await expect(page.locator('.diff-stats')).toBeVisible();
|
||||
});
|
||||
|
||||
test('scope selector switches between file, section, function', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Find scope selector buttons
|
||||
const fileBtn = page.getByRole('button', { name: /File/i });
|
||||
const sectionBtn = page.getByRole('button', { name: /Section/i });
|
||||
const functionBtn = page.getByRole('button', { name: /Function/i });
|
||||
|
||||
await expect(fileBtn).toBeVisible();
|
||||
await expect(sectionBtn).toBeVisible();
|
||||
await expect(functionBtn).toBeVisible();
|
||||
|
||||
// Click section scope
|
||||
await sectionBtn.click();
|
||||
await expect(sectionBtn).toHaveClass(/active/);
|
||||
|
||||
// Click function scope
|
||||
await functionBtn.click();
|
||||
await expect(functionBtn).toHaveClass(/active/);
|
||||
|
||||
// Click file scope
|
||||
await fileBtn.click();
|
||||
await expect(fileBtn).toHaveClass(/active/);
|
||||
});
|
||||
|
||||
test('scope selection updates diff view', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Select an entry in the tree
|
||||
const treeItem = page.locator('.tree-item').first();
|
||||
await treeItem.click();
|
||||
|
||||
// Verify selection state
|
||||
await expect(treeItem).toHaveClass(/selected/);
|
||||
|
||||
// Verify diff view updates (footer shows hashes)
|
||||
await expect(page.locator('.diff-footer')).toBeVisible();
|
||||
});
|
||||
|
||||
test('show only changed toggle filters unchanged entries', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Find the toggle
|
||||
const toggle = page.getByLabel(/Show only changed/i);
|
||||
await expect(toggle).toBeVisible();
|
||||
|
||||
// Count items before toggle
|
||||
const itemsBefore = await page.locator('.tree-item').count();
|
||||
|
||||
// Enable toggle
|
||||
await toggle.check();
|
||||
await expect(toggle).toBeChecked();
|
||||
|
||||
// Items may be filtered (or same count if all changed)
|
||||
const itemsAfter = await page.locator('.tree-item').count();
|
||||
expect(itemsAfter).toBeLessThanOrEqual(itemsBefore);
|
||||
});
|
||||
|
||||
test('opcodes/decompiled toggle changes view mode', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Find the toggle
|
||||
const toggle = page.getByLabel(/Opcodes|Decompiled/i);
|
||||
await expect(toggle).toBeVisible();
|
||||
|
||||
// Toggle and verify label changes
|
||||
const initialText = await toggle.locator('..').textContent();
|
||||
await toggle.click();
|
||||
const newText = await toggle.locator('..').textContent();
|
||||
|
||||
// Text should change between Opcodes and Decompiled
|
||||
expect(initialText).not.toEqual(newText);
|
||||
});
|
||||
|
||||
test('export signed diff button is functional', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Find export button
|
||||
const exportBtn = page.getByRole('button', { name: /Export Signed Diff/i });
|
||||
await expect(exportBtn).toBeVisible();
|
||||
|
||||
// Click and verify action
|
||||
await exportBtn.click();
|
||||
|
||||
// Should trigger download or modal (implementation dependent)
|
||||
// At minimum, button should be clickable without error
|
||||
});
|
||||
|
||||
test('tree navigation supports keyboard', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Focus first tree item
|
||||
const firstItem = page.locator('.tree-item').first();
|
||||
await firstItem.focus();
|
||||
|
||||
// Press Enter to select
|
||||
await page.keyboard.press('Enter');
|
||||
await expect(firstItem).toHaveClass(/selected/);
|
||||
});
|
||||
|
||||
test('diff view shows side-by-side comparison', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Verify side-by-side columns
|
||||
await expect(page.locator('.diff-header-row')).toBeVisible();
|
||||
await expect(page.locator('.line-base').first()).toBeVisible();
|
||||
await expect(page.locator('.line-candidate').first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('change indicators show correct colors', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Check for change type classes on tree items
|
||||
const addedItem = page.locator('.tree-item.change-added');
|
||||
const removedItem = page.locator('.tree-item.change-removed');
|
||||
const modifiedItem = page.locator('.tree-item.change-modified');
|
||||
|
||||
// At least one type should exist in a real diff
|
||||
const hasChanges =
|
||||
(await addedItem.count()) > 0 ||
|
||||
(await removedItem.count()) > 0 ||
|
||||
(await modifiedItem.count()) > 0;
|
||||
|
||||
expect(hasChanges).toBeTruthy();
|
||||
});
|
||||
|
||||
test('hash display in footer shows base and candidate hashes', async ({ page }) => {
|
||||
await page.goto('/binary/diff');
|
||||
await expect(page.locator('.binary-diff-panel')).toBeVisible({ timeout: 10000 });
|
||||
|
||||
// Select an entry
|
||||
await page.locator('.tree-item').first().click();
|
||||
|
||||
// Verify footer hash display
|
||||
await expect(page.getByText('Base Hash:')).toBeVisible();
|
||||
await expect(page.getByText('Candidate Hash:')).toBeVisible();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user