From d4caf45b2b9ea6a3276de792cf6f73085e66b1ae Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 16 Feb 2026 18:15:47 +0000 Subject: Add performance benchmarks, stress tests, and frontend perf tests Go benchmarks cover item CRUD/filter/sanitization, API endpoints (stream, item update, feed list), middleware stack (gzip, security headers, CSRF), and crawler pipeline (feed parsing, mocked crawl). Stress tests verify concurrent reads/writes and large dataset handling. Frontend perf tests measure template generation, DOM insertion, and store event throughput. New Makefile targets: bench, bench-short, stress, test-perf. https://claude.ai/code/session_01ChDVWFDrQoFjMYHpaLGr9s --- frontend-vanilla/src/perf/renderItems.perf.test.ts | 90 ++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 frontend-vanilla/src/perf/renderItems.perf.test.ts (limited to 'frontend-vanilla/src/perf/renderItems.perf.test.ts') diff --git a/frontend-vanilla/src/perf/renderItems.perf.test.ts b/frontend-vanilla/src/perf/renderItems.perf.test.ts new file mode 100644 index 0000000..3dd2ed7 --- /dev/null +++ b/frontend-vanilla/src/perf/renderItems.perf.test.ts @@ -0,0 +1,90 @@ +import { describe, it, expect } from 'vitest'; +import { createFeedItem } from '../components/FeedItem'; +import type { Item } from '../types'; + +function makeItem(id: number): Item { + return { + _id: id, + feed_id: 1, + title: `Test Item ${id}`, + url: `https://example.com/item/${id}`, + description: `

Description for item ${id} with bold and link

`, + publish_date: '2024-01-01T00:00:00Z', + read: id % 3 === 0, + starred: id % 5 === 0, + feed_title: 'Test Feed', + }; +} + +describe('renderItems performance', () => { + it('createFeedItem renders 100 items under 50ms', () => { + const items = Array.from({ length: 100 }, (_, i) => makeItem(i)); + + const start = performance.now(); + const html = items.map(item => createFeedItem(item)).join(''); + const elapsed = performance.now() - start; + + expect(html).toBeTruthy(); + expect(html).toContain('feed-item'); + expect(elapsed).toBeLessThan(50); + }); + + it('createFeedItem renders 500 items under 200ms', () => { + const items = Array.from({ length: 500 }, (_, i) => makeItem(i)); + + const start = performance.now(); + const html = items.map(item => createFeedItem(item)).join(''); + const elapsed = performance.now() - start; + + expect(html).toBeTruthy(); + expect(elapsed).toBeLessThan(200); + }); + + it('createFeedItem renders 1000 items under 100ms', () => { + const items = Array.from({ length: 1000 }, (_, i) => makeItem(i)); + + const start = performance.now(); + const results: string[] = []; + for (const item of items) { + results.push(createFeedItem(item)); + } + const elapsed = performance.now() - start; + + expect(results.length).toBe(1000); + expect(elapsed).toBeLessThan(100); + }); + + it('DOM insertion of 100 items under 200ms', () => { + const items = Array.from({ length: 100 }, (_, i) => makeItem(i)); + const html = items.map(item => createFeedItem(item)).join(''); + + const container = document.createElement('ul'); + document.body.appendChild(container); + + const start = performance.now(); + container.innerHTML = html; + const elapsed = performance.now() - start; + + expect(container.children.length).toBe(100); + expect(elapsed).toBeLessThan(200); + + document.body.removeChild(container); + }); + + it('DOM insertion of 500 items under 500ms', () => { + const items = Array.from({ length: 500 }, (_, i) => makeItem(i)); + const html = items.map(item => createFeedItem(item)).join(''); + + const container = document.createElement('ul'); + document.body.appendChild(container); + + const start = performance.now(); + container.innerHTML = html; + const elapsed = performance.now() - start; + + expect(container.children.length).toBe(500); + expect(elapsed).toBeLessThan(500); + + document.body.removeChild(container); + }); +}); -- cgit v1.2.3