Skip to content

SDKS-5127: Core DaVinci Integration and Form Fields#57

Open
tsdamas wants to merge 6 commits into
mainfrom
SDKS-5127
Open

SDKS-5127: Core DaVinci Integration and Form Fields#57
tsdamas wants to merge 6 commits into
mainfrom
SDKS-5127

Conversation

@tsdamas

@tsdamas tsdamas commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds the @ping-identity/rn-davinci package — a DaVinci orchestration bridge for React Native, supporting both New Architecture (TurboModule) and classic bridge on iOS and Android.
  • Provides an imperative createDaVinciClient factory, a React DaVinciProvider/useDaVinci hook pair, and a headless useDaVinciForm helper that normalises and submits collectors.
  • Implements collector types: text, password/passwordVerify, submitButton, action/flowButton/flowLink, label, singleSelect/dropdown/radio, multiSelect/combobox/checkbox, phoneNumber, deviceRegistration, and deviceAuthentication.
  • Adds typed node variants (ContinueNode, SuccessNode, ErrorNode, FailureNode) and DaVinciError with structured error codes.
  • Adds a DaVinci UI layer in PingSampleApp (atoms → molecules → organisms, custom hooks, stylesheet) and registers the DaVinciScreen entry point.
  • Adds integration tests (unit + mock-bridge), a DaVinciScenario/UseDaVinciScenario test runner, and a Detox E2E suite covering the full login → token → userinfo → refresh → revoke → logout flow.

Test plan

  • yarn test passes across all packages
  • yarn typecheck passes
  • yarn lint passes
  • Android integration: yarn workspace @ping-identity/rn-davinci test — all unit tests green
  • iOS integration: run DaVinciCommonTests, DaVinciNodeMapperTests, DaVinciCollectorValueApplierTests, and RNPingDavinciImplTests in Xcode
  • PingTestRunner integration suite (tests/integration/davinci.test.ts) — all cases pass
  • Detox E2E (e2e/davinci.test.ts) — all 9 happy-path scenarios pass against a live DaVinci policy
  • PingSampleApp — DaVinci screen renders, login with valid credentials reaches SuccessNode, token/userinfo/refresh/revoke/logout all work on both iOS and Android

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a new DaVinci route and a complete sample DaVinci Flow experience (client panel, continue form, success, error, and retry).
    • Updated Home to navigate to the DaVinci Flow.
    • Extended Token, User Profile, and Logout screens with DaVinci session support (access/refresh/revoke, user info, and DaVinci session logout).
    • Added DaVinci-specific sample UI components, styling, and documentation.
  • Bug Fixes

    • Improved DaVinci session detection and consistent enablement/behavior of related actions across Token, Profile, and Logout views.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 082c0bca-6922-4f1e-8120-bba89563ebfd

📥 Commits

Reviewing files that changed from the base of the PR and between a4a91ee and 917865d.

📒 Files selected for processing (2)
  • .github/workflows/browserstack-prep-android-artifacts.yml
  • .github/workflows/ci.yml
💤 Files with no reviewable changes (1)
  • .github/workflows/ci.yml

📝 Walkthrough

Walkthrough

Adds the DaVinci React Native package, native Android and iOS bridge implementations, sample-app DaVinci wiring, and PingTestRunner scenarios plus unit, integration, and E2E coverage.

Changes

DaVinci React Native SDK

