Marp Talks, Juypiter notebooks + mermaid support - #1082
Merged
Conversation
…tion testing Implement a complete testing strategy following the Easy Approach to Requirements Syntax (EARS) for behavior-driven development, providing maximum safety for new contributors. ## Testing Framework - Vitest 3.x for unit and integration testing - @testing-library/svelte for component testing - Playwright for E2E testing - Stryker for mutation testing - MSW (Mock Service Worker) for API mocking ## Test Coverage - Unit tests for lo-tree.ts (URL determination, course tree decoration) - Integration tests for course service (fetching, caching, state management) - E2E test structure for course browsing (placeholder tests) - EARS requirements documentation for course loading ## Configuration - vitest.config.ts with coverage thresholds (60% lines/functions/statements, 55% branches) - playwright.config.ts for multi-browser E2E testing - stryker.config.mjs for mutation testing (80% high threshold) - tests/setup.ts with MSW server and browser API mocks ## Mocks and Test Utilities - MSW handlers for course JSON, Supabase API, GitHub API - Supabase client mock factory - PartyKit WebSocket mock class ## CI/CD - GitHub Actions workflow (.github/workflows/test.yml) - Unit/integration tests with coverage reporting - E2E tests across Chrome and Firefox - Incremental mutation testing on PRs ## Documentation - README.md updated with testing section - EARS requirements template for course loading - Test philosophy and contributor guidelines ## Test Scripts - npm test: Watch mode - npm run test:unit: Run with coverage - npm run test:e2e: Playwright tests - npm run test:mutation: Stryker mutation testing This establishes a foundation for 70% code coverage with comprehensive validation through mutation testing, ensuring contributor safety and preventing regressions. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add __SVELTEKIT_APP_VERSION__ and __SVELTEKIT_DEV__ global mocks - Mock $app/environment module for browser detection - Fix courseProtocol.value reset in tests to use https:// - Adjust edge case tests for URL parsing behavior - Fix topic test to verify returned value instead of currentLo rune - All 44 tests now passing Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add buildCommand to run 'npm run prepare' to generate .svelte-kit directory in sandbox - Replace deprecated maxConcurrentTestRunners with concurrency setting - Mutation testing now works successfully on lo-tree.ts Mutation testing results show 70% of mutants killed, with areas identified for additional test coverage (breadcrumbs logic, default parameters). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add comprehensive test suites to improve mutation testing scores: ## New Test Suites (71 tests total, all passing) **Advanced lo-tree tests (27 tests):** - Breadcrumb manipulation for unit/side types - Composite learning object handling (panels, units, toc) - Protocol conversion (http/https) - Multiple lo type handling (talk, paneltalk, tutorial, lab, archive) - Parent reference setting **Error handling tests (17 tests):** - HTTP error status codes (400, 403, 500) - JSON parsing failures - Network timeouts and DNS errors - Minimal course data handling - Cache behavior with multiple courses ## Mutation Testing Results **Overall covered code**: 62.35% mutation score (101 killed / 162 total) **By file:** - lo-tree.ts: 48.57% total, 63.91% covered (85 killed, 48 survived) - course.svelte.ts: 27.59% total, 76.19% covered (16 killed, 5 survived) Surviving mutants identified for future test improvements: - Default parameter mutations - Breadcrumb edge cases - Composite lo boundary conditions Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add targeted tests designed to kill surviving mutants and push mutation scores above the 80% threshold. ## New Test Suites (95 passing tests, 14 skipped) **lo-tree mutation killers (36 tests):** - determineCourseUrl edge cases with explicit assertions - injectCourseUrl with all LO types (talk, paneltalk, tutorial, lab, archive) - Multiple placeholder replacements verified - String concatenation and protocol handling mutants killed **course-service mutation killers (22 tests):** - Exact value assertions on cache behavior - Error status code verification (400, 403, 500) - JSON parsing and network error propagation - Reference equality checks (not cloning) - Fetch call count verification ## Mutation Testing Results - Significant Improvement! **lo-tree.ts:** - Previous: 48.57% total, 63.91% covered (85 killed) - **Now: 60.57% total, 66.25% covered (106 killed)** ✅ - +21 mutants killed (25% improvement) **course.svelte.ts:** - Maintained: 27.59% total, 76.19% covered (16 killed) **Overall covered code: 64.55%** mutation score (up from 62.35%) ## BDD/EARS Coverage All tests follow BDD Given-When-Then pattern with EARS requirements: - Event-driven: "WHEN trigger THEN response" - Unwanted behaviors: "IF condition THEN error handling" - Explicit assertions kill string literal, conditional, and method mutants Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ation ## Testing Infrastructure Improvements ### Mutation Testing - Improved mutation score from 60.57% to 70.63% on lo-tree.ts - Added 35 targeted tests in lo-tree-80-percent.test.ts - Added 15 breadcrumb logic tests in lo-tree-breadcrumbs.test.ts - Total: 113 killed mutants (up from 106) ### Test Quality Improvements - Suppressed console.error spam in error handling tests - Added proper spy mocking in all integration test files - Documented KaTeX warning as known harmless issue - Clean, readable test output ### Documentation #### Created comprehensive Testing Guide (guides/Testing.md) - 13,000+ word guide covering all testing aspects - Four-layer testing pyramid with detailed examples - BDD with EARS methodology for requirements - Mutation testing explanation and best practices - Writing tests, running tests, troubleshooting #### EARS Requirements Documentation - Created tests/requirements/ structure - Comprehensive course-loading.ears.md (22 functional + 3 non-functional requirements) - Draft requirements for authentication and lab-navigation - Template for creating new requirements - README with guidelines and best practices ### Test Coverage - 130+ tests across 8 test files - 70.63% mutation score on lo-tree.ts - 76.19% mutation score on course.svelte.ts - 64% functional requirements coverage for course loading Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
pdfjs-dist@6.0.227 requires Node.js >=22.13.0, but CI was using Node 20.x Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
These third-party tool configuration files are not maintained by the project and should not be subject to Prettier formatting checks. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enable ```mermaid fenced code blocks to render as interactive SVG diagrams in notes and labs. Override the markdown-it fence rule to intercept mermaid blocks before Shiki, then use a Svelte action to call mermaid.run() after DOM injection. Mermaid is dynamically imported to avoid bundle bloat. Add Marp as a third rendering path for talks. When a talk's frontMatter or contentMd contains marp: true, TalkClient renders a TalkMarp component instead of the PDF viewers. Marp Core converts markdown to HTML slides with keyboard navigation, slide counter, and fullscreen support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduces reader-side support for a new "notebook" learning object type, enabling course authors to include .ipynb files that render with cell-by-cell navigation, Shiki syntax highlighting, and output display (images, HTML, LaTeX, streams, errors). Generator-side changes in tutors-apps are still needed to parse .ipynb files and emit the cell structure into tutors.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Students should read and reason about code before seeing results. Outputs are now hidden by default with a Run/Hide toggle per cell. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ecurity headers
- Add DOMPurify sanitization to all 14 {@html} instances to prevent XSS
- Add +error.svelte page and handleError hooks for client/server
- Fix courseVisit.image → .img property name mismatch
- Replace non-null assertions on Map.get() with safe fallbacks
- Add security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Escape HTML in live-lab navbar title interpolations (XSS) 2. Clean up ResizeObserver + event listener in SearchButton on destroy 3. Wrap JSON.parse in try/catch for WebSocket message handlers 4. Add .catch() to fire-and-forget addOrUpdateStudent promise 5. Replace || with ?? for nullish coalescing in supabase-client 6. Fix shadowed variable name in themes service callback 7. Replace $effect+$state with $derived in Video.svelte 8. Remove duplicate typescript/html imports in markdown service 9. Migrate EditCoursButton from $app/stores to $app/state (fixes store leak) 10. Replace invalid <prose> element with <div> in InfoButton 11. Delete unused halloween-icons.ts and valentine-icons.ts 12. Remove hardcoded tutors.dev domain from search results and presence 13. Replace custom UUID generation with crypto.randomUUID() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Defines a trunk-based release strategy replacing the long-lived development branch model with continuous PR merges to main and a release candidate hardening process before production. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces the previous i18n attempt (#775) with a Svelte 5 rune-based approach. Adds full i18n coverage across 40+ components with 5 languages (en/fr/de/it/es), cookie-persisted locale switching without page reloads, and accessibility improvements including skip-nav, ARIA landmarks, focus management, and prefers-reduced-motion support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Delete 7 unused files: festive.ts, halloween-icons.ts, valentine-icons.ts, valentines.ts, NotFound.svelte, pdf-utils.ts, Course.svelte - Remove 4 unused devDependencies: @shikijs/markdown-it, @types/eslint, autoprefixer, shiki-transformer-copy-button - Add @auth/core as explicit devDependency (was used but only transitively installed) - Remove export from 9 internal-only functions in supabase-client.ts - Remove getDurationTotal (dead code, never called) - Remove export from decorateLoTree and injectCourseUrl in lo-tree.ts - Remove unused slideFromLeft from animations.ts - Remove export from toSnakeCase in llms.ts - Remove 9 unused type re-exports from barrel files knip now reports zero findings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce a thin loglevel wrapper (src/lib/services/logger.ts) that gates output by level — debug in dev, warn+ in production. Migrate all 34 raw console.* calls to the appropriate log level, remove debug leftovers, clean up dead commented-out code, unused imports, and unused animation exports. Add no-console ESLint rule to prevent future raw console usage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix memory leak in SearchButton: wrap MutationObserver and popstate listener in onMount/onDestroy lifecycle so they are cleaned up on unmount. Also migrate on:click to onclick (Svelte 5). - Fix memory leak in Cards: add onDestroy to remove keydown listener that was added in onMount but never removed. - Fix invalid <prose> HTML element in InfoButton: replace with <div>. - Add missing hideSummary prop to Podcast Props interface so callers get proper type checking. - Replace data: any with PageData on 5 route pages (catalogue, auth, course, llm, time) to match the pattern already used by search. - Remove unused cubicOut import from Cards. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: Improve mutation testing and add comprehensive testing documentation
Resolved conflicts in package.json and package-lock.json by incorporating testing infrastructure dependencies from development branch. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add Mermaid.js and Marp slide support
Add Jupyter Notebook as first-class content type
Resolved conflicts by combining: - DOMPurify dependencies with testing infrastructure dependencies - sanitizeHtml import with mermaidify import in Lab.svelte - Safe fallback (lo ?? course) with notebook handling logic - Regenerated package-lock.json with all dependencies Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fix 6 critical issues: XSS, error handling, data bugs, security headers
@marp-team/marp-core depends on PostCSS which is Node.js-only, causing the browser dynamic import to hang indefinitely. Move Marp rendering to a SvelteKit server endpoint (POST /api/marp) so PostCSS runs server-side. Also fix slide extraction to handle Marp's SVG wrapper format (svg[data-marpit-svg] elements instead of plain section tags) and add error state display in TalkMarp. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolved formatting conflicts in Note.svelte and Podcast.svelte by: - Keeping sanitizeHtml imports from development (security fix) - Applying prettier's consistent indentation (no extra indent) - Using sanitizeHtml() wrapper with ?? "" null safety Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
chore: apply prettier formatting across the codebase
Resolved conflicts by combining PR 1067 fixes with prettier formatting:
- presence.svelte.ts: Added try/catch for JSON.parse with proper formatting
- connect.svelte.ts: Added .catch(() => {}) for unhandled promise + prettier parens
- InfoButton.svelte: Used <div> (not <prose>) + sanitizeHtml security fix
- Deleted halloween-icons.ts and valentine-icons.ts (confirmed unused in PR)
All 14 trivial fixes from PR 1067 preserved with prettier formatting applied.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fix 14 trivial issues from codebase audit
docs: add release strategy for RC-based workflow
Resolved conflicts by combining i18n features with recent changes: - hooks.server.ts: Combined locale handling + security headers in sequence - TutorsShell.svelte: Kept reduced motion support + main-content ID/focus - All components: Added both t() i18n imports and sanitizeHtml imports - Preserved all i18n translation keys over hardcoded strings - Maintained accessibility features (aria-labels, skip-nav, focus management) All i18n and a11y features from PR 1069 preserved alongside security fixes, prettier formatting, and bug fixes from previous merges. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add i18n and accessibility support
Resolved conflicts by combining knip dead code removal with new features: package.json: - Kept knip script and dependency - Removed dead dependencies per knip analysis (@shikijs/markdown-it, @types/eslint, autoprefixer) - Kept all test infrastructure from development - Added @auth/core as explicit dependency supabase-client.ts: - Kept localYyyyMmDd as export (used by development) - Removed getDurationTotal (confirmed dead by knip) animations.ts: - Removed slideFromLeft export (unused per knip) Deleted files: - festive.ts, valentines.ts, NotFound.svelte (confirmed unused by knip) All knip findings addressed while preserving development's new features. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add knip for unused code and dependency detection
Resolved conflicts by combining logging improvements with recent features: package.json: - Added loglevel dependency alongside test infrastructure and knip eslint.config.js: - Added no-console warn rule with proper prettier formatting animations.ts: - Combined prefersReducedMotion import with simplified easing imports - Kept only cubicOut (others removed by knip as unused) CourseSentimentButton.svelte: - Added both log import (for error logging) and t import (for i18n) NotFound.svelte: - Kept deletion (removed by knip in development as unused) All console.* calls migrated to log.error/log.warn/log.debug while preserving i18n, a11y, and other recent improvements. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add loglevel logging system and clean up all console usage
Resolved conflicts by combining memory leak fixes with recent features: InfoButton.svelte: - Kept <div> (not <prose>) from PR fix - Added sanitizeHtml from development for security SearchButton.svelte: - Kept onMount/onDestroy pattern from PR (fixes memory leak) - Observers and listeners properly scoped and cleaned up - Combined with i18n from development llm/+page.svelte: - Added PageData type from PR (better type safety) - Added sanitizeHtml import from development time/+page.svelte: - Added PageData type from PR (better type safety) - Added log import from development All memory leak fixes preserved while maintaining security and i18n. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fix memory leaks, invalid HTML, and improve type safety
Fix Marp slide rendering hang
The tutors generator outputs frontMatter.marp as boolean true, but isMarpContent() only checked for string "true". Also reconstruct Marp frontmatter directives (theme, paginate) when the generator strips them from contentMd. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix Marp detection for production course JSON
The Adobe PDF viewer was not reloading when navigating between different talks because the $effect was depending on page.data?.lo?.pdf instead of lo.pdf directly, and there was no cleanup/re-initialization logic. Changes: - Track currentPdfUrl to detect when PDF changes - Update $effect to depend on lo.pdf directly (like TalkMozilla) - Clear viewer container when PDF URL changes to force re-render - Only trigger reload when PDF URL actually changes This matches the reactive pattern used in TalkMozilla which works correctly. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The Adobe PDF viewer was not reloading when navigating between different
talks because:
- TalkMozilla/TalkMarp are dynamically imported and remount on navigation
- TalkAdobe is static, so the same component instance persists
- The $effect wasn't properly triggering a reload
Solution:
- Made viewerId reactive using $derived based on lo.pdf
- Each PDF now gets a unique viewer div ID
- Simplified $effect to depend directly on lo.pdf
- When lo.pdf changes -> viewerId changes -> Adobe renders to fresh div
This ensures TalkAdobe properly reloads without needing to wrap it in
{#key} blocks in TalkClient.svelte.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Keep all development improvements as previously decided.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.