103 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { test, expect } from '@playwright/test';
 | 
						|
 | 
						|
// Helpers to probe canvas by reading pixel colors
 | 
						|
async function getPixelColor(page: any, selector: string, x: number, y: number) {
 | 
						|
  return await page.$eval(selector, (canvas: HTMLCanvasElement, [x, y]) => {
 | 
						|
    const ctx = canvas.getContext('2d')!;
 | 
						|
    const dpr = window.devicePixelRatio || 1;
 | 
						|
    const data = ctx.getImageData(Math.floor(x), Math.floor(y), 1, 1).data;
 | 
						|
    return Array.from(data);
 | 
						|
  }, [x, y]);
 | 
						|
}
 | 
						|
 | 
						|
// Minimal smoke tests ensuring that UI controls affect the canvas
 | 
						|
// These assume the app starts with some graph data (test vault bundled)
 | 
						|
 | 
						|
test.describe('Graph Canvas', () => {
 | 
						|
  test.beforeEach(async ({ page }) => {
 | 
						|
    await page.goto('/');
 | 
						|
    // Open Graph view
 | 
						|
    await page.getByRole('button', { name: /graphe|graph/i }).first().click();
 | 
						|
    // Ensure canvas exists
 | 
						|
    await page.waitForSelector('app-graph-canvas canvas');
 | 
						|
  });
 | 
						|
 | 
						|
  test('toggle Existing files only reduces node count', async ({ page }) => {
 | 
						|
    // Open settings panel
 | 
						|
    await page.getByRole('button', { name: /settings|param/i }).first().click();
 | 
						|
    // Toggle Existing files only
 | 
						|
    const checkbox = page.getByText(/Existing files only/i).locator('..').locator('input[type="checkbox"]');
 | 
						|
    await checkbox.click({ force: true });
 | 
						|
    // Wait a bit for recompute
 | 
						|
    await page.waitForTimeout(200);
 | 
						|
    // We cannot count nodes directly; instead, ensure simulation tick updates occurred by reading overlay text
 | 
						|
    const stats = await page.locator('text=/Nodes:/').first().innerText();
 | 
						|
    expect(stats).toMatch(/Nodes:/);
 | 
						|
  });
 | 
						|
 | 
						|
  test('change Link distance affects layout (smoke)', async ({ page }) => {
 | 
						|
    await page.getByRole('button', { name: /settings|param/i }).first().click();
 | 
						|
    // Ensure Forces section is expanded in the settings accordion
 | 
						|
    const forcesHeader = page.getByRole('button', { name: /^Forces$/i }).first();
 | 
						|
    await forcesHeader.click({ force: true });
 | 
						|
    // Slide Link distance; we approximate by focusing input[type=range] with label
 | 
						|
    const slider = page.getByText(/Link distance/i).locator('..').locator('input[type="range"]').first();
 | 
						|
    await slider.evaluate((el: HTMLInputElement) => { el.value = '100'; el.dispatchEvent(new Event('input', { bubbles: true })); });
 | 
						|
    await page.waitForTimeout(300);
 | 
						|
    // No assertion on pixels here; just ensure canvas repaints by checking it remains attached
 | 
						|
    const canvasVisible = await page.isVisible('app-graph-canvas canvas');
 | 
						|
    expect(canvasVisible).toBeTruthy();
 | 
						|
  });
 | 
						|
 | 
						|
  test('adding group tag:test colors some nodes and legend updates', async ({ page }) => {
 | 
						|
    await page.getByRole('button', { name: /settings|param/i }).first().click();
 | 
						|
    // Add new group
 | 
						|
    await page.getByRole('button', { name: /new group/i }).click({ force: true });
 | 
						|
    const lastGroupInput = page.locator('app-graph-groups-section input[type="text"]').last();
 | 
						|
    await lastGroupInput.fill('tag:test');
 | 
						|
    // Wait for legend to render and reflect the new group
 | 
						|
    await page.waitForSelector('app-graph-legend');
 | 
						|
    const legendItems = page.locator('app-graph-legend button');
 | 
						|
    await legendItems.first().waitFor({ state: 'visible', timeout: 2000 }).catch(() => {});
 | 
						|
    const count = await legendItems.count();
 | 
						|
    expect(count).toBeGreaterThan(0);
 | 
						|
  });
 | 
						|
 | 
						|
  test('open/close Graph 10x remains responsive (no freeze)', async ({ page }) => {
 | 
						|
    // Capture console errors during the whole test
 | 
						|
    const errors: string[] = [];
 | 
						|
    page.on('console', (msg) => {
 | 
						|
      if (msg.type() === 'error') errors.push(msg.text());
 | 
						|
    });
 | 
						|
 | 
						|
    // Buttons in header/sidebar
 | 
						|
    const graphButtons = [
 | 
						|
      page.getByRole('button', { name: /graph|graphe/i }).first(),
 | 
						|
    ];
 | 
						|
    const filesButtons = [
 | 
						|
      page.getByRole('button', { name: /files|fichiers/i }).first(),
 | 
						|
    ];
 | 
						|
 | 
						|
    // Perform 10 rapid toggles
 | 
						|
    for (let i = 0; i < 10; i++) {
 | 
						|
      await graphButtons[0].click({ timeout: 2000 });
 | 
						|
      // Canvas should be present quickly
 | 
						|
      await page.waitForSelector('app-graph-canvas canvas', { timeout: 3000 });
 | 
						|
 | 
						|
      // Evaluate a trivial script to ensure main thread is not locked
 | 
						|
      const val = await page.evaluate(() => 21 + 21);
 | 
						|
      expect(val).toBe(42);
 | 
						|
 | 
						|
      // Switch back to files
 | 
						|
      await filesButtons[0].click({ timeout: 2000 });
 | 
						|
 | 
						|
      // Quick evaluation again
 | 
						|
      const val2 = await page.evaluate(() => 1 + 1);
 | 
						|
      expect(val2).toBe(2);
 | 
						|
    }
 | 
						|
 | 
						|
    // Ensure no console errors during toggles
 | 
						|
    expect(errors.length).toBeLessThan(2); // allow transient warnings but not repeated errors
 | 
						|
  });
 | 
						|
});
 |