Skip to content

feat: Pay later button - #1753

Open
saralvasquez wants to merge 12 commits into
mainfrom
pay-later-button-feature
Open

saralvasquez wants to merge 12 commits into
mainfrom
pay-later-button-feature

Conversation

@saralvasquez

@saralvasquez saralvasquez commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary of changes

  • Adds XML and compose version of the PayPal PayLater button
  • Adds test coverage for the new functionality
  • Adds additional UIComponent test coverage where lacking

XML

Screen_recording_20261109_112348.webm

Compose

Screen_recording_20261109_112526.webm

AI Usage

Which AI Agent Was Used?

  • Copilot
  • Claude
  • Other (Type Name Here)

How was AI used?
Aided in the development of this feature in many ways

Estimated AI Code Contribution

  • less than 30%
  • 30 - 60%
  • 60 - 100%

Checklist

  • Added a changelog entry
  • Tested and confirmed payment flows affected by this change are functioning as expected

Authors

agedd and others added 10 commits October 15, 2026 18:17
…od name (#1732)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* feat: add pay later wordmark assets

* feat: add basic pay later button

* fix: remove analytic constants and render PayPalResult as non-optional

* refactor: set `offerPayLater` to true

* feat: clean-up

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add basic pay later button

* fix: remove analytic constants and render PayPalResult as non-optional

* refactor: set `offerPayLater` to true

* feat: clean-up

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: share button style mapping between paypal and pay later colors

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor(demo): handle pay later return in onResume with separate slots

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* style: fix trailing space and missing final newline

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: extract shared drawing logic into PaymentButtonRenderer

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: disable payment buttons while a flow is in progress

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: re-enable payment buttons when a flow fails or finishes

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: address pr feedback

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: fix lint warnings

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* feat: add pay later wordmark assets

* feat: add basic pay later button

* fix: remove analytic constants and render PayPalResult as non-optional

* refactor: set `offerPayLater` to true

* feat: clean-up

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add basic pay later button

* fix: remove analytic constants and render PayPalResult as non-optional

* refactor: set `offerPayLater` to true

* feat: clean-up

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: share button style mapping between paypal and pay later colors

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor(demo): handle pay later return in onResume with separate slots

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* style: fix trailing space and missing final newline

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add composable paylaterbuttonview

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* style: add new line

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: extract shared drawing logic into PaymentButtonRenderer

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: update pay later button composable

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add compose pay later button

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add pay later composable to demo app

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: disable payment buttons while a flow is in progress

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: re-enable payment buttons when a flow fails or finishes

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: address lint warning

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: address pr feedback

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: fix lint warnings

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add composable paylaterbuttonview

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* style: add new line

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: update pay later button composable

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add compose pay later button

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add pay later composable to demo app

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: address lint warning

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: persist compose pay later flow state across activity recreation

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: re-enable compose pay later button when the flow fails to launch

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: adding missing }

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: deliver compose pay later missing-registry failure from a LaunchedEffect

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: extract shared paypal flow for compose paypal and pay laterbuttons

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* test: add unit tests for compose PayPal flow helpers

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: lint issues

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* test: add compose pay later button test

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* test: add test to make sure the flag is only set for pay later request

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* test: add UIComponents unit test coverage for buttons and card field inputs

Add unit tests for the View PayPalButton, Compose PayPal/Venmo buttons,
button colors, activity/context extensions, PendingRequestException,
Compose button views, Compose CardFields CVV truncation, and
BaseTextInputView.

To make the buttons testable, add an internal constructor to the View
PayPalButton and route the Compose buttons through internal
PayPalButtonContent/VenmoButtonContent composables that accept factories.
Public APIs are unchanged. Add Compose UI test dependencies to the unit test
classpath and remove the placeholder ExampleUnitTest.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test: cover View VenmoButton, PayLaterButton flows and PaymentButtonRenderer

Add unit tests for the View VenmoButton, PayLaterButton launch/return flows,
PaymentButtonRenderer appearance states and PaymentButtonStyle mappings.
Add an internal constructor to the View VenmoButton for dependency injection
in tests; the public API is unchanged. Remove the ActivityExtensions and
ContextExtensions unit tests, which are covered through the button tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test: merge PayLaterButton and PaymentButtonRenderer tests into existing files