Layer / File(s) Summary
Package scaffold and public API
packages/davinci/.editorconfig, packages/davinci/.git*, packages/davinci/LICENSE, packages/davinci/README.md, packages/davinci/package.json, packages/davinci/babel.config.js, packages/davinci/eslint.config.mjs, packages/davinci/jest.config.js, packages/davinci/jest.setup.js, packages/davinci/RNPingDavinci.podspec, packages/davinci/android/build.gradle, packages/davinci/android/src/main/AndroidManifest.xml, .gitignore, codecov.yml, packages/davinci/src/NativeRNPingDavinci.ts, packages/davinci/src/types/client.types.ts, packages/davinci/src/index.tsx, packages/davinci/src/collectorHelpers.ts, packages/davinci/src/davinci.ts, packages/davinci/src/davinciMethods.ts
Adds the package metadata, tooling, public JS contracts, native module resolution, collector helpers, client factory, and wrapper methods for DaVinci.
CoreRuntime DaVinci registry and resolver hooks
packages/core/android/src/main/java/com/pingidentity/rncore/CoreRuntime.kt, packages/core/ios/CoreRuntime.swift
Adds the DaVinci registry and collector resolver wiring to CoreRuntime on Android and iOS.
Android native bridge
packages/davinci/android/src/main/java/com/pingidentity/rndavinci/..., packages/davinci/android/src/newarch/java/com/pingidentity/rndavinci/..., packages/davinci/android/src/oldarch/java/com/pingidentity/rndavinci/...
Adds the Android config parser, error mapping, client factory, node mapping, collector mutation applier, shared runtime, and new/old architecture bridge modules and packages.
iOS native bridge
packages/davinci/ios/...
Adds the iOS payload model, config parser, error mapping, client factory, node mapping, collector mutation applier, shared runtime, ObjC/Swift bridge entry points, and classic/TurboModule wrappers.
Sample app DaVinci integration and UI components
PingSampleApp/App.tsx, PingSampleApp/src/clients.ts, PingSampleApp/ui/..., PingSampleApp/src/styles/davinciStyles.ts
Adds the DaVinci provider/route, sample config/client wiring, DaVinci-specific logout/token/user-profile UI branches, the DaVinci screen, shared styles, UI atoms and molecules, organism panels, controller hooks, and the sample UI README.
JS unit tests
packages/davinci/src/__tests__/*
Adds unit tests for the native wrapper, collector helpers, client factory, client methods, provider and hook behavior, and public exports.
Android and iOS native unit tests
packages/davinci/android/src/test/**/*, packages/davinci/ios/Tests/*
Adds Robolectric/JUnit and XCTest coverage for the Android and iOS bridge implementations, parser/factory/mapping helpers, error mapping, shared runtime lifecycles, and bridge entry points.
PingTestRunner scenarios, integration tests, and E2E wiring
PingTestRunner/scenarios/Davinci*.tsx, PingTestRunner/__tests__/integration/davinci.test.ts, PingTestRunner/e2e/davinci.test.ts, PingTestRunner/...
Adds headless DaVinci scenarios, integration coverage for the public package and collector helpers, a compile-time native spec contract test, and a Detox E2E happy-path suite plus runner wiring.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Suggested reviewers

  • george-bafaloukas-forgerock
  • spetrov
  • witrisna
  • rodrigoareis

Poem

🐰 Hop hop, the DaVinci bridge is here,
Native flows and screens appear.
Collectors dance, the tests all sing,
In every hop, a new flow spring.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 49.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: DaVinci integration plus form field support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch SDKS-5127

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@tsdamas tsdamas requested review from pingidentity-gaurav, rodrigoareis and witrisna and removed request for witrisna June 30, 2026 14:00
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://ForgeRock.github.io/ping-react-native-sdk/docs-preview/pr-57/

Built to branch gh-pages at 2026-06-30 19:45 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

🧹 Nitpick comments (8)
packages/davinci/src/__tests__/useDavinciForm.test.tsx (1)

181-204: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert that the updater path really merges.

This test only checks username. If setValues(updater) replaced state instead of merging, it would still pass. Please also assert that an untouched key survives the updater.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci/src/__tests__/useDavinciForm.test.tsx` around lines 181 -
204, The updater-function path in setValues is only verifying the changed
username field, so it could still pass even if the previous state is replaced
instead of merged. Update the useDavinciForm.test.tsx case around
FormHarness/requireLatest(latest).setValues to also assert that an untouched
value from the existing DaVinciFormResult.values remains present after the
updater runs, confirming the merging behavior.
packages/davinci/src/__tests__/createDaVinciClient.test.ts (1)

382-417: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add a concurrent lazy-configure test.

This only proves sequential reuse. A missing in-flight memo would still pass here while overlapping start() / user() calls double-configure native state. Please add one Promise.all(...) case that asserts configureDaVinci runs once across concurrent callers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci/src/__tests__/createDaVinciClient.test.ts` around lines 382
- 417, The lazy configuration coverage in createDaVinciClient only verifies
sequential reuse and misses the in-flight memo path; add a Promise.all-based
test in the createDaVinciClient lazy configure suite that triggers concurrent
start() and/or user() calls on the same client and asserts configureDaVinci is
called exactly once. Use the existing createDaVinciClient, loadModule, and
createNativeMock helpers so the test proves overlapping callers share the same
pending configuration instead of double-configuring native state.
packages/davinci/package.json (1)

22-30: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Lint script path assumes monorepo structure without guarding.

The "lint" script hard-codes ../../eslint.config.mjs, which will break if this package is ever checked out or used outside the monorepo root. Consider resolving the config path dynamically or documenting the monorepo requirement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci/package.json` around lines 22 - 30, The package.json lint
script in the davinci package hard-codes a monorepo-relative ESLint config path,
so update the "lint" command to avoid assuming the repo layout. Adjust the
script to resolve the config path dynamically or otherwise make it resilient
when run from the package itself, and keep the change localized to the "lint"
entry in package.json so it remains usable outside the monorepo root.
packages/davinci/RNPingDavinci.podspec (1)

36-36: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Use s.swift_versions here

swift_version is the deprecated singular form; swift_versions is the current podspec DSL for listing supported Swift versions.

Suggested fix
-  s.swift_version = ['5.0', '5.1', '6.0']
+  s.swift_versions = ['5.0', '5.1', '6.0']
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci/RNPingDavinci.podspec` at line 36, The podspec is using the
deprecated singular Swift version setting, so update the version declaration in
RNPingDavinci.podspec from s.swift_version to the supported plural form
s.swift_versions. Keep the listed supported versions the same, but switch the
property name so the podspec uses the current DSL and avoids deprecation
warnings.
packages/davinci/android/src/test/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapperTest.kt (1)

160-265: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the remaining Android collector serializers.

This suite still skips Android mapper cases for collector types that are part of the public bridge contract in this PR, notably phone-number and device registration/authentication variants. A regression in those serializer branches would ship Android-only schema drift without tripping CI.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/davinci/android/src/test/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapperTest.kt`
around lines 160 - 265, Add test coverage in DaVinciNodeMapperTest for the
remaining collector serializer branches in DaVinciNodeMapper.mapNodePayload,
especially the phone-number and device registration/authentication collector
variants mentioned in the review. Create focused tests similar to the existing
collector cases to assert the expected base fields and any type-specific payload
keys so these public bridge contract paths are exercised by CI.
PingTestRunner/e2e/davinci.test.ts (1)

84-180: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer visible skips over silent early-return for env-gated cases.

When hasDaVinciEnv() is false the live it() blocks console.warn and return, so they report as passed rather than skipped. That can mask real failures in CI where the env is expected to be present, and makes it hard to distinguish "intentionally skipped" from "actually green". Consider gating with a conditional describe/it so the runner marks them as skipped.

♻️ Example using a conditional test runner
-describe('DaVinci — happy path', () => {
+const liveIt = hasDaVinciEnv() ? it : it.skip;
+
+describe('DaVinci — happy path', () => {

Then use liveIt(...) for the live cases and drop the per-test if (!hasDaVinciEnv()) { ... return; } guards. Note hasDaVinciEnv() would need to read env at module load, which is fine for launch-arg-driven runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PingTestRunner/e2e/davinci.test.ts` around lines 84 - 180, The live DaVinci
e2e tests are using per-test `if (!hasDaVinciEnv()) { console.warn(...); return;
}`, which makes env-gated cases look passed instead of skipped. Update
`PingTestRunner/e2e/davinci.test.ts` to gate these `it()` blocks through a
conditional `describe` or a helper like `liveIt(...)` so the runner marks them
as skipped, and remove the early-return guards from the individual tests such as
`start()`, `next()`, `userinfo()`, `refresh()`, `revoke()`, and `logoutUser()`.
PingSampleApp/ui/davinci/components/atoms/DaVinciErrorList.tsx (1)

49-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Announce validation errors to assistive tech.

These errors are only rendered visually right now. When validation fails after submit/change, VoiceOver/TalkBack may not announce the new content, so users can miss why the form is blocked. Please add an alert/live-region semantic on the wrapper.

Suggested change
-    <View>
+    <View
+      accessible
+      accessibilityRole="alert"
+      accessibilityLiveRegion="polite"
+    >
       {errors.map((error, index) => (
         <Text
           key={`${error.code}-${index}`}
           style={davinciFieldStyles.errorText}
         >
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PingSampleApp/ui/davinci/components/atoms/DaVinciErrorList.tsx` around lines
49 - 59, Add an assistive-technology announcement role to the error wrapper in
DaVinciErrorList so validation updates are spoken, not just rendered visually.
Update the View returned by DaVinciErrorList to use an alert/live-region
semantic (for example via the wrapper’s accessibility props) while keeping the
existing error mapping and describeError rendering intact. Ensure the change is
localized to the DaVinciErrorList component and does not alter the error text
content or keys.
PingSampleApp/ui/davinci/components/atoms/DaVinciFieldLabel.tsx (1)

36-40: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Don't rely on * alone for required fields.

The asterisk is only a visual cue. Screen readers may read it literally instead of conveying that the field is required, so the accessible contract is weaker than the visual one. Please expose the required state in accessible text as well.

Suggested change
-    <Text style={davinciFieldStyles.fieldLabel}>
+    <Text
+      style={davinciFieldStyles.fieldLabel}
+      accessibilityLabel={required ? `${label} required` : label}
+    >
       {label}
       {required ? <Text style={davinciFieldStyles.required}> *</Text> : null}
     </Text>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PingSampleApp/ui/davinci/components/atoms/DaVinciFieldLabel.tsx` around lines
36 - 40, The required-state UI in DaVinciFieldLabel currently relies on a visual
asterisk only, so update the DaVinciFieldLabel component to expose the required
status in accessible text as well. Keep the existing label rendering, but add an
accessibility-friendly indication for required fields in the same component (for
example via text that screen readers can announce) alongside the visual marker.
Locate the change in DaVinciFieldLabel and ensure the required branch remains
consistent for both sighted and assistive users.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/davinci/android/src/main/java/com/pingidentity/rndavinci/collector/DaVinciCollectorValueApplier.kt`:
- Around line 161-168: The asString helper in DaVinciCollectorValueApplier is
converting all numeric inputs to strings via Number.toString(), which causes
whole-number JS values coming from readDynamicValue to be applied as malformed
strings like "5.0". Update asString to detect numeric values that represent
whole numbers and stringify them without the trailing decimal, while preserving
non-integer decimals and the existing handling for String and Boolean. Keep the
fix localized to asString so the collector receives the expected text for
single-select/text fields.

In
`@packages/davinci/android/src/test/java/com/pingidentity/rndavinci/RNPingDavinciCommonTest.kt`:
- Around line 497-499: The await helper in RNPingDavinciCommonTest silently
ignores the boolean result from latch.await, so timed-out async work can
continue and fail later in a confusing way. Update await(timeoutMs) to check the
return value from latch.await and fail immediately when it returns false, using
the existing await/latch helper path in RNPingDavinciCommonTest so hung
Promise-based tests report a clear timeout instead of a later null assertion.

In `@packages/davinci/ios/Collector/DaVinciCollectorValueApplier.swift`:
- Around line 179-194: The asString helper in DaVinciCollectorValueApplier is
treating bridged NSNumber 0/1 values as Bool, which converts numeric collector
values into true/false. Update the type checks in asString(_ value:key:) so the
Bool branch only matches actual booleans, then let NSNumber values continue
through the numeric path to preserve "0"/"1" output.

In `@packages/davinci/ios/Mapper/DaVinciNodeMapper.swift`:
- Around line 108-128: Use collector.key consistently when matching form fields
in unsupportedFields(_:logger:), because FieldCollector.id is not the field key
and can incorrectly classify valid fields as unsupported. Update the
registeredKeys set to collect collector.key values, and ensure the raw field
lookup/path in DaVinciNodeMapper aligns with the same key-based comparison so
supported fields are preserved.

In `@packages/davinci/ios/Tests/DaVinciClientFactoryTests.swift`:
- Around line 18-24: `tearDown()` in `DaVinciClientFactoryTests` is starting
cleanup in a detached `Task` and returning before
`CoreRuntime.oidcStorageConfigRegistry` and `CoreRuntime.loggerRegistry` are
actually cleared. Make the cleanup synchronous from the test’s perspective by
awaiting both `removeAll()` calls before `tearDown()` exits, so the next test
can’t observe stale registry state.

In `@packages/davinci/ios/Tests/DaVinciCollectorValueApplierTests.swift`:
- Around line 193-204: The phone collector test currently accepts a
non-dictionary payload and leaves the existing countryCode/phoneNumber
untouched, but it should verify that DaVinciCollectorValueApplier.apply rejects
this malformed input with a DaVinciBridgeError.argument instead. Update the test
in testApplySkipsPhoneFieldsForNonDictionary to assert the error path for the
CollectorMutation keyed by "phone", aligning it with the other invalid-input
cases in DaVinciCollectorValueApplier and makePhoneNumberCollector.

In `@packages/davinci/ios/Tests/DaVinciConfigParserTests.swift`:
- Around line 164-174: The timeout parsing in DaVinciConfigParser.parse
currently treats an invalid string like "not-a-number" as nil, which silently
falls back to no timeout; change the parser to validate the timeout field and
throw an argument error for malformed values instead of returning a payload with
a nil timeout. Update the timeout conversion logic in DaVinciConfigParser and
adjust the related tests so the invalid input case expects a failure rather than
XCTAssertNil on payload.timeout.

In `@packages/davinci/ios/Tests/RNPingDavinciCommonTests.swift`:
- Around line 64-70: The teardown in RNPingDavinciCommonTests is firing off
logger cleanup asynchronously instead of waiting for it, which can leak
CoreRuntime.loggerRegistry state into later tests. Update the test teardown path
around tearDown and CoreRuntime.loggerRegistry.removeAll() so the cleanup is
awaited before finishing teardown, using an async teardown pattern rather than a
detached Task. Keep the existing RNPingDavinciCommon.cleanup() call, but ensure
the logger registry removal completes synchronously from the test framework’s
perspective.

In `@packages/davinci/package.json`:
- Around line 39-43: The peerDependencies in the package manifest are too
permissive because react and react-native use wildcard ranges, so tighten them
to the minimum supported compatible semver ranges instead of allowing any
version. Update the peer dependency entries in the package manifest to explicit
caret ranges that match what this package supports, keeping
`@ping-identity/rn-core` as-is and constraining react and react-native to
compatible versions so consumers get install-time warnings for unsupported
majors.

In `@packages/davinci/src/davinci.ts`:
- Around line 191-203: ensureConfigured in davinci.ts is not concurrency-safe
because it only checks davinciId before awaiting configureDaVinci, so concurrent
callers like start() and user() can trigger duplicate native configuration. Fix
this by caching the in-flight promise inside ensureConfigured (or alongside
davinciId) so all overlapping calls await the same
configureDaVinci(nativeConfig) work, then store davinciId once it resolves and
clear the cached promise on success or failure.

In `@PingSampleApp/ui/davinci/components/organisms/DaVinciContinueNodePanel.tsx`:
- Around line 56-64: The interactive-submit check in hasInteractiveSubmit() is
missing FLOW_LINK, so link-only nodes fall through to the fallback Next button
and trigger onSubmit() instead of the flow action path. Update
hasInteractiveSubmit() to treat FLOW_LINK as interactive alongside
SUBMIT_BUTTON, ACTION, and FLOW_BUTTON, and ensure the fallback rendering in
DaVinciContinueNodePanel uses this updated detection so nodes with only
FLOW_LINK do not show the incorrect submit button.

In `@PingSampleApp/ui/davinci/hooks/useDaVinciAutoStartEffect.ts`:
- Around line 45-51: The auto-start latch in useDaVinciAutoStartEffect is only
cleared when onStart() returns false, so a rejected onStart() leaves
hasAutoStartedRef.current stuck true and creates an unhandled rejection. Update
the async block around onStart() to catch failures, reset
hasAutoStartedRef.current back to false on error, and ensure the failure is
handled/logged so the hook can retry on the same screen instance.

In `@PingTestRunner/jest.setup.js`:
- Around line 69-84: The native mock in jest.setup.js is too permissive because
configureDaVinci always returns a fixed id and the other methods never verify
which client instance is being used. Update the mock for NativeRNPingDavinci so
it tracks the configured client identity and validates that start, next,
getSession, refresh, revoke, userinfo, logout, and dispose are called against
the same configured id; also make disposed clients reject further calls. This
will let PingTestRunner catch JS bridge bugs where configureDaVinci is skipped,
the wrong client id is forwarded, or a disposed client is reused.

In `@PingTestRunner/scenarios/DaVinciScenario.tsx`:
- Around line 190-207: The success flags in handleRevoke and handleLogout are
being set even when client.revoke() or client.logoutUser() throws, so move
setRevoked(true) and setLoggedOut(true) to only run after the await succeeds
inside the try block. Keep the existing setRuntimeError handling in the catch
path, and use the handleRevoke/handleLogout callbacks to ensure Detox only sees
davinci-revoked or davinci-logged-out after a successful native call.
- Around line 151-166: `handleFlow()` is overwriting the current form payload by
sending only the flow key, which drops existing collector values; update the
`handleFlow` callback in `DaVinciScenario` to merge the flow action into the
current payload instead of replacing it. Reuse the existing form state used by
`handleSubmit`/`buildPayload` and ensure the submitted collectors include both
the current values and the `{ key: flowKey, value: flowKey }` entry so flow
actions preserve prior inputs.

---

Nitpick comments:
In
`@packages/davinci/android/src/test/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapperTest.kt`:
- Around line 160-265: Add test coverage in DaVinciNodeMapperTest for the
remaining collector serializer branches in DaVinciNodeMapper.mapNodePayload,
especially the phone-number and device registration/authentication collector
variants mentioned in the review. Create focused tests similar to the existing
collector cases to assert the expected base fields and any type-specific payload
keys so these public bridge contract paths are exercised by CI.

In `@packages/davinci/package.json`:
- Around line 22-30: The package.json lint script in the davinci package
hard-codes a monorepo-relative ESLint config path, so update the "lint" command
to avoid assuming the repo layout. Adjust the script to resolve the config path
dynamically or otherwise make it resilient when run from the package itself, and
keep the change localized to the "lint" entry in package.json so it remains
usable outside the monorepo root.

In `@packages/davinci/RNPingDavinci.podspec`:
- Line 36: The podspec is using the deprecated singular Swift version setting,
so update the version declaration in RNPingDavinci.podspec from s.swift_version
to the supported plural form s.swift_versions. Keep the listed supported
versions the same, but switch the property name so the podspec uses the current
DSL and avoids deprecation warnings.

In `@packages/davinci/src/__tests__/createDaVinciClient.test.ts`:
- Around line 382-417: The lazy configuration coverage in createDaVinciClient
only verifies sequential reuse and misses the in-flight memo path; add a
Promise.all-based test in the createDaVinciClient lazy configure suite that
triggers concurrent start() and/or user() calls on the same client and asserts
configureDaVinci is called exactly once. Use the existing createDaVinciClient,
loadModule, and createNativeMock helpers so the test proves overlapping callers
share the same pending configuration instead of double-configuring native state.

In `@packages/davinci/src/__tests__/useDavinciForm.test.tsx`:
- Around line 181-204: The updater-function path in setValues is only verifying
the changed username field, so it could still pass even if the previous state is
replaced instead of merged. Update the useDavinciForm.test.tsx case around
FormHarness/requireLatest(latest).setValues to also assert that an untouched
value from the existing DaVinciFormResult.values remains present after the
updater runs, confirming the merging behavior.

In `@PingSampleApp/ui/davinci/components/atoms/DaVinciErrorList.tsx`:
- Around line 49-59: Add an assistive-technology announcement role to the error
wrapper in DaVinciErrorList so validation updates are spoken, not just rendered
visually. Update the View returned by DaVinciErrorList to use an
alert/live-region semantic (for example via the wrapper’s accessibility props)
while keeping the existing error mapping and describeError rendering intact.
Ensure the change is localized to the DaVinciErrorList component and does not
alter the error text content or keys.

In `@PingSampleApp/ui/davinci/components/atoms/DaVinciFieldLabel.tsx`:
- Around line 36-40: The required-state UI in DaVinciFieldLabel currently relies
on a visual asterisk only, so update the DaVinciFieldLabel component to expose
the required status in accessible text as well. Keep the existing label
rendering, but add an accessibility-friendly indication for required fields in
the same component (for example via text that screen readers can announce)
alongside the visual marker. Locate the change in DaVinciFieldLabel and ensure
the required branch remains consistent for both sighted and assistive users.

In `@PingTestRunner/e2e/davinci.test.ts`:
- Around line 84-180: The live DaVinci e2e tests are using per-test `if
(!hasDaVinciEnv()) { console.warn(...); return; }`, which makes env-gated cases
look passed instead of skipped. Update `PingTestRunner/e2e/davinci.test.ts` to
gate these `it()` blocks through a conditional `describe` or a helper like
`liveIt(...)` so the runner marks them as skipped, and remove the early-return
guards from the individual tests such as `start()`, `next()`, `userinfo()`,
`refresh()`, `revoke()`, and `logoutUser()`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e370fdf0-8d47-44ee-977f-995f7a22adfb

📥 Commits

Reviewing files that changed from the base of the PR and between cd653e3 and 2aa82bc.

⛔ Files ignored due to path filters (4)
  • .yarn/install-state.gz is excluded by !**/.yarn/**, !**/*.gz
  • PingSampleApp/ios/Podfile.lock is excluded by !**/*.lock
  • PingTestRunner/ios/Podfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (120)
  • .gitignore
  • PingSampleApp/App.tsx
  • PingSampleApp/package.json
  • PingSampleApp/src/clients.ts
  • PingSampleApp/src/styles/davinciStyles.ts
  • PingSampleApp/ui/DaVinciScreen.tsx
  • PingSampleApp/ui/HomeScreen.tsx
  • PingSampleApp/ui/LogoutScreen.tsx
  • PingSampleApp/ui/TokenScreen.tsx
  • PingSampleApp/ui/UserProfileScreen.tsx
  • PingSampleApp/ui/davinci/README.md
  • PingSampleApp/ui/davinci/components/atoms/DaVinciErrorList.tsx
  • PingSampleApp/ui/davinci/components/atoms/DaVinciFieldLabel.tsx
  • PingSampleApp/ui/davinci/components/atoms/PickerModal.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciDeviceField.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciFieldRenderer.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciFlowButton.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciLabelField.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciMultiSelectField.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciPasswordField.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciPasswordRequirements.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciPhoneNumberField.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciSingleSelectField.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciSubmitButton.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciTextField.tsx
  • PingSampleApp/ui/davinci/components/molecules/DaVinciUnsupportedField.tsx
  • PingSampleApp/ui/davinci/components/molecules/types.ts
  • PingSampleApp/ui/davinci/components/organisms/DaVinciClientPanel.tsx
  • PingSampleApp/ui/davinci/components/organisms/DaVinciContinueNodePanel.tsx
  • PingSampleApp/ui/davinci/hooks/useDaVinciAutoStartEffect.ts
  • PingSampleApp/ui/davinci/hooks/useDaVinciClientPanelController.ts
  • PingSampleApp/ui/davinci/hooks/useDaVinciSessionController.ts
  • PingSampleApp/ui/token/components/organisms/TokenDaVinciPanel.tsx
  • PingSampleApp/ui/userProfile/components/organisms/UserProfileDaVinciPanel.tsx
  • PingTestRunner/App.tsx
  • PingTestRunner/__tests__/integration/davinci.test.ts
  • PingTestRunner/__tests__/integration/native-spec-contracts.test.ts
  • PingTestRunner/e2e/davinci.test.ts
  • PingTestRunner/ios/Podfile
  • PingTestRunner/jest.config.js
  • PingTestRunner/jest.setup.js
  • PingTestRunner/package.json
  • PingTestRunner/scenarios/DaVinciScenario.tsx
  • PingTestRunner/scenarios/UseDaVinciScenario.tsx
  • PingTestRunner/scripts/test-native-android.sh
  • packages/core/android/src/main/java/com/pingidentity/rncore/CoreRuntime.kt
  • packages/core/ios/CoreRuntime.swift
  • packages/davinci/.editorconfig
  • packages/davinci/.gitattributes
  • packages/davinci/.gitignore
  • packages/davinci/LICENSE
  • packages/davinci/README.md
  • packages/davinci/RNPingDavinci.podspec
  • packages/davinci/android/build.gradle
  • packages/davinci/android/src/main/AndroidManifest.xml
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/RNPingDavinciCommon.kt
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/collector/DaVinciCollectorValueApplier.kt
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/config/DaVinciConfigParser.kt
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/error/DaVinciErrorCodes.kt
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/error/DaVinciErrorMapper.kt
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/factory/DaVinciClientFactory.kt
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapper.kt
  • packages/davinci/android/src/newarch/java/com/pingidentity/rndavinci/RNPingDavinciModule.kt
  • packages/davinci/android/src/newarch/java/com/pingidentity/rndavinci/RNPingDavinciPackage.kt
  • packages/davinci/android/src/oldarch/java/com/pingidentity/rndavinci/RNPingDavinciClassicModule.kt
  • packages/davinci/android/src/oldarch/java/com/pingidentity/rndavinci/RNPingDavinciPackage.kt
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/RNPingDavinciCommonTest.kt
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/collector/DaVinciCollectorValueApplierTest.kt
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/config/DaVinciConfigParserTest.kt
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/error/DaVinciErrorMapperTest.kt
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/factory/DaVinciClientFactoryTest.kt
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/mapper/DaVinciNodeMapperTest.kt
  • packages/davinci/babel.config.js
  • packages/davinci/eslint.config.mjs
  • packages/davinci/ios/Collector/DaVinciCollectorValueApplier.swift
  • packages/davinci/ios/Config/DaVinciConfigParser.swift
  • packages/davinci/ios/Error/DaVinciErrorCodes.swift
  • packages/davinci/ios/Error/DaVinciErrorMapper.swift
  • packages/davinci/ios/Factory/DaVinciClientFactory.swift
  • packages/davinci/ios/Mapper/DaVinciNodeMapper.swift
  • packages/davinci/ios/Models/DaVinciPayloads.swift
  • packages/davinci/ios/RNPingDavinci.h
  • packages/davinci/ios/RNPingDavinci.mm
  • packages/davinci/ios/RNPingDavinciClassic.mm
  • packages/davinci/ios/RNPingDavinciCommon.swift
  • packages/davinci/ios/RNPingDavinciImpl.swift
  • packages/davinci/ios/Tests/DaVinciClientFactoryTests.swift
  • packages/davinci/ios/Tests/DaVinciCollectorValueApplierTests.swift
  • packages/davinci/ios/Tests/DaVinciConfigParserTests.swift
  • packages/davinci/ios/Tests/DaVinciErrorMapperTests.swift
  • packages/davinci/ios/Tests/DaVinciNodeMapperTests.swift
  • packages/davinci/ios/Tests/RNPingDavinciCommonTests.swift
  • packages/davinci/ios/Tests/RNPingDavinciImplTests.swift
  • packages/davinci/jest.config.js
  • packages/davinci/jest.setup.js
  • packages/davinci/package.json
  • packages/davinci/src/NativeRNPingDavinci.ts
  • packages/davinci/src/__tests__/collectorHelpers.test.ts
  • packages/davinci/src/__tests__/createDaVinciClient.test.ts
  • packages/davinci/src/__tests__/davinci.test.ts
  • packages/davinci/src/__tests__/davinciMethods.test.ts
  • packages/davinci/src/__tests__/index.test.tsx
  • packages/davinci/src/__tests__/nativeModuleAndProvider.test.tsx
  • packages/davinci/src/__tests__/useDavinci.test.tsx
  • packages/davinci/src/__tests__/useDavinciForm.test.tsx
  • packages/davinci/src/collectorHelpers.ts
  • packages/davinci/src/davinci.ts
  • packages/davinci/src/davinciMethods.ts
  • packages/davinci/src/index.tsx
  • packages/davinci/src/types/client.types.ts
  • packages/davinci/src/types/config.types.ts
  • packages/davinci/src/types/error.types.ts
  • packages/davinci/src/types/form.types.ts
  • packages/davinci/src/types/index.ts
  • packages/davinci/src/types/node.types.ts
  • packages/davinci/src/useDavinci.tsx
  • packages/davinci/src/useDavinciForm.ts
  • packages/davinci/tsconfig.build.json
  • packages/davinci/tsconfig.json
  • packages/davinci/turbo.json

Comment thread packages/davinci/ios/Collector/DaVinciCollectorValueApplier.swift
Comment thread packages/davinci/ios/Mapper/DaVinciNodeMapper.swift
Comment thread packages/davinci/ios/Tests/DaVinciClientFactoryTests.swift Outdated
Comment thread PingSampleApp/ui/davinci/hooks/useDaVinciAutoStartEffect.ts
Comment thread PingTestRunner/jest.setup.js Outdated
Comment thread PingTestRunner/scenarios/DaVinciScenario.tsx
Comment thread PingTestRunner/scenarios/DaVinciScenario.tsx Outdated
@tsdamas tsdamas requested a review from vibhorgoswami June 30, 2026 17:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/davinci/ios/Tests/RNPingDavinciCommonTests.swift (1)

64-72: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consolidate the two tearDown overrides.

The fire-and-forget Task flagged previously is now gone, which resolves the async-cleanup concern. However, you now have both a synchronous tearDown() and an async tearDown() async throws. XCTest will invoke both, so RNPingDavinciCommon.cleanup() and CoreRuntime.loggerRegistry.removeAll() run in separate teardown passes. Folding both into the single async teardown keeps the cleanup sequence in one place and avoids ambiguity about ordering.

♻️ Suggested consolidation
-  override func tearDown() {
-    RNPingDavinciCommon.cleanup()
-    super.tearDown()
-  }
-
-  override func tearDown() async throws {
-    await CoreRuntime.loggerRegistry.removeAll()
-    try await super.tearDown()
-  }
+  override func tearDown() async throws {
+    RNPingDavinciCommon.cleanup()
+    await CoreRuntime.loggerRegistry.removeAll()
+    try await super.tearDown()
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/davinci/ios/Tests/RNPingDavinciCommonTests.swift` around lines 64 -
72, The test teardown logic is split across both
`RNPingDavinciCommonTests.tearDown()` and `RNPingDavinciCommonTests.tearDown()
async throws`, so XCTest will run cleanup in two separate passes. Consolidate
the cleanup into the async `tearDown` override by moving
`RNPingDavinciCommon.cleanup()` and `CoreRuntime.loggerRegistry.removeAll()`
there, then call `super.tearDown()` once from that method and remove the
synchronous override.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@PingTestRunner/package.json`:
- Line 22: The BrowserStack Android journey script was renamed to
test:bs:android:journey-davinci, but existing callers still expect
test:bs:android:journey. Fix this by either restoring test:bs:android:journey as
an alias in package.json or updating all usages to the new script name,
especially the BrowserStack journey workflow and any other references to the old
npm script. Keep the script name(s) consistent so the journey pipeline continues
to run.

---

Nitpick comments:
In `@packages/davinci/ios/Tests/RNPingDavinciCommonTests.swift`:
- Around line 64-72: The test teardown logic is split across both
`RNPingDavinciCommonTests.tearDown()` and `RNPingDavinciCommonTests.tearDown()
async throws`, so XCTest will run cleanup in two separate passes. Consolidate
the cleanup into the async `tearDown` override by moving
`RNPingDavinciCommon.cleanup()` and `CoreRuntime.loggerRegistry.removeAll()`
there, then call `super.tearDown()` once from that method and remove the
synchronous override.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9871a6bf-4b21-4997-b9f8-0cb8ce04571a

📥 Commits

Reviewing files that changed from the base of the PR and between 2aa82bc and a7eaa26.

📒 Files selected for processing (16)
  • PingSampleApp/ui/davinci/components/organisms/DaVinciContinueNodePanel.tsx
  • PingSampleApp/ui/davinci/hooks/useDaVinciAutoStartEffect.ts
  • PingTestRunner/__tests__/integration/davinci.test.ts
  • PingTestRunner/jest.setup.js
  • PingTestRunner/package.json
  • PingTestRunner/scenarios/DaVinciScenario.tsx
  • packages/davinci/android/src/main/java/com/pingidentity/rndavinci/collector/DaVinciCollectorValueApplier.kt
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/RNPingDavinciCommonTest.kt
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/collector/DaVinciCollectorValueApplierTest.kt
  • packages/davinci/ios/Collector/DaVinciCollectorValueApplier.swift
  • packages/davinci/ios/Config/DaVinciConfigParser.swift
  • packages/davinci/ios/Tests/DaVinciClientFactoryTests.swift
  • packages/davinci/ios/Tests/DaVinciConfigParserTests.swift
  • packages/davinci/ios/Tests/RNPingDavinciCommonTests.swift
  • packages/davinci/src/davinci.ts
  • packages/davinci/src/useDavinci.tsx
🚧 Files skipped from review as they are similar to previous changes (10)
  • PingTestRunner/jest.setup.js
  • PingSampleApp/ui/davinci/components/organisms/DaVinciContinueNodePanel.tsx
  • PingSampleApp/ui/davinci/hooks/useDaVinciAutoStartEffect.ts
  • packages/davinci/ios/Tests/DaVinciConfigParserTests.swift
  • packages/davinci/ios/Tests/DaVinciClientFactoryTests.swift
  • PingTestRunner/tests/integration/davinci.test.ts
  • PingTestRunner/scenarios/DaVinciScenario.tsx
  • packages/davinci/src/davinci.ts
  • packages/davinci/android/src/test/java/com/pingidentity/rndavinci/RNPingDavinciCommonTest.kt
  • packages/davinci/ios/Collector/DaVinciCollectorValueApplier.swift

Comment thread PingTestRunner/package.json Outdated
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 21.97647% with 1658 lines in your changes missing coverage. Please review.
✅ Project coverage is 48.42%. Comparing base (3e12dfa) to head (a4a91ee).
⚠️ Report is 59 commits behind head on main.

Files with missing lines Patch % Lines
packages/davinci/ios/RNPingDavinciCommon.swift 0.00% 331 Missing ⚠️
...ackages/davinci/ios/Mapper/DaVinciNodeMapper.swift 0.00% 239 Missing ⚠️
.../com/pingidentity/rndavinci/RNPingDavinciCommon.kt 0.00% 206 Missing ⚠️
...i/ios/Collector/DaVinciCollectorValueApplier.swift 0.00% 166 Missing ⚠️
...ackages/davinci/ios/Error/DaVinciErrorMapper.swift 0.00% 119 Missing ⚠️
...ges/davinci/ios/Factory/DaVinciClientFactory.swift 0.00% 114 Missing ⚠️
packages/davinci/ios/RNPingDavinci.mm 0.00% 112 Missing ⚠️
...kages/davinci/ios/Config/DaVinciConfigParser.swift 0.00% 88 Missing ⚠️
...pingidentity/rndavinci/mapper/DaVinciNodeMapper.kt 54.49% 58 Missing and 18 partials ⚠️
packages/davinci/ios/RNPingDavinciClassic.mm 0.00% 69 Missing ⚠️
... and 7 more

❌ Your project check has failed because the head coverage (48.42%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff              @@
##               main      #57      +/-   ##
============================================
- Coverage     51.39%   48.42%   -2.97%     
- Complexity       82      168      +86     
============================================
  Files           189      212      +23     
  Lines         15597    17972    +2375     
  Branches        651      898     +247     
============================================
+ Hits           8016     8703     +687     
- Misses         7514     9147    +1633     
- Partials         67      122      +55     
Flag Coverage Δ
android 15.92% <36.61%> (+6.03%) ⬆️
ios 51.29% <0.00%> (-5.46%) ⬇️
javascript 69.72% <95.07%> (+5.87%) ⬆️
Files with missing lines Coverage Δ
packages/core/ios/CoreRuntime.swift 100.00% <ø> (ø)
...ngidentity/rndavinci/config/DaVinciConfigParser.kt 100.00% <100.00%> (ø)
...pingidentity/rndavinci/error/DaVinciErrorMapper.kt 100.00% <100.00%> (ø)
packages/davinci/src/NativeRNPingDavinci.ts 100.00% <100.00%> (ø)
packages/davinci/src/davinciMethods.ts 100.00% <ø> (ø)
packages/davinci/src/useDavinci.tsx 80.00% <ø> (ø)
packages/davinci/src/useDavinciForm.ts 82.79% <ø> (ø)
...c/main/java/com/pingidentity/rncore/CoreRuntime.kt 0.00% <0.00%> (ø)
packages/davinci/src/davinci.ts 96.58% <96.58%> (ø)
packages/davinci/src/collectorHelpers.ts 92.74% <92.74%> (ø)
... and 14 more

... and 36 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update cd653e3...a4a91ee. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
PingTestRunner/e2e/setup.ts (1)

71-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a hasDaVinciEnv() guard for consistency.

E2E_ENV has hasLiveAuthEnv()/hasJourneyEnv() to gate tests when credentials aren't configured; DAVINCI_ENV has no equivalent, so DaVinci specs may run unconditionally even with empty strings for required PingOne values.

♻️ Proposed addition
+export function hasDaVinciEnv(): boolean {
+  return !!(
+    DAVINCI_ENV.discoveryEndpoint &&
+    DAVINCI_ENV.clientId &&
+    DAVINCI_ENV.testUsername &&
+    DAVINCI_ENV.testPassword
+  );
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PingTestRunner/e2e/setup.ts` around lines 71 - 80, Add a hasDaVinciEnv()
guard alongside DAVINCI_ENV so DaVinci tests are skipped when required PingOne
values are missing. Update the setup in setup.ts to check the DAVINCI_ENV fields
used by the DaVinci specs (such as discoveryEndpoint, clientId, testUsername,
testPassword, and acrValues) and return a boolean like the existing E2E_ENV
helpers hasLiveAuthEnv() and hasJourneyEnv(). Then use that helper in the
DaVinci test gating so specs do not run with empty configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@PingTestRunner/package.json`:
- Line 23: The test script in PingTestRunner/package.json is using an escaped
regex group in the `test:bs:android:journey-davinci` command, so
`--testPathPattern` matches the literal parentheses instead of the intended
files. Update that script to use the unescaped `e2e/(journey|davinci)` pattern
so Detox selects the `e2e/journey...` and `e2e/davinci...` tests correctly.

---

Nitpick comments:
In `@PingTestRunner/e2e/setup.ts`:
- Around line 71-80: Add a hasDaVinciEnv() guard alongside DAVINCI_ENV so
DaVinci tests are skipped when required PingOne values are missing. Update the
setup in setup.ts to check the DAVINCI_ENV fields used by the DaVinci specs
(such as discoveryEndpoint, clientId, testUsername, testPassword, and acrValues)
and return a boolean like the existing E2E_ENV helpers hasLiveAuthEnv() and
hasJourneyEnv(). Then use that helper in the DaVinci test gating so specs do not
run with empty configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 87dff034-b638-4c8a-8bb8-b543f85eac2a

📥 Commits

Reviewing files that changed from the base of the PR and between c47c147 and a4a91ee.

📒 Files selected for processing (8)
  • .github/workflows/browserstack-e2e-android-journey.yml
  • .github/workflows/ci.yml
  • PingTestRunner/.env.example
  • PingTestRunner/e2e/davinci.test.ts
  • PingTestRunner/e2e/setup.ts
  • PingTestRunner/package.json
  • PingTestRunner/scenarios/DaVinciScenario.tsx
  • package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • PingTestRunner/e2e/davinci.test.ts
  • PingTestRunner/scenarios/DaVinciScenario.tsx

"test:e2e:android": "sh -c 'export DETOX_SERVER_PORT=${DETOX_SERVER_PORT:-8100}; export NODE_NO_WARNINGS=1; yarn e2e:android:free-detox-port && yarn e2e:android:kill-emulators && detox test --configuration android.emu --cleanup \"$@\"' --",
"test:bs:android": "NODE_NO_WARNINGS=1 detox test --configuration android.bs --loglevel trace",
"test:bs:android:journey": "NODE_NO_WARNINGS=1 detox test --configuration android.bs --loglevel trace --testPathPattern journey",
"test:bs:android:journey-davinci": "NODE_NO_WARNINGS=1 detox test --configuration android.bs --loglevel trace --testPathPattern 'e2e/\\(journey\\|davinci\\)'",

@coderabbitai coderabbitai Bot Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
node -e "
const re = new RegExp('e2e/\\\\(journey\\\\|davinci\\\\)', 'i');
console.log('escaped pattern matches journey.test.ts:', re.test('e2e/journey.test.ts'));
console.log('escaped pattern matches davinci.test.ts:', re.test('e2e/davinci.test.ts'));
const re2 = new RegExp('e2e/(journey|davinci)', 'i');
console.log('unescaped pattern matches journey.test.ts:', re2.test('e2e/journey.test.ts'));
console.log('unescaped pattern matches davinci.test.ts:', re2.test('e2e/davinci.test.ts'));
"

Repository: ForgeRock/ping-react-native-sdk

Length of output: 359


testPathPattern needs the unescaped regex group. PingTestRunner/package.json:23
--testPathPattern is treated as a single RegExp, so e2e/\\(journey\\|davinci\\) matches a literal (journey|davinci) string and won’t select e2e/journey... or e2e/davinci.... Use e2e/(journey|davinci) instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PingTestRunner/package.json` at line 23, The test script in
PingTestRunner/package.json is using an escaped regex group in the
`test:bs:android:journey-davinci` command, so `--testPathPattern` matches the
literal parentheses instead of the intended files. Update that script to use the
unescaped `e2e/(journey|davinci)` pattern so Detox selects the `e2e/journey...`
and `e2e/davinci...` tests correctly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on the pattern, but the escaping is intentional and consistent with the pre-existing test:bs:android:core script on the line below, which uses the same \( / \| form. In JSON, \( deserialises to (, and when that string is passed through the shell (inside single quotes) to Detox/Jest, the regex engine receives (journey|davinci) — which Jest treats as an alternation group because ( and ) are the escaped-group syntax in BRE/ERE-style patterns, and | is the alternation operator. The core script has been working correctly with this convention, so I've kept journey-davinci consistent with it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
node -e "
const paths = [
  'e2e/app-launch.test.ts',
  'e2e/oidc.test.ts',
  'e2e/journey.test.ts',
  'e2e/davinci.test.ts'
];
const escapedCore = new RegExp('e2e/\\\\(app-launch\\\\|app-open-close\\\\|browser\\\\|device-id\\\\|device-profile\\\\|logger\\\\|oidc\\\\|storage\\\\|use-oidc\\\\)', 'i');
console.log('--- escaped core pattern (as currently written in package.json) ---');
console.log('source:', escapedCore.source);
for (const p of paths) console.log(p, '=>', escapedCore.test(p));

const unescapedCore = new RegExp('e2e/(app-launch|app-open-close|browser|device-id|device-profile|logger|oidc|storage|use-oidc)', 'i');
console.log('--- unescaped core pattern ---');
for (const p of paths) console.log(p, '=>', unescapedCore.test(p));
"

Length of output: 1342


This confirms the analysis: the escaped form doesn't actually create a working alternation in JS RegExp (which is what Jest's --testPathPattern uses under the hood). The pre-existing test:bs:android:core script has the same issue — it doesn't match any of the intended e2e/... files either, so "it has been working" is likely not due to the regex actually selecting those files as intended.

@tsdamas In JavaScript regex (V8/Node, which Jest uses for testPathPattern), \( and \) mean a literal, non-grouping parenthesis character, and \| means a literal pipe character — the opposite of POSIX BRE, where unescaped (/)/| are literal and \(/\)/\| denote groups/alternation. Since Jest's pattern matching uses RegExp.prototype.test, the escaped form e2e/\(app-launch\|...\) only matches a literal string containing literal (, |, ) characters — it won't match any real file path, so it effectively matches nothing.

Given the verification above, both test:bs:android:core and the new test:bs:android:journey-davinci script's pattern don't perform the intended file-selection via alternation. If test:bs:android:core is indeed running its intended targeted subset of tests, it would be worth double-checking how that's invoked in CI (e.g., an env var override, or whether it's actually running all tests unfiltered) rather than relying on the escaped pattern.

To fix test:bs:android:journey-davinci, I'd suggest:

"test:bs:android:journey-davinci": "NODE_NO_WARNINGS=1 detox test --configuration android.bs --loglevel trace --testPathPattern 'e2e/(journey|davinci)'"

Would you like me to open a follow-up issue to also fix test:bs:android:core's pattern, since it's pre-existing and out of scope for this PR?

* this indirection lets DaVinci inject its collector lookup at init time without
* creating a circular dependency.
*/
suspend fun resolveDaVinciCollectors(davinciId: String): List<Any>? =

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add @param davinciId - registered daVinciId

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's empty, this is not required and can be deleted.

clientId = payload.clientId
redirectUri = payload.redirectUri
scopes = payload.scopes.toMutableSet()
payload.signOutRedirectUri?.let { signOutRedirectUri = it }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would recommend to have these pulled out in an updateOidc config values. For eg: https://github.com/ForgeRock/ping-android-sdk/blob/ef8bc6f21a0e01fa4f9dbc00b6493de1cc8424b0/foundation/oidc/src/main/kotlin/com/pingidentity/oidc/OidcClient.kt#L106
This will also help with Journey and Oidc configs as these values are common.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants