Skip to content

T-J92O-md-test-apps

State: closed/done · Impact: high · Complexity: medium

Neither the engine nor the layer can be run in a browser without a product around it, so every visual or performance check today goes through the notes product. This task adds two test apps: a Vite demo that exercises the engine in isolation and a Nuxt playground that exercises every layer component, each with Playwright and the shared performance harness the budgets are measured with.

LocationRole today
packages/ts/json-canvas-vue/demo/Precedent: Vite + TS demo nested in its library, moon.yml, playwright.config.ts booting the dev server, e2e specs under tests/
packages/ts/obsidian-bases/demo/Precedent: Nuxt demo nested in its library
.moon/workspace.ymlsources: registers nested demo projects (json-canvas-demo) because the packages/ts/* glob stops at the parent
package.jsonRoot workspaces lists packages/ts/json-canvas-vue/demo and packages/ts/obsidian-bases/demo explicitly
packages/ts/obsidian-md/test/fixtures/every-feature.mdThe fixture the demo ships until the corpus lands
packages/ts/ui/playwright.config.tsChromium and WebKit project shape

The corpus fixtures and headless bench come from T-0GV4-md-engine-line-endings-corpus; the layer comes from T-A0HT-md-ui-layer-skeleton.

AppPurposeShape
packages/ts/obsidian-editor/demo/Engine in isolation: corpus fixture picker, mode switch, plugin toggles (omit), bench tab running the bench cases in the browser, a Vue tab mounting useObsidianEditorVite + TS with @vitejs/plugin-vue for the Vue tab; moon.yml (check, build, e2e); root workspaces entry; moon source obsidian-editor-demo; dev port 4781
packages/ts/markdown-ui/playground/Layer in isolation: one page per Md* component, a fixture vault, large-note fixtures, Playwright e2e and perfNuxt app extends: ['@sksizer/markdown-ui'], ssr: false; moon.yml (check, e2e, perf); root workspaces entry; moon source markdown-ui-playground; dev port 4893

Playground fixtures under packages/ts/markdown-ui/playground/fixtures/: vault/ (ten notes with wikilinks, embeds, tags, a table, math, mermaid, <details>), generate.ts writes large/lines-2000.md, large/lines-10000.md and large/bytes-600k.md (deterministic content, committed), provider.ts is an in-memory MarkdownProvider with loadNote, saveAttachment (object URLs) and onInvalidate.

Perf harness packages/ts/markdown-ui/playground/tests/perf-harness.ts:

measure(page, name, fn): Promise<number> // performance.mark/measure around fn, returns ms
collectLongTasks(page): Promise<LongTask[]> // PerformanceObserver('longtask') buffer
heapUsed(page): Promise<number> // CDP Performance.getMetrics JSHeapUsedSize
withTrace(page, name, fn) // saves a Chromium trace under test-results/traces/

packages/ts/markdown-ui/playground/tests/perf.e2e.ts ships with one case (open lines-2000.md in live mode, first paint under 300 ms) as the harness proof; the full budget matrix is T-I630-md-ui-playground-e2e-perf. playground-smoke.e2e.ts opens every component page and asserts it renders. demo-smoke.e2e.ts loads each corpus fixture and switches modes.

  1. Scaffold the demo (package.json, vite.config.ts, index.html, src/main.ts, src/vue-tab.ts, moon.yml, playwright.config.ts, tsconfig.json); import corpus fixtures with import.meta.glob; wire the bench tab to the bench runner’s exported cases.
  2. Register the demo in root package.json workspaces and .moon/workspace.yml sources; bun install; moon run obsidian-editor-demo:check.
  3. Scaffold the playground (package.json, nuxt.config.ts, app/app.vue, app/pages/index.vue, one page per component: surface, viewer, mode-toggle, mermaid; moon.yml, playwright.config.ts, tsconfig.json).
  4. Write the fixture vault, generate.ts, the generated large files, and provider.ts.
  5. Write perf-harness.ts, perf.e2e.ts (one case), playground-smoke.e2e.ts.
  6. Register the playground in root workspaces and moon sources; bun install; moon run markdown-ui-playground:check.
  7. Run both e2e suites locally (bunx playwright install chromium once).
LocationKindChange
packages/ts/obsidian-editor/demo/package.jsonnewVite app manifest
packages/ts/obsidian-editor/demo/vite.config.tsnewVue plugin, port 4781
packages/ts/obsidian-editor/demo/index.htmlnewEntry
packages/ts/obsidian-editor/demo/src/main.tsnewFixture picker, mode switch, plugin toggles, bench tab
packages/ts/obsidian-editor/demo/src/vue-tab.tsnewMounts useObsidianEditor
packages/ts/obsidian-editor/demo/moon.ymlnewcheck, build, e2e
packages/ts/obsidian-editor/demo/playwright.config.tsnewBoots bun run dev
packages/ts/obsidian-editor/demo/tests/demo-smoke.e2e.tsnewLoads fixtures, switches modes
packages/ts/obsidian-editor/demo/tsconfig.jsonnewVite TS config
packages/ts/markdown-ui/playground/package.jsonnewNuxt app manifest
packages/ts/markdown-ui/playground/nuxt.config.tsnewextends: ['@sksizer/markdown-ui'], ssr: false, port 4893
packages/ts/markdown-ui/playground/app/app.vuenewNav over component pages
packages/ts/markdown-ui/playground/app/pages/index.vuenewIndex
packages/ts/markdown-ui/playground/app/pages/surface.vuenewMdSurface over the fixture vault and the large notes
packages/ts/markdown-ui/playground/app/pages/viewer.vuenewMdViewer
packages/ts/markdown-ui/playground/app/pages/mode-toggle.vuenewMdModeToggle
packages/ts/markdown-ui/playground/app/pages/mermaid.vuenewMdMermaidBlock in light and dark
packages/ts/markdown-ui/playground/fixtures/vault/newTen notes
packages/ts/markdown-ui/playground/fixtures/generate.tsnewWrites the large fixtures
packages/ts/markdown-ui/playground/fixtures/large/newlines-2000.md, lines-10000.md, bytes-600k.md
packages/ts/markdown-ui/playground/fixtures/provider.tsnewIn-memory MarkdownProvider
packages/ts/markdown-ui/playground/tests/perf-harness.tsnewmeasure, collectLongTasks, heapUsed, withTrace
packages/ts/markdown-ui/playground/tests/perf.e2e.tsnewOne budget case
packages/ts/markdown-ui/playground/tests/playground-smoke.e2e.tsnewEvery page renders
packages/ts/markdown-ui/playground/moon.ymlnewcheck, e2e, perf
packages/ts/markdown-ui/playground/playwright.config.tsnewBoots nuxt dev, Chromium
packages/ts/markdown-ui/playground/tsconfig.jsonnewNuxt TS config
package.jsonmodifyTwo workspaces entries
.moon/workspace.ymlmodifyobsidian-editor-demo, markdown-ui-playground sources
packages/ts/obsidian-editor/README.mdmodify”Testing” names the demo

The layer README from T-A0HT-md-ui-layer-skeleton gains a section naming the playground and how to run e2e and perf.

  • AC-1: moon run obsidian-editor-demo:check markdown-ui-playground:check passes.
  • AC-2: moon run obsidian-editor-demo:e2e passes: each corpus fixture loads and live → source → live keeps the document text.
  • AC-3: moon run markdown-ui-playground:e2e passes: the four component pages (surface, viewer, mode-toggle, mermaid) render their component root (.md-surface, .md-reading, [data-testid="md-mode-toggle"], .obsmd-mermaid).
  • AC-4: moon run markdown-ui-playground:perf runs the perf spec; the 2 000-line live open case measures under 300 ms and a trace file exists under the playground’s test-results/traces/.
  • AC-5: the harness exports measure, collectLongTasks, heapUsed, withTrace, each exercised by the perf spec.
  • AC-6: bun install --frozen-lockfile at the root succeeds and bun pm ls lists @sksizer/obsidian-editor-demo and @sksizer/markdown-ui-playground.
  • AC-7: generate.ts is deterministic: running it twice leaves git status clean.
  • AC-8: grep -rn "from '@nuxt/ui'" packages/ts/markdown-ui/playground/app returns nothing.
  • T-A0HT-md-ui-layer-skeleton for the layer the playground extends.
  • The demo’s fixture picker and bench tab read T-0GV4-md-engine-line-endings-corpus’s corpus and bench; until it lands the demo ships with the every-feature fixture alone and no bench tab.
  • S-0010: the playground extends the layer and imports no @nuxt/ui directly.

Member of milestone M-931L; the test apps section of decision D-K3EM-markdown-editor-chrome-and-plugin-environment.

T-A0HT-md-ui-layer-skeleton


← Back to Tasks