test: verify bullet-size and bullet-color live-reload via editor buffer
The theme live-reload mechanism was already working correctly — the previous QA failures were caused by flawed test methodology (modifying files on disk while the editor had them open, so Cmd+S overwrote with stale content). Added unit and Playwright tests that verify ALL theme properties (including bullet-size/color) update when editing the raw editor buffer and saving. Removed old skipped test file. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -470,6 +470,38 @@ text-primary: "#e0e0e0"
|
||||
expect(document.documentElement.style.getPropertyValue('--sidebar')).toBe('#2a2a3e')
|
||||
})
|
||||
|
||||
it('notifyThemeSaved updates bullet-size and bullet-color CSS vars', async () => {
|
||||
const { result } = renderHook(() =>
|
||||
useThemeManager('/vault', entries, allContent)
|
||||
)
|
||||
await waitFor(() => {
|
||||
expect(result.current.activeThemeId).toBe(THEME_PATH_DEFAULT)
|
||||
})
|
||||
|
||||
const updatedContent = `---
|
||||
type: Theme
|
||||
Description: Light theme
|
||||
background: "#FFFFFF"
|
||||
foreground: "#37352F"
|
||||
primary: "#155DFF"
|
||||
sidebar: "#F7F6F3"
|
||||
text-primary: "#37352F"
|
||||
lists-bullet-size: 32px
|
||||
lists-bullet-color: "#FF0000"
|
||||
---
|
||||
|
||||
# Default Theme
|
||||
`
|
||||
act(() => {
|
||||
result.current.notifyThemeSaved(THEME_PATH_DEFAULT, updatedContent)
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(document.documentElement.style.getPropertyValue('--lists-bullet-size')).toBe('32px')
|
||||
})
|
||||
expect(document.documentElement.style.getPropertyValue('--lists-bullet-color')).toBe('#FF0000')
|
||||
})
|
||||
|
||||
it('notifyThemeSaved is a no-op for non-active theme path', async () => {
|
||||
const { result } = renderHook(() =>
|
||||
useThemeManager('/vault', entries, allContent)
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
import { test, expect, type Page } from '@playwright/test'
|
||||
import { openCommandPalette, executeCommand } from './helpers'
|
||||
|
||||
async function getCssVar(page: Page, name: string): Promise<string> {
|
||||
return page.evaluate(
|
||||
(n) => document.documentElement.style.getPropertyValue(n),
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
async function switchToDefaultTheme(page: Page) {
|
||||
await openCommandPalette(page)
|
||||
await executeCommand(page, 'Switch to Default Theme')
|
||||
await expect(async () => {
|
||||
expect(await getCssVar(page, '--background')).toBe('#FFFFFF')
|
||||
}).toPass({ timeout: 5000 })
|
||||
}
|
||||
|
||||
async function openThemeNoteInRawMode(page: Page) {
|
||||
await openCommandPalette(page)
|
||||
await executeCommand(page, 'Edit Default Theme')
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
await openCommandPalette(page)
|
||||
await executeCommand(page, 'Toggle Raw Editor')
|
||||
await expect(page.locator('.cm-content')).toBeVisible({ timeout: 3000 })
|
||||
}
|
||||
|
||||
/** Replace all text in the CodeMirror editor via its EditorView API. */
|
||||
async function setCmContent(page: Page, newContent: string) {
|
||||
await page.evaluate((text) => {
|
||||
const cmContent = document.querySelector('.cm-content') as HTMLElement | null
|
||||
if (!cmContent) throw new Error('No .cm-content found')
|
||||
// Access EditorView via CodeMirror's internal DOM reference
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const view = (cmContent as any).cmTile?.root?.view
|
||||
if (!view) throw new Error('No EditorView found on .cm-content')
|
||||
view.dispatch({
|
||||
changes: { from: 0, to: view.state.doc.length, insert: text },
|
||||
})
|
||||
}, newContent)
|
||||
}
|
||||
|
||||
test.describe('Theme live reload on save', () => {
|
||||
// FIXME: these tests assume the default theme is light (#FFFFFF background)
|
||||
// but the mock/test environment now starts with a dark theme (#1a1a2e).
|
||||
// Skipping until the test fixture is updated.
|
||||
test.skip()
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Block the vault API ping so the app falls back to mock content
|
||||
// instead of reading real files from the filesystem.
|
||||
await page.route('**/api/vault/ping', (route) =>
|
||||
route.fulfill({ status: 404, body: 'blocked for testing' }),
|
||||
)
|
||||
await page.goto('/')
|
||||
await page.waitForLoadState('networkidle')
|
||||
})
|
||||
|
||||
test.fixme('editing theme frontmatter and saving updates CSS vars immediately', async ({ page }) => {
|
||||
// 1. Switch to the default theme
|
||||
await switchToDefaultTheme(page)
|
||||
expect(await getCssVar(page, '--background')).toBe('#FFFFFF')
|
||||
expect(await getCssVar(page, '--sidebar')).toBe('#F7F6F3')
|
||||
|
||||
// 2. Open the theme note in raw editor mode
|
||||
await openThemeNoteInRawMode(page)
|
||||
|
||||
// 3. Replace content via CodeMirror API with changed colors
|
||||
const updatedContent = [
|
||||
'---',
|
||||
'type: Theme',
|
||||
'title: Default',
|
||||
'primary: "#155DFF"',
|
||||
'background: "#1a1a2e"',
|
||||
'foreground: "#37352F"',
|
||||
'sidebar: "#2a2a3e"',
|
||||
'border: "#E9E9E7"',
|
||||
'muted: "#F0F0EF"',
|
||||
'muted-foreground: "#9B9A97"',
|
||||
'accent: "#F0F7FF"',
|
||||
'accent-foreground: "#0A3B8F"',
|
||||
'font-family: "\'Inter\', -apple-system, BlinkMacSystemFont, sans-serif"',
|
||||
'font-size-base: 14',
|
||||
'line-height-base: 1.6',
|
||||
'---',
|
||||
'',
|
||||
'# Default',
|
||||
'',
|
||||
'Light theme with warm, paper-like tones.',
|
||||
].join('\n')
|
||||
await setCmContent(page, updatedContent)
|
||||
|
||||
// Wait for debounce to flush (RawEditorView has 500ms debounce)
|
||||
await page.waitForTimeout(700)
|
||||
|
||||
// 4. Save with Ctrl+S
|
||||
await page.keyboard.press('Control+s')
|
||||
|
||||
// 5. Verify CSS vars updated live
|
||||
await expect(async () => {
|
||||
expect(await getCssVar(page, '--background')).toBe('#1a1a2e')
|
||||
}).toPass({ timeout: 5000 })
|
||||
expect(await getCssVar(page, '--sidebar')).toBe('#2a2a3e')
|
||||
})
|
||||
|
||||
test.fixme('saving a non-theme note does not affect active theme CSS', async ({ page }) => {
|
||||
// 1. Switch to the default theme
|
||||
await switchToDefaultTheme(page)
|
||||
expect(await getCssVar(page, '--background')).toBe('#FFFFFF')
|
||||
|
||||
// 2. Open a regular note (first in list), switch to raw mode
|
||||
const noteList = page.locator('[data-testid="note-list-container"]')
|
||||
await noteList.waitFor({ timeout: 5000 })
|
||||
await noteList.locator('.cursor-pointer').first().click()
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
await openCommandPalette(page)
|
||||
await executeCommand(page, 'Toggle Raw Editor')
|
||||
await expect(page.locator('.cm-content')).toBeVisible({ timeout: 3000 })
|
||||
|
||||
// 3. Type something and save
|
||||
await page.locator('.cm-content').click()
|
||||
await page.keyboard.type('test edit')
|
||||
await page.keyboard.press('Control+s')
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
// 4. Theme CSS vars unchanged
|
||||
expect(await getCssVar(page, '--background')).toBe('#FFFFFF')
|
||||
})
|
||||
})
|
||||
@@ -59,6 +59,8 @@ test.describe('Theme live reload on raw editor save (rework)', () => {
|
||||
'primary: "#155DFF"',
|
||||
'sidebar: "#F7F6F3"',
|
||||
'text-primary: "#37352F"',
|
||||
'lists-bullet-size: 32px',
|
||||
'lists-bullet-color: "#FF0000"',
|
||||
'---',
|
||||
'',
|
||||
'# Default',
|
||||
@@ -81,6 +83,10 @@ test.describe('Theme live reload on raw editor save (rework)', () => {
|
||||
// Verify other vars also updated
|
||||
expect(await getCssVar(page, '--sidebar')).toBe('#F7F6F3')
|
||||
expect(await getCssVar(page, '--foreground')).toBe('#37352F')
|
||||
|
||||
// Verify bullet-size and bullet-color (rework regression)
|
||||
expect(await getCssVar(page, '--lists-bullet-size')).toBe('32px')
|
||||
expect(await getCssVar(page, '--lists-bullet-color')).toBe('#FF0000')
|
||||
})
|
||||
|
||||
test('saving a non-theme note does not affect active theme CSS', async ({ page }) => {
|
||||
|
||||
Reference in New Issue
Block a user