feat: modernize extension with WXT, TypeScript, and comprehensive testing#4
Merged
justcarlson merged 76 commits intomasterfrom Jan 25, 2026
Merged
Conversation
- STACK.md - Technologies and dependencies - ARCHITECTURE.md - System design and patterns - STRUCTURE.md - Directory layout - CONVENTIONS.md - Code style and patterns - TESTING.md - Test structure - INTEGRATIONS.md - External services - CONCERNS.md - Technical debt and issues
Chrome extension modernization: jQuery/Handlebars removal, TypeScript migration, Vite build system, comprehensive testing, and Chrome Web Store compliance.
Mode: yolo Depth: comprehensive Parallelization: enabled Workflow agents: research=on, plan_check=on, verifier=on Model profile: quality
Files: - STACK.md - FEATURES.md - ARCHITECTURE.md - PITFALLS.md - SUMMARY.md Key findings: - Stack: WXT framework with TypeScript, Vite, Vitest, Playwright - Architecture: Event-driven service workers, storage-first state management - Critical pitfall: Service worker state loss requires storage-based architecture
45 requirements across 7 categories: - Build System (6) - Code Quality (4) - Testing (8) - CI/CD (5) - Web Store Compliance (5) - Git Workflow (6) - Code Migration (10) Plus 6 v2 requirements deferred.
Phases: 1. Build Foundation: WXT/Vite + TypeScript + Biome 2. Core Migration: Service worker + URL matching 3. UI Migration: Popup + welcome to vanilla TS 4. Testing & Quality: Vitest + Playwright + coverage 5. Web Store Compliance: Privacy policy + permissions 6. CI/CD & Automation: GitHub Actions + versioning Git workflow: feature branches, PR merges, phase tags All 38 v1 requirements mapped to phases.
Phase 01: Build Foundation - Implementation decisions documented - Phase boundary established
Phase 1: Build Foundation - Standard stack identified (WXT 0.20.x, TypeScript 5.9.x, Biome 2.3.x) - Architecture patterns documented (entrypoints, config, TypeScript setup) - Pitfalls catalogued (async main, modules conflict, CommonJS, sourcemaps)
Phase 01: Build Foundation - 4 plan(s) in 3 wave(s) - Wave 1: 01-01 (WXT/TS), 01-02 (Biome/Husky) - parallel - Wave 2: 01-03 (static assets) - depends on 01-01 - Wave 3: 01-04 (verification checkpoint) - depends on all - Ready for execution
- Replace Grunt/Webpack dependencies with WXT 0.20.13 - Add TypeScript 5.9.3 and @types/chrome - Set package.json type to module for ESM support - Create wxt.config.ts with manifest configuration - Add minimal background.ts entrypoint for WXT prepare - Generate .wxt/ directory with type definitions Scripts: dev, build, zip, postinstall Permissions: webNavigation, tabs, scripting, storage Host permissions: *.zendesk.com
- Create tsconfig.json extending WXT-generated config - Enable strict mode for all strict type-checking - Set target ES2022 for modern JavaScript features - Add noUncheckedIndexedAccess for safer array/object access - Add noImplicitOverride for explicit method overrides - Enable verbatimModuleSyntax for ESM enforcement
- Add biome.json with recommended rules and tab indentation - Add lint, lint:fix, and format scripts to package.json - Install @biomejs/biome devDependency - Format TypeScript files with Biome style
- Add popup entrypoint with HTML, TypeScript, and CSS - Add welcome page entrypoint with HTML and TypeScript - All entrypoints are placeholders for Phase 3 UI migration - Build produces loadable Chrome extension in .output/chrome-mv3/
- Install husky and lint-staged devDependencies - Add prepare script to initialize Husky - Add lint-staged config for TypeScript and JSON/HTML/CSS files - Create .husky/pre-commit hook running lint-staged
- Add biome.json with recommended rules and tab indentation - Add lint, lint:fix, and format scripts to package.json - Install @biomejs/biome devDependency - Format TypeScript/CSS files with Biome style - Configure exclusions for legacy code, generated files, and planning docs
Tasks completed: 2/2 - Task 1: Configure Biome linter and formatter - Task 2: Set up Husky and lint-staged for pre-commit hooks SUMMARY: .planning/phases/01-build-foundation/01-02-SUMMARY.md
- Copy extension icons (16px, 48px, 128px) to public/images/icons/ - Copy i18n messages to public/_locales/en/messages.json - Add appName and appDescription keys for Chrome i18n - Update wxt.config.ts with icons and default_locale - Use __MSG_appName__ for i18n-aware manifest name
- Install rollup-plugin-visualizer for bundle inspection - Add conditional visualizer plugin in wxt.config.ts (ANALYZE=true) - Add npm run analyze script for on-demand bundle stats - Generate treemap visualization with gzip/brotli sizes
Tasks completed: 2/2 - Move static assets to public directory - Add bundle visualizer for size analysis SUMMARY: .planning/phases/01-build-foundation/01-03-SUMMARY.md
Tasks completed: 2/2 - Run comprehensive build verification (8 checks passed) - Complete Phase 1 human verification (approved) Phase 1 (Build Foundation) complete. SUMMARY: .planning/phases/01-build-foundation/01-04-SUMMARY.md
- 4/4 plans executed successfully - All BUILD-01 through BUILD-06 requirements verified - All QUAL-01 through QUAL-03 requirements verified - Human verified extension loads in Chrome
Phase 02: Core Migration - Implementation decisions documented - Phase boundary established
Phase 2: Core Migration - Standard stack identified (no new deps - Phase 1 sufficient) - Storage-first service worker architecture documented - URL matching TypeScript patterns documented - Pitfalls catalogued (termination, listener registration, serialization)
Phase 02: Core Migration - 4 plan(s) in 3 wave(s) - Wave 1: 02-01, 02-02 (parallel - types/url-matching, storage/tabs wrappers) - Wave 2: 02-03 (service worker implementation) - Wave 3: 02-04 (verification checkpoint) - Ready for execution
- RouteType: 'lotus' | 'ticket' union type - RouteMatch: interface for matched URL with subdomain, path, type - UrlDetectionMode: 'allUrls' | 'ticketUrls' | 'noUrls' union - ZendeskTabInfo: tab tracking interface with subdomain and lastActive - StorageSchema: chrome.storage.local structure definition
- Implement storage-first architecture with loadState/saveState - Add URL detection mode get/set with 'allUrls' default - Add clearState for extension updates - Silent fallback with console.warn on storage errors per CONTEXT.md - Use Record<> not Map for JSON serialization Exports: loadState, saveState, getUrlDetection, setUrlDetection, clearState
- matchZendeskUrl(): Parse URLs with native URL constructor - buildZendeskUrl(): Reconstruct full Zendesk agent URL from RouteMatch - isZendeskAgentUrl(): Quick check for agent interface URLs - Uses pathname only, ignoring query params and hash per CONTEXT.md - Rejects restricted routes (chat, voice, print) - Ticket routes take priority over lotus routes
- Implement focusTab with window.focused for window-to-front behavior - Add updateTabUrl for in-place navigation - Add closeTab with silent ignore on already-closed - Add queryZendeskTabs for agent tab discovery - All operations in try/catch per RESEARCH.md pitfall #3 Exports: focusTab, updateTabUrl, closeTab, queryZendeskTabs
Tasks completed: 2/2 - Task 1: Create shared type definitions - Task 2: Port URL matching logic to TypeScript SUMMARY: .planning/phases/02-core-migration/02-01-SUMMARY.md
Tasks completed: 2/2 - Create type-safe storage wrapper - Create type-safe tabs wrapper SUMMARY: .planning/phases/02-core-migration/02-02-SUMMARY.md
Use fixed dark text color on bright accent background instead of theme-dependent --text variable which becomes light in dark mode.
- All 4 plans executed (design tokens, popup, welcome page, verification) - 5/5 requirements marked complete (MIGR-01, MIGR-02, MIGR-08, MIGR-09, MIGR-10) - Phase goal verified: jQuery/Handlebars fully replaced with vanilla TypeScript - One contrast fix applied during verification (fe6c9ee)
Phase 04: Testing & Quality - Implementation decisions documented - Phase boundary established
Phase 04: Testing & Quality - Standard stack identified (Vitest + WxtVitest + Playwright) - Architecture patterns documented (co-located tests, fixtures) - Pitfalls catalogued (service worker termination, state leaking)
Phase 04: Testing & Quality - 6 plan(s) in 4 wave(s) - Wave 1: test infrastructure setup - Wave 2: unit tests (URL, storage, tabs, background) - Wave 3: E2E tests with Playwright - Wave 4: CI workflow integration - Ready for execution
Address 5 checker issues: - 04-04: Remove Task 1 (export from closure impossible), use behavior testing - 04-06: Add .gitignore to files_modified - 04-01: Add smoke test verifying fake-browser works (TEST-02) - 04-04: Revise must_haves to reflect behavior testing approach - 04-05: Change from Wave 3 to Wave 2 (E2E independent of unit tests) - 04-06: Change from Wave 4 to Wave 3 (correct dependency calculation)
- Add vitest 4.x and @vitest/coverage-v8 for unit testing - Add @playwright/test for E2E testing - Add test, test:coverage, and test:e2e npm scripts
- Configure WxtVitest() plugin for Chrome API mocking - Set v8 coverage provider with text, HTML, and lcov reporters - Define 70% global coverage thresholds - Exclude types.ts and UI entry files from coverage
- Add vitest.setup.ts with fakeBrowser.reset() before each test - Create storage.test.ts smoke test to verify Chrome API mocking (TEST-02) - Confirm fake-browser integration works with WxtVitest plugin
Tasks completed: 3/3 - Install test dependencies - Create Vitest configuration with WXT plugin - Create test setup with mock reset and smoke test SUMMARY: .planning/phases/04-testing-quality/04-01-SUMMARY.md
- Configure testDir as ./e2e for test file location - Single worker with no parallel execution for extension testing - webServer command ensures extension is built before tests - CI-specific retries and github reporter
- Test all 5 exported functions: loadState, saveState, getUrlDetection, setUrlDetection, clearState - Verify default state behavior when storage is empty - Verify state persistence and retrieval roundtrip - Test silent fallback on storage errors (no throws) - Uses fakeBrowser for stateful Chrome API mocking
- Create persistent context with extension loaded via Chrome args - Wait for service worker event to derive extension ID - Per RESEARCH.md Pitfall 4: prevents flaky tests from timing
- Test message handlers via storage observation (getStatus, setMode) - Test storage-first architecture (loadState, saveState, clearState) - Test findMostRecentTab selection logic through storage patterns - 22 tests covering behavior without requiring internal exports
- Test matchZendeskUrl for valid URLs, restricted routes, invalid URLs - Test buildZendeskUrl for URL construction - Test isZendeskAgentUrl for agent vs non-agent URL detection - 41 tests covering subdomain extraction, path normalization, query/hash handling - 96.55% line coverage, 100% function coverage on url-matching.ts
- Test all 4 exported functions: focusTab, updateTabUrl, closeTab, queryZendeskTabs - Verify focusTab activates tab and brings window to front - Verify updateTabUrl returns boolean success for caller cleanup - Test silent error handling when tabs don't exist - Uses vi.spyOn for Chrome tabs API mocking
- Add termination/restart cycle simulation test - Add in-memory state leakage verification test - Add rapid restart cycle stress test - Tests verify storage-first architecture under MV3 constraints
Tasks completed: 2/2 - Task 1: Create URL matching test file with comprehensive coverage - Task 2: Verify edge cases and coverage gaps (verification pass) SUMMARY: .planning/phases/04-testing-quality/04-02-SUMMARY.md
Tasks completed: 3/3 - Create storage module unit tests (16 tests, 100% coverage) - Create tabs module unit tests (11 tests, 100% coverage) - Verify coverage thresholds (both modules at 100%) SUMMARY: .planning/phases/04-testing-quality/04-03-SUMMARY.md
Tasks completed: 2/2 - Task 1: Create background service worker unit tests - Task 2: Test service worker state persistence (TEST-08) SUMMARY: .planning/phases/04-testing-quality/04-04-SUMMARY.md
- Add popup.spec.ts with 3 tests for mode toggle UI - Test popup loads with three mode options - Test mode change persists via clicking labels - Add mock-pages/agent-ticket.html for future navigation tests - Move background.test.ts from entrypoints/ to src/ (WXT conflict)
Tasks completed: 3/3 - Playwright configuration for extension testing - Extension fixtures with service worker waiting - Popup UI E2E tests (3 tests passing) SUMMARY: .planning/phases/04-testing-quality/04-05-SUMMARY.md
- Add lint job running Biome checks on PRs (QUAL-04) - Add test job running unit tests with coverage - Add build job with artifact upload - Add e2e job running Playwright tests after build - Upload coverage, build, and Playwright reports as artifacts
- Add coverage/, playwright-report/, test-results/ to biome excludes - Fix noNonNullAssertion lint errors in welcome/main.ts with setText helper - Exclude entrypoints/background.ts from coverage (tested via behavior tests & E2E) All tests pass locally: lint, unit tests (98.41% coverage), build, E2E.
- Add coverage/ directory (Vitest coverage reports) - Add playwright-report/ directory (Playwright HTML reports) - Add test-results/ directory (Playwright test artifacts)
Tasks completed: 3/3 - Create GitHub Actions CI workflow - Verify all tests pass locally - Add .gitignore entries for test artifacts SUMMARY: .planning/phases/04-testing-quality/04-06-SUMMARY.md Phase 4 (Testing & Quality) complete - 90 unit tests, 3 E2E tests, CI gates.
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.
Summary
Major modernization of QuickTab extension from legacy stack (jQuery 1.6.1, ES5, Grunt) to modern tooling (TypeScript, WXT/Vite, Vitest/Playwright). This PR includes Phases 1-4 of the modernization roadmap.
Phase 1: Build Foundation
Phase 2: Core Migration
Phase 3: UI Migration
Phase 4: Testing & Quality
Test plan
npm run lintpassesnpm run test:coverage -- --runpasses with 70%+ coveragenpm run buildproduces loadable extensionnpm run test:e2epasses popup tests