Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions e2e/tests/isotope-chart.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import { test, expect } from '@playwright/test';
import {
waitForDatabaseReady,
acceptMeteredWarningIfPresent,
acceptPrivacyConsent
} from '../fixtures/test-helpers';

test.describe('Isotope Chart', () => {
test.beforeEach(async ({ page }) => {
await acceptPrivacyConsent(page);
await page.goto('/');
await acceptMeteredWarningIfPresent(page);
await waitForDatabaseReady(page);
});

test('should navigate to isotope chart page', async ({ page }) => {
// Click on Isotope Chart navigation link
await page.click('text=Isotope Chart');

// Wait for page to load
await expect(page).toHaveURL('/isotope-chart');

// Verify page title
await expect(page.locator('h1')).toContainText('Isotope Chart');
await expect(page.locator('h1')).toContainText('Segré Chart');
});

test('should display chart with controls', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Verify main elements are present
await expect(page.locator('h1')).toContainText('Isotope Chart');

// Check for toggle controls
await expect(page.locator('text=Valley of Stability')).toBeVisible();
await expect(page.locator('text=Magic Numbers')).toBeVisible();

// Check for legend button
await expect(page.locator('text=Legend')).toBeVisible();

// Check for canvas element (chart rendering)
const canvas = page.locator('canvas');
await expect(canvas).toBeVisible();
});

test('should toggle valley of stability', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Find the valley of stability checkbox
const valleyCheckbox = page.locator('input[type="checkbox"]').first();

// Should be checked by default
await expect(valleyCheckbox).toBeChecked();

// Uncheck it
await valleyCheckbox.click();
await expect(valleyCheckbox).not.toBeChecked();

// Check it again
await valleyCheckbox.click();
await expect(valleyCheckbox).toBeChecked();
});

test('should toggle magic numbers', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Find the magic numbers checkbox (second checkbox)
const magicCheckbox = page.locator('input[type="checkbox"]').nth(1);

// Should be checked by default
await expect(magicCheckbox).toBeChecked();

// Uncheck it
await magicCheckbox.click();
await expect(magicCheckbox).not.toBeChecked();

// Check it again
await magicCheckbox.click();
await expect(magicCheckbox).toBeChecked();
});

test('should toggle legend visibility', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Legend should be visible by default
await expect(page.locator('text=Nuclide Stability')).toBeVisible();
await expect(page.locator('text=Chart Features')).toBeVisible();

// Click hide legend button
await page.click('text=Hide Legend');

// Legend sections should not be visible
await expect(page.locator('text=Nuclide Stability')).not.toBeVisible();

// Click show legend button
await page.click('text=Show Legend');

// Legend should be visible again
await expect(page.locator('text=Nuclide Stability')).toBeVisible();
});

test('should display info banner with explanation', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Check for info banner
await expect(page.locator('text=What is the Segré Chart?')).toBeVisible();
await expect(page.locator('text=valley of stability')).toBeVisible();
await expect(page.locator('text=Magic numbers')).toBeVisible();
});

test('should show stability legend items', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Verify stability color legend
await expect(page.locator('text=Stable')).toBeVisible();
await expect(page.locator('text=Long-lived')).toBeVisible();
await expect(page.locator('text=Short-lived')).toBeVisible();
await expect(page.locator('text=Unknown / Not in database')).toBeVisible();
});

test('should show axes information in legend', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Verify axes information
await expect(page.locator('text=Proton number (Z)')).toBeVisible();
await expect(page.locator('text=Neutron number (N)')).toBeVisible();
await expect(page.locator('text=Z=1-94, N=0-150')).toBeVisible();
});

test('should show interaction instructions', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Verify interaction instructions
await expect(page.locator('text=Hover:')).toBeVisible();
await expect(page.locator('text=Click:')).toBeVisible();
await expect(page.locator('text=Scroll:')).toBeVisible();
await expect(page.locator('text=Drag:')).toBeVisible();
});

test('should render canvas chart', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Wait for canvas to be rendered
const canvas = page.locator('canvas');
await expect(canvas).toBeVisible();

// Canvas should have non-zero dimensions
const boundingBox = await canvas.boundingBox();
expect(boundingBox).not.toBeNull();
expect(boundingBox!.width).toBeGreaterThan(0);
expect(boundingBox!.height).toBeGreaterThan(0);
});

test('should have zoom controls hint', async ({ page }) => {
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Check for zoom hints
await expect(page.locator('text=Scroll to zoom')).toBeVisible();
await expect(page.locator('text=Double-click to reset')).toBeVisible();
});

test('should be responsive on mobile', async ({ page }) => {
// Set mobile viewport
await page.setViewportSize({ width: 375, height: 667 });
await page.goto('/isotope-chart');
await waitForDatabaseReady(page);

// Page should still load
await expect(page.locator('h1')).toContainText('Isotope Chart');

// Canvas should be visible
const canvas = page.locator('canvas');
await expect(canvas).toBeVisible();
});
});
1 change: 1 addition & 0 deletions e2e/tests/navigation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ test.describe('Navigation and Routing', () => {
{ path: '/fission', name: 'Fission', heading: /Fission Reactions/i, needsDb: true },
{ path: '/twotwo', name: 'Two-to-Two', heading: /Two-to-Two Reactions/i, needsDb: true },
{ path: '/element-data', name: 'Element Data', heading: /Element Data/i, needsDb: true },
{ path: '/isotope-chart', name: 'Isotope Chart', heading: /Isotope Chart/i, needsDb: true },
{ path: '/tables', name: 'Tables in Detail', heading: /Tables in Detail/i, needsDb: true },
{ path: '/all-tables', name: 'All Tables', heading: /All Tables/i, needsDb: true },
{ path: '/cascades', name: 'Cascades', heading: /Cascade Simulations/i, needsDb: false },
Expand Down
Binary file added metered-connection-warning-screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import ShowElementData from './pages/ShowElementData'
import TablesInDetail from './pages/TablesInDetail'
import AllTables from './pages/AllTables'
import CascadesAll from './pages/CascadesAll'
import IsotopeChart from './pages/IsotopeChart'
import PrivacyPreferences from './pages/PrivacyPreferences'
import SentryTest from './pages/SentryTest'
import DatabaseErrorCard from './components/DatabaseErrorCard'
Expand Down Expand Up @@ -88,6 +89,7 @@ function App() {
<Route path="/fission" element={<FissionQuery />} />
<Route path="/twotwo" element={<TwoToTwoQuery />} />
<Route path="/element-data" element={<ShowElementData />} />
<Route path="/isotope-chart" element={<IsotopeChart />} />
<Route path="/tables" element={<TablesInDetail />} />
<Route path="/all-tables" element={<AllTables />} />
<Route path="/cascades" element={<CascadesAll />} />
Expand Down
Loading
Loading