feat: improve component discovery, config, and CI#1
Conversation
- Add cpk-e2e.config.ts for configurable target project - Improve component discovery to distinguish types from components - Use Storybook index.json for accurate story matching - Add repository_dispatch trigger to CI for cpk-ui integration - Add review-pr claude command - Fix iframe.html rendering in Playwright tests
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds a configurable E2E runner with Storybook integration, light/dark theme testing, JSON outputs, expanded discovery/coverage tooling, Playwright test updates, CI job split with caching, and new CLI/config exports for targeting arbitrary projects. Changes
Sequence DiagramsequenceDiagram
participant User as User/CI
participant CLI as CLI (scripts/cli.ts)
participant Config as Config (cpk-e2e.config.ts)
participant Discover as Discovery (discover-components.ts)
participant SB as Storybook (build/static)
participant Playwright as Playwright (tests)
participant Report as Reporter (check-coverage / runner)
User->>CLI: run e2e [--skip-build / args]
CLI->>Config: load config
CLI->>Discover: request component discovery (config.targetRoot)
Discover->>SB: fetch index.json / stories.json
SB-->>Discover: StoryInfo[]
Discover-->>CLI: ComponentInfo[], story baseline
alt build required
CLI->>SB: run build (config.storybookBuildCommand)
SB-->>CLI: storybook-static ready
end
CLI->>Playwright: run tests (light + dark, baseURL from config)
Playwright->>SB: load iframe.html?id=...
SB-->>Playwright: rendered story
Playwright->>Playwright: collect errors, take screenshots
Playwright-->>Report: send results
Report-->>User: emit JSON/CLI coverage report
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly upgrades the E2E testing infrastructure by introducing a new, configurable testing setup. It refines the component discovery process to precisely identify React components and leverages Storybook's internal index for more accurate story-to-component mapping. Additionally, it introduces an automated PR review command to streamline development workflows and improves the Playwright testing approach for better performance and stability. Highlights
Changelog
Ignored Files
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request significantly improves the E2E testing framework by introducing a configuration file, enhancing component discovery logic, and optimizing the Playwright tests. The move to a configurable setup with cpk-e2e.config.ts is a great step towards making the tool more adaptable. The component discovery is now much more intelligent, capable of distinguishing real React components from other exports. The test suite is also more robust and faster by directly rendering stories in iframe.html. I've left a few suggestions to further improve the code, mainly around avoiding private APIs and fixed waits in tests for better stability, and refining some of the new discovery logic.
There was a problem hiding this comment.
Pull request overview
This PR enhances the cpk-e2e toolchain around Storybook-driven E2E testing by introducing a configuration file, improving story/component discovery logic, and updating CI to support cpk-ui-driven integration runs.
Changes:
- Added
cpk-e2e.config.tsand updated build/package entrypoints to support a configurable target project layout. - Refactored Storybook E2E tests to fetch stories from
index.json/stories.jsonand render viaiframe.html. - Updated discovery/coverage logic to use Storybook’s index metadata and improved CI with
repository_dispatchand caching.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.build.json | Adjusts build root/include to emit compiled output with preserved folder structure and include the new config source. |
| package.json | Updates published entrypoints (main/types/bin) to match the new dist/scripts/* output layout. |
| cpk-e2e.config.ts | Introduces configurable target paths and options intended to drive the E2E pipeline. |
| cpk-e2e.config.js | Adds a JS version of the config (appears to be a compiled artifact). |
| cpk-e2e.config.d.ts | Adds a declaration file for the config (appears to be a compiled artifact). |
| scripts/run-e2e.ts | Uses the new config for target paths and Storybook build invocation. |
| scripts/discover-components.ts | Adds Storybook index parsing and stronger heuristics to distinguish components vs types/interfaces. |
| scripts/check-coverage.ts | Refactors coverage to use Storybook index metadata and adds JSON output mode. |
| scripts/index.ts | Re-exports new discovery/index types and helpers. |
| tests/components.spec.ts | Switches to Storybook index.json story enumeration and iframe.html rendering for E2E. |
| .github/workflows/ci.yml | Adds repository_dispatch, splits build/e2e jobs, and introduces caching for dependencies, browsers, and Storybook build artifacts. |
| .claude/commands/review-pr.md | Adds a Claude command doc for PR review automation. |
Comments suppressed due to low confidence (1)
scripts/run-e2e.ts:44
- This step runs
scripts/discover-components.tswithout passingTARGET_ROOT/indexPath, butdiscover-components.tsis hardcoded to../../cpk-ui. With the new config, this will still discover from cpk-ui even ifconfig.targetRootchanges. Consider passing target paths into the script (args/env) or refactoring discovery into a function that takes the config.
// Step 1: Discover components
log('📦', 'Discovering components...');
exec('npx tsx scripts/discover-components.ts');
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
- Replace private Playwright API (_options) with baseURL parameter
- Use waitForLoadState('networkidle') instead of fixed waitForTimeout
- Return false instead of true in isActualComponent on file read error
- Precompute storyTitlesArray to avoid rebuilding in loop
- Wire config.ignoredErrors into test IGNORED_ERRORS list
- Remove compiled config artifacts (cpk-e2e.config.js/d.ts) and gitignore them
- Fix hardcoded repo refs in review-pr.md, use {owner}/{repo} placeholders
- Update validation commands to match actual package.json scripts
- Use config for discover-components paths instead of hardcoded values
- Add dark mode tests, improve error boundary handling
- Update CLAUDE.md and README.md documentation
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request significantly refactors the E2E testing tool to enhance configurability and testing capabilities. Key changes include externalizing configuration into a new cpk-e2e.config.ts file, improving component discovery and story coverage checks by leveraging Storybook's index.json and more accurate parsing, and enhancing Playwright tests to directly access story iframes for both light and dark themes with better error handling and screenshot capture. The CLI and documentation have been updated to reflect these changes. The review comments suggest improving the /review-pr command's robustness by dynamically fetching repository information instead of using hardcoded placeholders, and refactoring the light and dark mode test suites to reduce code duplication and improve maintainability.
There was a problem hiding this comment.
Pull request overview
This PR makes the E2E runner configurable for different target projects, expands Playwright coverage to validate both light and dark themes, and updates CI/docs accordingly.
Changes:
- Add a central
cpk-e2e.config.tsand refactor scripts/tests to use it (ignored errors, target root, Storybook build command). - Update Playwright E2E tests to fetch stories from Storybook’s index and run light + dark render/screenshot passes.
- Improve CI workflow triggers and caching; update docs/exports/build settings for packaging.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.build.json | Expands build scope to compile config + scripts into dist/. |
| tests/components.spec.ts | Refactors story fetching + adds light/dark rendering and screenshot capture. |
| scripts/run-e2e.ts | Uses config-driven target root and Storybook build command in the orchestration pipeline. |
| scripts/index.ts | Re-exports additional discovery helpers/types. |
| scripts/discover-components.ts | Adds Storybook index parsing and more robust export classification. |
| scripts/cli.ts | Improves CLI argument forwarding and exit behavior. |
| scripts/check-coverage.ts | Switches to Storybook index-based coverage and adds optional JSON output. |
| README.md | Documents dark mode coverage and new configuration options. |
| playwright.config.ts | Removes global screenshot setting (tests take explicit screenshots). |
| package.json | Adjusts main/types/bin paths to match dist/scripts/* output layout. |
| cpk-e2e.config.ts | Introduces configurable target paths, build command, port, and ignored error patterns. |
| CLAUDE.md | Updates project structure/usage docs to reflect new configuration and dark mode testing. |
| .gitignore | Ignores generated config JS/typings artifacts. |
| .github/workflows/ci.yml | Adds more triggers, splits build/e2e jobs, and introduces caching for faster CI. |
| .claude/commands/review-pr.md | Adds a Claude command doc for reviewing/applying PR feedback. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
- Fix __dirname resolution in discover-components.ts and run-e2e.ts (use process.cwd() so paths work from both tsx and dist/) - Deduplicate Light/Dark test suites into shared testStoriesRender() - Use dynamic repo resolution in review-pr.md (gh repo view) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (2)
.claude/commands/review-pr.md (1)
86-87: Consider extracting common repo lookup once.
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)is duplicated. Define it once and reuse to reduce drift.Also applies to: 95-96
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.claude/commands/review-pr.md around lines 86 - 87, Extract the duplicated repository lookup into a single variable declared once (e.g., REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)) and reuse it for subsequent calls; replace the repeated assignments before the two gh api invocations with references to that single REPO variable so both usages (the gh api "repos/$REPO/pulls/$PR_NUMBER/comments" call and the other gh api call at the later duplicate) read from the same shared variable.scripts/cli.ts (1)
18-18: Consider sanitizing or escaping arguments passed to shell commands.While the current use case involves safe flags like
--jsonand--headed, joining user-provided arguments directly into shell commands could potentially allow shell metacharacter injection if malicious arguments were passed. For robustness, consider usingexecSyncwith an array-based approach or escaping special characters.♻️ Optional: Use spawn with array arguments for safer execution
-import {execSync} from 'child_process'; +import {execSync, spawnSync} from 'child_process'; import * as path from 'path'; const args = process.argv.slice(2); const command = args[0]; -const restArgs = args.slice(1).join(' '); +const restArgs = args.slice(1); const SCRIPTS_DIR = path.resolve(__dirname); -function exec(cmd: string) { +function exec(cmd: string, cmdArgs: string[] = []) { try { - execSync(cmd, {stdio: 'inherit', cwd: process.cwd()}); + const result = spawnSync(cmd, cmdArgs, {stdio: 'inherit', cwd: process.cwd(), shell: true}); + if (result.status !== 0) { + process.exit(result.status ?? 1); + } } catch (err: unknown) { const code = (err as {status?: number}).status ?? 1; process.exit(code); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/cli.ts` at line 18, restArgs is built by joining user arguments (args.slice(1).join(' ')) and then passed to a shell command, which risks shell metacharacter injection; change this to pass arguments as an array to a spawn/spawnSync or execFile/execFileSync call (instead of building a single string) so each token is passed as a distinct argument, or apply a robust escaping utility before joining; update the code that constructs restArgs and the subsequent child_process invocation to use the array form (e.g., keep args.slice(1) as the arg array) and eliminate join(' ') to ensure safe execution.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.claude/commands/review-pr.md:
- Around line 85-86: The comment "Replace OWNER/REPO with the actual repository"
is outdated because the script already sets REPO dynamically using the command
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner); update or remove
that comment near the REPO assignment in .claude/commands/review-pr.md so it
reflects the dynamic resolution (e.g., "Repository is resolved dynamically via
gh repo view") or delete the line to avoid confusion, ensuring the REPO variable
and the gh repo view command remain unchanged.
- Around line 115-119: The GraphQL snippets use single-quoted query bodies so
shell vars $PR_NUMBER and $THREAD_ID are not interpolated; update the gh api
calls that build the GraphQL query (the commands invoking gh api graphql -f
query=...) to use GraphQL variables instead (pass -F prNumber="$PR_NUMBER" and
-F threadId="$THREAD_ID" and declare variables in the query signature like
query($prNumber: Int!, $threadId: ID!) ), then replace inline
$PR_NUMBER/$THREAD_ID occurrences in the query with $prNumber/$threadId and
adjust the selection/mutation fields that reference those variables (e.g., the
pullRequest(number: $prNumber) and thread(id: $threadId) usages) so the shell
interpolation issue is resolved.
- Around line 81-89: The script uses $PR_NUMBER in sections 6.1–6.3 but never
defines it; normalize the input in $ARGUMENTS into PR_NUMBER before any API
calls by invoking the GitHub CLI to resolve the PR (e.g., use `gh pr view` on
"$ARGUMENTS" and extract the numeric .number) and assign that to PR_NUMBER, then
place this assignment near the start of the script before the first usage in the
Get Inline Review Comments block; update the same pattern before the blocks in
6.2 and 6.3 so all calls like gh api "repos/$REPO/pulls/$PR_NUMBER/..." use a
defined PR_NUMBER.
In @.github/workflows/ci.yml:
- Around line 80-86: The "Clone cpk-ui" step currently always checks out default
HEAD; change that step to consume github.event.client_payload.ref or .sha from
the repository_dispatch payload and use it when cloning (or clone then checkout
the provided sha/ref) so dispatched workflows pin the intended cpk-ui revision;
keep the "Get cpk-ui commit hash" step as-is but ensure it runs after the
clone/checkout in the ../cpk-ui directory. Use the step name "Clone cpk-ui" and
reference github.event.client_payload.ref (fallback to github.ref_name) or
github.event.client_payload.sha when implementing the change.
- Around line 98-111: Remove the partial restore behavior and use the cache
step's cache-hit output to decide whether to rebuild: in the "Cache Storybook
build" step (actions/cache@v4) remove the restore-keys field and add an id
(e.g., id: cpk-ui-cache) so you can reference outputs; then update the "Build
cpk-ui Storybook" step to check steps.cpk-ui-cache.outputs.cache-hit (if not
'true' then run cd ../cpk-ui && CI=1 STORYBOOK=1 npx storybook build -o
storybook-static, else echo "Using cached Storybook build") instead of checking
for ../cpk-ui/storybook-static/index.json; keep the same cache path and key but
rely only on exact key hits.
In `@cpk-e2e.config.ts`:
- Around line 8-10: The JSDoc on CpkE2eConfig.targetRoot incorrectly states
paths are "relative to this config file" while scripts/run-e2e.ts resolves them
relative to process.cwd() (see ROOT and TARGET_ROOT); either update the JSDoc to
state that targetRoot is resolved relative to the current working directory
(process.cwd()), or change the resolution in scripts/run-e2e.ts to resolve
targetRoot relative to the config file location (e.g., derive the config file
directory via import.meta.url or the module filename and use path.resolve(dir,
config.targetRoot)); update the CpkE2eConfig.targetRoot comment or the PATH
resolution logic consistently so the doc and implementation match.
In `@scripts/check-coverage.ts`:
- Around line 39-47: The substring fallback in the hasCoverage check is too
permissive (title.includes(nameLower)); change it to match a normalized leaf
story title or use an explicit mapping: for each title in storyTitlesArray
derive a normalizedLeaf (e.g.,
title.split('/').pop().toLowerCase().replace(/[-_]/g, '')) and then check
normalizedLeaf === nameLower (or consult a prebuilt component->story mapping)
instead of title.includes(nameLower); update the logic in the hasCoverage
expression that references storyTitlesArray, nameLower, and comp.hasStory to use
this stricter comparison.
In `@scripts/discover-components.ts`:
- Around line 344-348: The testFiles array currently includes path.join(dir,
'__tests__', `${name}.test.tsx`) but omits pure TypeScript tests under
__tests__; update the testFiles constant to also include path.join(dir,
'__tests__', `${name}.test.ts`) so the helper scans both .test.tsx and .test.ts
in the __tests__ directory (locate the testFiles declaration and add the
additional path.join entry).
- Around line 264-278: The blacklist check that returns false for names ending
with 'Item' is too broad and excludes real components; update the filter in the
block that uses name.endsWith('Item') so it no longer rejects all '*Item' names
— either remove the 'Item' entry from the list or move that specific check to
run after the source-definition check (so actual exported/component definitions
are preserved); edit the code that references name.endsWith('Item') in
scripts/discover-components.ts to implement one of these two options and ensure
legitimate components like ListItem/MenuItem are not filtered out.
In `@tests/components.spec.ts`:
- Around line 159-176: The root-content non-empty render assertion is only
executed when theme === 'light', so move or duplicate that check to run for dark
mode as well: update the block that queries page.locator('#storybook-root,
`#root`') and inspects innerHTML (currently guarded by if (theme === 'light')) so
it executes regardless of theme (or add an explicit branch for theme === 'dark')
and still pushes 'Component rendered empty content' onto the errors array when
innerHTML is empty and errors.length === 0; keep the existing try/catch behavior
and use the same root, rootCount, innerHTML, and errors symbols to locate and
modify the code.
---
Nitpick comments:
In @.claude/commands/review-pr.md:
- Around line 86-87: Extract the duplicated repository lookup into a single
variable declared once (e.g., REPO=$(gh repo view --json nameWithOwner -q
.nameWithOwner)) and reuse it for subsequent calls; replace the repeated
assignments before the two gh api invocations with references to that single
REPO variable so both usages (the gh api "repos/$REPO/pulls/$PR_NUMBER/comments"
call and the other gh api call at the later duplicate) read from the same shared
variable.
In `@scripts/cli.ts`:
- Line 18: restArgs is built by joining user arguments (args.slice(1).join(' '))
and then passed to a shell command, which risks shell metacharacter injection;
change this to pass arguments as an array to a spawn/spawnSync or
execFile/execFileSync call (instead of building a single string) so each token
is passed as a distinct argument, or apply a robust escaping utility before
joining; update the code that constructs restArgs and the subsequent
child_process invocation to use the array form (e.g., keep args.slice(1) as the
arg array) and eliminate join(' ') to ensure safe execution.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 136d07d9-644d-4469-ac1e-1f767151db83
📒 Files selected for processing (15)
.claude/commands/review-pr.md.github/workflows/ci.yml.gitignoreCLAUDE.mdREADME.mdcpk-e2e.config.tspackage.jsonplaywright.config.tsscripts/check-coverage.tsscripts/cli.tsscripts/discover-components.tsscripts/index.tsscripts/run-e2e.tstests/components.spec.tstsconfig.build.json
💤 Files with no reviewable changes (1)
- playwright.config.ts
- Fix command injection in CLI by using execFileSync with array args
- Wrap error collector cleanup in try/finally to prevent listener leaks
- Check non-empty render in both light and dark mode
- Use config.storybookPort in playwright.config.ts instead of hardcoded 6006
- Use config paths for webServer command in playwright.config.ts
- Fix JSDoc: targetRoot is relative to cwd, not config file
- Remove overly broad 'Item' suffix from component blocklist
- Add __tests__/${name}.test.ts to test file scan
- Tighten coverage matching to exact equality (not substring)
- Use lock file hash for cpk-ui deps cache key instead of commit hash
- Add cpk-e2e.config.ts to package.json files for npm publish
- Remove outdated "Replace OWNER/REPO" comment in review-pr.md
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
There was a problem hiding this comment.
♻️ Duplicate comments (2)
.github/workflows/ci.yml (2)
102-115:⚠️ Potential issue | 🟠 MajorRemove
restore-keysand usecache-hitoutput to avoid stale Storybook builds.The
restore-keys: storybook-prefix can restore a Storybook build from a different cpk-ui commit. When a partial restore succeeds,index.jsonexists on disk, so the rebuild is skipped and E2E tests run against an outdated Storybook output.♻️ Suggested fix
- name: Cache Storybook build + id: storybook-cache uses: actions/cache@v4 with: path: ../cpk-ui/storybook-static key: storybook-${{ steps.cpk-ui-hash.outputs.hash }} - restore-keys: storybook- - name: Build cpk-ui Storybook run: | - if [ ! -f ../cpk-ui/storybook-static/index.json ]; then + if [ "${{ steps.storybook-cache.outputs.cache-hit }}" != "true" ]; then cd ../cpk-ui && CI=1 STORYBOOK=1 npx storybook build -o storybook-static else echo "Using cached Storybook build" fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/ci.yml around lines 102 - 115, Remove the restore-keys entry from the "Cache Storybook build" step (actions/cache@v4) and give that step an id (e.g., id: storybook-cache) so you can read its outputs.cache-hit; then change the "Build cpk-ui Storybook" step to rely on the cache-hit output (steps.storybook-cache.outputs.cache-hit) instead of checking for ../cpk-ui/storybook-static/index.json so a partial restore won't skip a fresh build. Ensure the cache key remains storybook-${{ steps.cpk-ui-hash.outputs.hash }} and update the conditional in the build step to run the build when cache-hit != 'true'.
80-86:⚠️ Potential issue | 🟠 MajorConsume
client_payloadfromrepository_dispatchto pin the cpk-ui checkout.When triggered via
repository_dispatch(typecpk-ui-updated), the clone step always fetches the default branch HEAD instead of the specific revision sent in the dispatch payload. This means workflows triggered by cpk-ui may test against a different commit than intended.♻️ Suggested fix
# Clone cpk-ui and get its commit hash for cache key - name: Clone cpk-ui - run: git clone --depth 1 https://github.com/crossplatformkorea/cpk-ui.git ../cpk-ui + run: | + git clone --depth 1 https://github.com/crossplatformkorea/cpk-ui.git ../cpk-ui + if [ -n "${{ github.event.client_payload.sha }}" ]; then + cd ../cpk-ui && git fetch origin ${{ github.event.client_payload.sha }} && git checkout ${{ github.event.client_payload.sha }} + fi
🧹 Nitpick comments (2)
.github/workflows/ci.yml (1)
64-78: Consider using Playwright version in cache key to avoid version mismatches.The Playwright browser cache key uses the entire
bun.lockhash, which may be overly broad. More importantly, therestore-keys: playwright-prefix can restore browsers from a different Playwright version, potentially causing compatibility issues when the cached browsers don't match the installed@playwright/testversion.Consider extracting the Playwright version for a more precise cache key:
♻️ Suggested improvement
+ - name: Get Playwright version + id: playwright-version + run: echo "version=$(npx playwright --version)" >> "$GITHUB_OUTPUT" + - name: Cache Playwright browsers id: playwright-cache uses: actions/cache@v4 with: path: ~/.cache/ms-playwright - key: playwright-${{ hashFiles('bun.lock') }} - restore-keys: playwright- + key: playwright-${{ steps.playwright-version.outputs.version }}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/ci.yml around lines 64 - 78, The Playwright browser cache key can mismatch Playwright versions; update the workflow to include the Playwright version in the cache key and restore-keys so cached browsers match the installed `@playwright/test` version: add a step that determines the Playwright version (e.g., from package.json or via npx/playwright) and exports it to the environment, then change the cache step key from playwright-${{ hashFiles('bun.lock') }} to include that version (e.g., playwright-${{ env.PLAYWRIGHT_VERSION }}-${{ hashFiles('bun.lock') }}) and update restore-keys to playwright-${{ env.PLAYWRIGHT_VERSION }}- so restore only uses same-version caches; keep the existing install/restore conditionals (steps named "Cache Playwright browsers", "Install Playwright browsers", "Install Playwright system deps") intact.scripts/discover-components.ts (1)
283-298: Static analysis ReDoS warning is a false positive in this context.The ast-grep warnings flag potential ReDoS from variable-interpolated regexes. However,
nameoriginates from parsed component identifiers in your own source files (not user input), and the patterns are linear (no nested quantifiers). The risk is negligible for this build-time tool.If you want to suppress the warning explicitly, you could pre-validate that
namematches/^[A-Za-z_$][A-Za-z0-9_$]*$/(valid JS identifier) before interpolation, but this is optional.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/discover-components.ts` around lines 283 - 298, The interpolated regexes in compPatterns (constructed using the variable name) are triggering static ReDoS warnings; to fix, validate the name before interpolation in the code that builds compPatterns (the variable name used there) by ensuring it matches a JS identifier pattern like /^[A-Za-z_$][A-Za-z0-9_$]*$/ and only build the RegExp entries when the check passes (or alternatively escape the name with a safe escape function before creating RegExp); update the code that constructs compPatterns to perform this pre-validation (or escaping) so the interpolated values are provably safe to include in new RegExp(...) calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In @.github/workflows/ci.yml:
- Around line 102-115: Remove the restore-keys entry from the "Cache Storybook
build" step (actions/cache@v4) and give that step an id (e.g., id:
storybook-cache) so you can read its outputs.cache-hit; then change the "Build
cpk-ui Storybook" step to rely on the cache-hit output
(steps.storybook-cache.outputs.cache-hit) instead of checking for
../cpk-ui/storybook-static/index.json so a partial restore won't skip a fresh
build. Ensure the cache key remains storybook-${{ steps.cpk-ui-hash.outputs.hash
}} and update the conditional in the build step to run the build when cache-hit
!= 'true'.
---
Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 64-78: The Playwright browser cache key can mismatch Playwright
versions; update the workflow to include the Playwright version in the cache key
and restore-keys so cached browsers match the installed `@playwright/test`
version: add a step that determines the Playwright version (e.g., from
package.json or via npx/playwright) and exports it to the environment, then
change the cache step key from playwright-${{ hashFiles('bun.lock') }} to
include that version (e.g., playwright-${{ env.PLAYWRIGHT_VERSION }}-${{
hashFiles('bun.lock') }}) and update restore-keys to playwright-${{
env.PLAYWRIGHT_VERSION }}- so restore only uses same-version caches; keep the
existing install/restore conditionals (steps named "Cache Playwright browsers",
"Install Playwright browsers", "Install Playwright system deps") intact.
In `@scripts/discover-components.ts`:
- Around line 283-298: The interpolated regexes in compPatterns (constructed
using the variable name) are triggering static ReDoS warnings; to fix, validate
the name before interpolation in the code that builds compPatterns (the variable
name used there) by ensuring it matches a JS identifier pattern like
/^[A-Za-z_$][A-Za-z0-9_$]*$/ and only build the RegExp entries when the check
passes (or alternatively escape the name with a safe escape function before
creating RegExp); update the code that constructs compPatterns to perform this
pre-validation (or escaping) so the interpolated values are provably safe to
include in new RegExp(...) calls.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ea7c6d49-8731-49db-9aee-982053585973
📒 Files selected for processing (9)
.claude/commands/review-pr.md.github/workflows/ci.ymlcpk-e2e.config.tspackage.jsonplaywright.config.tsscripts/check-coverage.tsscripts/cli.tsscripts/discover-components.tstests/components.spec.ts
✅ Files skipped from review due to trivial changes (1)
- .claude/commands/review-pr.md
🚧 Files skipped from review as they are similar to previous changes (1)
- playwright.config.ts
There was a problem hiding this comment.
Pull request overview
This PR makes the E2E runner more configurable (via a new cpk-e2e.config.ts) and expands Storybook render testing to cover both light and dark themes while updating the tooling/CI around it.
Changes:
- Add
cpk-e2e.config.tsand wire it into scripts + Playwright config (target paths, Storybook build command, port, ignored errors). - Update Playwright E2E tests to fetch stories from
index.jsonand run each story in both light/dark mode (including themed screenshots). - Refactor/extend component discovery + coverage checks to use Storybook’s built index when available; update CI caching and docs.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.build.json | Compiles from repo root and includes the new config file in the build. |
| tests/components.spec.ts | Switches to /iframe.html?id= and adds light/dark render + screenshot coverage. |
| scripts/run-e2e.ts | Makes Storybook build target configurable and updates runner output. |
| scripts/index.ts | Exposes new discovery/Storybook index helpers from the scripts entrypoint. |
| scripts/discover-components.ts | Adds Storybook index reading and more robust export/star-export parsing. |
| scripts/cli.ts | Switches to execFileSync for safer argument handling and adds --json forwarding. |
| scripts/check-coverage.ts | Uses Storybook index + adds --json output mode for coverage reporting. |
| README.md | Documents dark-mode testing, JSON outputs, and the new configuration file. |
| playwright.config.ts | Uses configurable port/paths for baseURL and webServer command. |
| package.json | Adjusts published entrypoints/bin paths and includes cpk-e2e.config.ts in package files. |
| cpk-e2e.config.ts | New centralized configuration for target paths/options. |
| CLAUDE.md | Updates project docs to reflect new config + dark-mode testing and structure. |
| .gitignore | Ignores generated config JS/DTS artifacts. |
| .github/workflows/ci.yml | Splits build/e2e jobs and adds caching for Playwright + cpk-ui deps + Storybook build. |
| .claude/commands/review-pr.md | Adds a Claude command doc for reviewing PRs via gh. |
Comments suppressed due to low confidence (1)
scripts/run-e2e.ts:45
run-e2e.tsshells out tonpx tsx scripts/discover-components.ts, which won't exist (and requirestsx) when running the built package viadist/scripts/run-e2e.js(the CLI points to dist). Consider invoking the compiled JS indist/scripts(via__dirname) or importing/calling the underlying functions directly socpk-e2e runworks afterbun run build/npm publish.
// Step 1: Discover components
log('📦', 'Discovering components...');
exec('npx tsx scripts/discover-components.ts');
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
- Rename CPK_UI_ROOT to TARGET_ROOT in discover-components.ts - Update file header to say "target project" instead of "cpk-ui" - Use explicit hasErrorOverlay flag instead of errors.length proxy - Rename header in run-e2e.ts to generic "E2E Test Runner" Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Summary
cpk-e2e.config.tsfor configurable target project pathindex.jsonfor accurate story matchingrepository_dispatchtrigger to CI for cpk-ui integrationreview-prclaude commandiframe.htmlrendering in Playwright testsTest plan
bun run discoverto verify component discoverybun run testto verify E2E tests passbun run buildto verify package buildsSummary by CodeRabbit
New Features
Tests
Chores
Documentation