|
| 1 | +import { describe, it, expect } from "vitest"; |
| 2 | +import { readFileSync } from "fs"; |
| 3 | +import { resolve } from "path"; |
| 4 | + |
| 5 | +/** |
| 6 | + * Regression tests for issue #186: UI does not match design spec after PR #185. |
| 7 | + * |
| 8 | + * These tests verify that emoji-picker and page-icon source files comply with |
| 9 | + * the design spec constraints for touch targets, input styling, mobile |
| 10 | + * visibility, and responsive width. |
| 11 | + */ |
| 12 | + |
| 13 | +function readSource(relativePath: string): string { |
| 14 | + return readFileSync(resolve(__dirname, relativePath), "utf-8"); |
| 15 | +} |
| 16 | + |
| 17 | +describe("emoji-picker design spec compliance", () => { |
| 18 | + const source = readSource("./emoji-picker.tsx"); |
| 19 | + |
| 20 | + it("emoji buttons have 44px minimum touch target on mobile", () => { |
| 21 | + // Design spec: "Touch targets: minimum 44px on mobile." |
| 22 | + // Emoji buttons must use min-h-[44px] and min-w-[44px] for mobile. |
| 23 | + expect(source).toContain("min-h-[44px]"); |
| 24 | + expect(source).toContain("min-w-[44px]"); |
| 25 | + }); |
| 26 | + |
| 27 | + it("filter input has border per input spec", () => { |
| 28 | + // Design spec: Inputs should have border-white/[0.06] border. |
| 29 | + const precedingClass = source.match( |
| 30 | + /className="[^"]*border border-white\/\[0\.06\][^"]*"[\s\S]*?aria-label="Filter emojis"/ |
| 31 | + ); |
| 32 | + expect(precedingClass).not.toBeNull(); |
| 33 | + }); |
| 34 | + |
| 35 | + it("filter input has focus ring per input spec", () => { |
| 36 | + // Design spec: Inputs should have ring-2 ring-ring on focus. |
| 37 | + const inputSection = source.match( |
| 38 | + /className="[^"]*"[\s\S]*?aria-label="Filter emojis"/ |
| 39 | + ); |
| 40 | + expect(inputSection).not.toBeNull(); |
| 41 | + expect(inputSection![0]).toContain("focus:ring-2"); |
| 42 | + expect(inputSection![0]).toContain("focus:ring-ring"); |
| 43 | + }); |
| 44 | + |
| 45 | + it("picker uses responsive width to avoid mobile clipping", () => { |
| 46 | + // Design spec: "No horizontal scroll on any breakpoint." |
| 47 | + // The picker must not use a fixed w-72 without a mobile-responsive alternative. |
| 48 | + expect(source).toContain("sm:w-72"); |
| 49 | + // Must have a viewport-relative width for mobile |
| 50 | + expect(source).toMatch(/w-\[calc\(100vw/); |
| 51 | + }); |
| 52 | +}); |
| 53 | + |
| 54 | +describe("page-icon design spec compliance", () => { |
| 55 | + const source = readSource("./page-icon.tsx"); |
| 56 | + |
| 57 | + it("page icon button has 44px minimum touch target on mobile", () => { |
| 58 | + // Design spec: "Touch targets: minimum 44px on mobile." |
| 59 | + expect(source).toContain("min-h-[44px]"); |
| 60 | + expect(source).toContain("min-w-[44px]"); |
| 61 | + }); |
| 62 | + |
| 63 | + it("add-icon button is visible on mobile (not hover-only)", () => { |
| 64 | + // Design spec: Touch targets must be accessible on mobile. |
| 65 | + // The button container must not rely solely on group-hover for visibility. |
| 66 | + // It should use max-sm:opacity-100 or similar to be visible on touch devices. |
| 67 | + expect(source).toContain("max-sm:opacity-100"); |
| 68 | + }); |
| 69 | + |
| 70 | + it("add-icon button has 44px minimum touch target on mobile", () => { |
| 71 | + // The "Add icon" button must meet the 44px minimum on mobile. |
| 72 | + const addIconSection = source.match( |
| 73 | + /aria-label="Add page icon"[\s\S]{0,50}/ |
| 74 | + ); |
| 75 | + expect(addIconSection).not.toBeNull(); |
| 76 | + |
| 77 | + const classSection = source.match( |
| 78 | + /className="[^"]*min-h-\[44px\][^"]*"[\s\S]*?aria-label="Add page icon"/ |
| 79 | + ); |
| 80 | + expect(classSection).not.toBeNull(); |
| 81 | + }); |
| 82 | +}); |
0 commit comments