Poc UI rendering validation#877
Conversation
Documents the design for a testing-only extractor that renders a paywall at a specified viewport/locale/dark-mode and emits a per-component layout JSON matching the cross-platform extractor schema. Approach shares the mount pipeline with presentPaywall so production parity is guaranteed by construction, while the extractor module is gated to be tree-shaken from the published bundle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10-phase TDD plan covering: upstream data attrs in purchases-ui-js, the buildPaywallMountProps refactor, build-time gating, the tree walker / DOM reader / synthesizer / extractor function, installer, Node CLI + Playwright orchestrator, CI guard, and the E2E fixture test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pure helper that resolves locale fallback, builds variablesPerPackage, and parses package info. presentPaywall now calls it; this is the single mount pipeline that the upcoming extractor will share. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mode-gated Vite define for the upcoming dev-only extractor. Production builds evaluate it to false (so Rollup will tree-shake gated branches); dev builds and tests evaluate it to true. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pure generator that yields every component entry from PaywallData. Descends stacks, footers, purchase_button/package wrappers, tabs, carousels, and timelines. Used by the upcoming extractPaywallLayout.
…ge tests Earlier walker yielded a tab's id but used walkStackChildren on its stack, dropping the stack node itself. Switch to walkStack to match how footer/purchase_button/package handle their inner stacks. Add tests for tabs/carousel/timeline/badge to lock in coverage.
Looks up rendered nodes via data-rc-component-id; returns ComponentLayout with frame relative to the container, plus state, nativeType, domTag, and label (for text components). Frames are rounded to integers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Builds an Offering with one blank package per package_id referenced by the paywall data. Used by the extractor when the caller does not supply a real offering; gets rendered through the same paywall mount pipeline with no purchase functionality required. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The synthesizer's local recursion missed packages reachable only via sticky_footer, tabs/control, carousel/pages, or stack.badge. Reuse the walker (which already handles every wrapping type) by adding the original node reference to WalkEntry. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mounts <Paywall> via the shared buildPaywallMountProps pipeline into a sized container, walks the paywall data tree, reads per-component frames from data-rc-component-id elements, returns ExtractedLayout. Also stubs window.matchMedia in vitest.setup.js (jsdom omits it) and fixes fixtureUiConfig/fixturePaywallData to supply the minimal fields the Paywall component requires (app.fonts, a traversable stack). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dev/test builds attach window.__rcExtractPaywallLayout__ via a gated dynamic import; production builds strip the entire dev/ subtree from the bundle via Rollup dead-code elimination. Includes a smoke test that confirms the global is set when the gate is true. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The playground is the page Playwright loads in Task 7.2's Node orchestrator: it imports purchases-js's main entry, which (in dev mode) dynamically imports the extractor installer. Adds three npm scripts (extract, extract:e2e, check-extractor-stripped) whose implementations land in subsequent tasks.
Launches a Vite dev server pointing at scripts/extractor-playground, launches headless Chromium, navigates to the playground page, waits for window.__rcExtractPaywallLayout__ to be installed, calls it via page.evaluate, and writes the returned JSON to the --out path. Also updates extractor-playground/main.ts to import only the extractor installer rather than all of src/main.ts, avoiding TC39 decorator and type-only import issues that crash Playwright Chromium. Adds a devFixupPlugin that replaces __RC_PAYWALL_EXTRACTOR__ at transform time (Vite define only applies at build time, not dev-server mode) and strips any residual decorator lines as a defensive measure. Updates eslint.config.js to allow Node globals and browser globals in scripts/*.mjs files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move browser launch inside try block so Vite server is closed when chromium.launch throws. Validate numeric args (width/height/scale) are positive finite numbers; reject missing flag values upfront. Print a progress line before browser launch.
Reads dist/Purchases.es.js and dist/Purchases.umd.js and exits 1 if 'extractPaywallLayout', 'installExtractor', or '__rcExtractPaywallLayout__' appears in either. Wired as 'pnpm run check-extractor-stripped'.
Runs the full Node orchestrator against a fixture paywall and asserts the output JSON has metadata.platform=web, the required component IDs, and that the title text renders with a non-zero frame. Catches regressions across the entire pipeline: Vite dev server + Playwright + buildPaywallMountProps + walker + reader + JSON output. Also excludes scripts/ from the vitest test runner so the E2E harness is not picked up as a vitest suite (it uses node:assert, not vitest). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add 'Verify extractor was stripped from prod bundle' to the test job (runs check-extractor-stripped after build). Add 'Run paywall layout extractor E2E' to the test-e2e job (Playwright already installed in the image). Refresh api-report to confirm no extractor symbols leaked into the public API. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Make WalkEntry.node optional so test fixtures don't have to set it. - Narrow fixtureUiConfig() return to UIConfig (was Offering['uiConfig']). - Replace the field-by-field prop list in extractPaywallLayout's mount call with ...mountProps so new fields added to PaywallMountProps flow automatically; the production path already uses spread. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Comment |
Generated by 🚫 Danger |
Adds a --offerings <file> (+ optional --offering-id <id>) path to the CLI that normalizes an RC /offerings API response into the extractor's input shape. Synthesizes missing PaywallData.id and default_locale, falls back to an empty ui_config when the response doesn't carry one. Adds ExtractInput.offeringId so the metadata's offeringId can be set without supplying a full Offering object — required because the API response only contains paywall_components, not package data. When an identifier is passed without a full offering, the synthesizer still builds blank packages so buildPaywallMountProps doesn't NPE. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Motivation / Description
Changes introduced
Linear ticket (if any)
Additional comments
running with a local version of purchases-ui-js (currently in a draft pr 289)