From bbb29857b83116fc1c367ea422bc2f43d8028a43 Mon Sep 17 00:00:00 2001 From: Test Date: Fri, 6 Mar 2026 16:09:29 +0100 Subject: [PATCH] test: add regression tests for hyphenated folder sidebar duplicates - Sidebar unit test: entries with isA 'Monday Ideas' produce exactly one section header (not two) - Playwright smoke test: verify no duplicate section labels in sidebar Co-Authored-By: Claude Opus 4.6 --- src/components/Sidebar.test.tsx | 38 +++++++++++++++++++ .../smoke/sidebar-duplicate-sections.spec.ts | 36 ++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/smoke/sidebar-duplicate-sections.spec.ts diff --git a/src/components/Sidebar.test.tsx b/src/components/Sidebar.test.tsx index fbcbaed0..fc68f0dc 100644 --- a/src/components/Sidebar.test.tsx +++ b/src/components/Sidebar.test.tsx @@ -893,4 +893,42 @@ describe('Sidebar', () => { expect(screen.queryByRole('textbox', { name: 'Section name' })).not.toBeInTheDocument() }) }) + + it('renders exactly one section for a hyphenated custom type like Monday Ideas', () => { + const entriesWithMondayIdeas: VaultEntry[] = [ + ...mockEntries, + { + path: '/vault/monday-ideas/standup-bingo.md', + filename: 'standup-bingo.md', + title: 'Standup Bingo', + isA: 'Monday Ideas', + aliases: [], belongsTo: [], relatedTo: [], + status: null, owner: null, cadence: null, + archived: false, trashed: false, trashedAt: null, + modifiedAt: 1700000000, createdAt: null, + fileSize: 310, snippet: '', wordCount: 120, + relationships: {}, icon: null, color: null, order: null, + sidebarLabel: null, template: null, sort: null, view: null, + outgoingLinks: [], properties: {}, + }, + { + path: '/vault/monday-ideas/theme-days.md', + filename: 'theme-days.md', + title: 'Theme Days', + isA: 'Monday Ideas', + aliases: [], belongsTo: [], relatedTo: [], + status: null, owner: null, cadence: null, + archived: false, trashed: false, trashedAt: null, + modifiedAt: 1700000000, createdAt: null, + fileSize: 280, snippet: '', wordCount: 95, + relationships: {}, icon: null, color: null, order: null, + sidebarLabel: null, template: null, sort: null, view: null, + outgoingLinks: [], properties: {}, + }, + ] + render( {}} />) + // "Monday Ideas" pluralized → "Monday Ideases" (the pluralizeType function) + const mondaySections = screen.getAllByText(/Monday Ideas/i) + expect(mondaySections).toHaveLength(1) + }) }) diff --git a/tests/smoke/sidebar-duplicate-sections.spec.ts b/tests/smoke/sidebar-duplicate-sections.spec.ts new file mode 100644 index 00000000..ba384c61 --- /dev/null +++ b/tests/smoke/sidebar-duplicate-sections.spec.ts @@ -0,0 +1,36 @@ +import { test, expect } from '@playwright/test' + +test.describe('Sidebar duplicate sections', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/') + await page.waitForLoadState('networkidle') + }) + + test('no duplicate sidebar section headers', async ({ page }) => { + // Verify that every section label in the sidebar is unique. + // Before the fix, hyphenated folder names (e.g. monday-ideas/) + // would produce a different isA than the Type file title, + // resulting in two sidebar sections for the same type. + + const sidebar = page.locator('.app__sidebar') + + // Wait for at least one Expand/Collapse button (indicates sections rendered) + await sidebar.locator('button[aria-label*="Collapse"], button[aria-label*="Expand"]').first().waitFor({ timeout: 5000 }) + + // Extract section labels from the Expand/Collapse aria-labels + const buttons = sidebar.locator('button[aria-label*="Collapse"], button[aria-label*="Expand"]') + const count = await buttons.count() + const labels: string[] = [] + for (let i = 0; i < count; i++) { + const ariaLabel = await buttons.nth(i).getAttribute('aria-label') + // aria-label is like "Collapse Projects" or "Expand Projects" + const label = ariaLabel?.replace(/^(Collapse|Expand)\s+/, '') ?? '' + if (label) labels.push(label) + } + + // Every label should be unique — no duplicates + const uniqueLabels = [...new Set(labels)] + expect(labels).toEqual(uniqueLabels) + expect(labels.length).toBeGreaterThan(0) + }) +})