Move the PayLaterButton flow tests into PayLaterButtonUnitTest and the
renderer appearance tests into PaymentButtonRendererUnitTest so each class
has a single test file. Replace the weak pressed-state renderer test with
fill-color assertions.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test: remove vacuous and duplicate UIComponents tests

Delete tests that restated source constants or could not fail (focus fill,
same-color setButtonColor, color keys, PaymentButtonStyleUnitTest, repeated
loading cycle, Compose color-style count). Fold error assertions into the
existing PayLaterButton failure tests and strengthen click, NPE, hint and
icon tests with argument, message and direction checks.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix: remove test bloat

* test: merge CardFields CVV truncation tests into CardFieldsUnitTest

Move the Compose CardFields CVV truncation tests into the existing
CardFieldsUnitTest so the composable has a single test file.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix: remove more test bloat

* fix: removing PayPal compose tests since refactor is coming

* refactor: restore compose PayPalButton to match the base branch

Remove the internal PayPalButtonContent seam added for unit tests, since the
compose PayPalButton tests were removed ahead of an upcoming refactor.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test: add compose PayPalButton unit tests

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix: resolve lint issue

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
* feat: add pay later wordmark assets

* feat: add basic pay later button

* fix: remove analytic constants and render PayPalResult as non-optional

* refactor: set `offerPayLater` to true

* feat: clean-up

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add basic pay later button

* fix: remove analytic constants and render PayPalResult as non-optional

* refactor: set `offerPayLater` to true

* feat: clean-up

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: share button style mapping between paypal and pay later colors

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor(demo): handle pay later return in onResume with separate slots

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* style: fix trailing space and missing final newline

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* refactor: extract shared drawing logic into PaymentButtonRenderer

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix: disable payment buttons while a flow is in progress

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: add analytics events to PayLaterButton

Sends PAY_LATER_BUTTON_PRESENTED on initialize and
PAY_LATER_BUTTON_SELECTED when the PayPal flow is launched, mirroring
the existing PayPalButton/VenmoButton pattern. Adds a
UIComponentsAnalyticsUnitTest pinning the event name constants.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix: resolve lint issue

* fix: remove unnecessary hideLoading

* test: mock AnalyticsClient in PayLaterButtonUnitTest

The launch failure test reaches the analytics call in completePayPalFlow,
which built a real AnalyticsClient and threw because SdkComponent is not
initialized in unit tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test: verify Pay Later selected analytics event

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* feat: add analytics events to compose PayLaterButton

Sends PAY_LATER_BUTTON_PRESENTED once when the composable is first shown
and PAY_LATER_BUTTON_SELECTED on click, with the compose UI type,
mirroring the compose PayPalButton. Adds unit tests for the compose and
XML Pay Later button analytics, and Compose UI test dependencies to the
UIComponents unit test classpath.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Alekhya Geddam <ageddam@paypal.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* test: add PayLaterButton instrumentation tests

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test: Expand PayLaterButton UI and unit test coverage

Add XML inflation, drawing, initialize and click instrumentation tests,
compose PayLaterButtonView and click-failure tests, and compose
PayLaterButton unit tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test: Prune redundant PayLaterButton instrumentation tests

Remove tests that duplicate PayPalButtonTest coverage of the shared renderer
or repeat each other. Fix compose PayLaterButton crashing when it is the first
SDK use by resolving AnalyticsClient lazily after PayPalClient is created.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix: remove useless comment

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@saralvasquez
saralvasquez requested review from a team and agedd November 7, 2026 01:01
@saralvasquez
saralvasquez requested a review from a team as a code owner November 7, 2026 01:01
@saralvasquez
saralvasquez requested a review from noguier November 7, 2026 01:01
@github-actions

github-actions Bot commented Nov 7, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities found.

Scanned Files

  • settings.gradle

@noguier

noguier commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

I think it would be useful to add end-to-end recording of the flow to this PR ❤️

@saralvasquez

Copy link
Copy Markdown
Contributor Author

Ah yup! I forgot again! I'll get that up soon

…eation (#1755)

* feat: fix paypal button compose flows not returning a result when activity is recreated

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: update browser-switch version and add change-log entry

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat: update changelog.md

Co-authored-by: Jax DesMarais-Leder <jdesmarais@paypal.com>
Signed-off-by: agedd <ageddam@paypal.com>

* doc: update browser-switch version in DEPENDENCIES.md

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Signed-off-by: agedd <ageddam@paypal.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Jax DesMarais-Leder <jdesmarais@paypal.com>

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants