Skip to content

test: cover custom paywall tracking, ad tracker, and model parsing - #1013

Merged
vegaro merged 6 commits into
mainfrom
cesar/unity-tracking-model-tests
Aug 6, 2026
Merged

test: cover custom paywall tracking, ad tracker, and model parsing#1013
vegaro merged 6 commits into
mainfrom
cesar/unity-tracking-model-tests

Conversation

@vegaro

@vegaro vegaro commented Jul 24, 2026

Copy link
Copy Markdown
Member

Part of the #1006 split. Rebased onto main; no longer stacked on anything.

Adds TrackingTests.cs for custom paywall parameter resolution and ad-tracker forwarding/JSON serialization, and extends JsonModelTests.cs with full/minimal CustomerInfo and SubscriptionOption payloads, the epoch-vs-null date quirk, unrecognized-enum fallbacks, and the WebPurchaseRedemption/WebPurchaseRedemptionResult variants.

The JsonModelTests overlap is resolved

The earlier note here warned that this and #1014 both create JsonModelTests.cs. #1014 landed first, so I checked what main already has before rebasing: main's version holds 4 tests (VirtualCurrenciesParsesCurrenciesByCode, SubscriptionPriceSupportsValuesAboveInt32Range, StoreProductParsesKnownProductCategory, StoreProductFallsBackToUnknownProductCategory), this branch's version is a strict superset containing those same 4 with byte-identical bodies plus 11 more. Nothing on main is unique, so the rebase keeps this version wholesale — no coverage lost, no duplication introduced. The file now has 15 tests.

Second commit: fixture fidelity

MinimalCustomerInfoJson omitted every field the mappers always send as an explicit null, plus entitlements.verification. Android's convertToJson maps Kotlin null to JSONObject.NULL and the iOS mappers use NSNull(), so those keys are on the wire, not absent.

The web-redemption error fixture paired "code":11 with readableErrorCode: "UNKNOWN_ERROR" — a value neither platform emits, and inconsistent with the code. Code 11 is InvalidCredentialsError, so it now carries the iOS values for that code plus the deprecated readable_error_code that ships alongside it.

The synthetic "UNRECOGNIZED" and "BOGUS" values are unchanged and now carry comments: they stand in for enum members added natively before Unity knows the name, which is exactly what those fallback tests exist to pin down.

Verified against purchases-hybrid-common 18.29.0, which is what main pins. The redeemWebPurchase result names and per-variant payload shapes (customerInfo on success, error on failure, obfuscatedEmail on expiry, bare result for the other two) already matched and were left alone.

Verification

  • Edit Mode tests: 49 passed, 0 failed. Packages rebuilt from this branch and re-imported so the run used this code.

🤖 Generated with Claude Code


Note

Low Risk
Test-only changes (fixtures and NUnit tests); no runtime SDK or native bridge behavior is modified.

Overview
Adds Edit Mode test coverage for JSON model parsing and analytics forwarding, without changing production SDK code.

JsonModelTests moves inline JSON into JsonModelFixtures and adds tests for full CustomerInfo, full/minimal SubscriptionOption, millis 0 → null dates, UNKNOWN fallbacks for unrecognized enums/categories, and all WebPurchaseRedemptionResult variants (plus ArgumentException on unknown result).

TrackingTests (new) uses PurchasesWrapperSpy to verify TrackCustomPaywallImpression parameter resolution (offering id/context from first package, deprecated ctor) and that AdTracker events forward to the wrapper, including ToJsonString optional-field omission for ad payload types.

Reviewed by Cursor Bugbot for commit cd17929. Bugbot is set up for automated code reviews on this repo. Configure here.

vegaro commented Jul 24, 2026

Copy link
Copy Markdown
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@vegaro
vegaro force-pushed the cesar/unity-edit-mode-test-infra branch from 75760bd to 3ded913 Compare July 24, 2026 16:03
@vegaro
vegaro force-pushed the cesar/unity-tracking-model-tests branch 2 times, most recently from a99499a to a16c6a6 Compare July 27, 2026 08:57
@vegaro
vegaro force-pushed the cesar/unity-edit-mode-test-infra branch 2 times, most recently from 62ef6c4 to 98db931 Compare July 27, 2026 09:00
@vegaro
vegaro force-pushed the cesar/unity-tracking-model-tests branch 2 times, most recently from 72cb687 to 7eda6d0 Compare July 27, 2026 10:15
@vegaro
vegaro force-pushed the cesar/unity-edit-mode-test-infra branch from 98db931 to c91fc0a Compare July 27, 2026 10:15
@vegaro
vegaro force-pushed the cesar/unity-tracking-model-tests branch from 7eda6d0 to f60e3e3 Compare July 27, 2026 10:20
@vegaro
vegaro force-pushed the cesar/unity-edit-mode-test-infra branch from c91fc0a to a45f0a2 Compare July 27, 2026 10:20
vegaro added a commit that referenced this pull request Jul 27, 2026
This one's pure harness/CI plumbing, no test content, so it's a small.

Adds the `RevenueCat.Tests.EditMode` assembly, `PurchasesWrapperSpy`,
and an internal `SetWrapper` hook (via `InternalsVisibleTo`) so tests
can inject the spy into `Purchases`. Wires a `test-edit-mode` CircleCI
job that imports the packaged SDK and runs the suite the same way CI
already exercises the API tests.

Stacked on top, each independent of the others:
- #1014 configuration and harness smoke tests
- #1010 wrapper pass-through tests
- #1011 purchase forwarding & result parsing
- #1012 single-request callback flows
- #1013 tracking + model tests

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Changes are test/CI infrastructure plus a small internal injection
hook on `Purchases`; no production purchase or auth behavior changes for
shipped apps.
> 
> **Overview**
> Adds **Unity Edit Mode test plumbing** so later PRs can assert
`Purchases` behavior against the **exported** `Purchases.unitypackage` /
`PurchasesUI.unitypackage`.
> 
> Introduces the Editor-only `RevenueCat.Tests.EditMode` assembly and a
**`PurchasesWrapperSpy`** that records every `IPurchasesWrapper` call.
**`Purchases.SetWrapper`** (internal, exposed via `InternalsVisibleTo`
on the SDK assembly) lets tests inject the spy and keeps **`AdTracker`**
wired to the same wrapper; platform `Start()` now goes through
`SetWrapper` instead of assigning `_wrapper` directly.
> 
> **CircleCI** broadens the pre-import “hide scripts” step to
`Assets/Tests` (`.cs` and `.asmdef`), adds a **`test-edit-mode`** job
(`unity/test` editmode after `import-package`), stores JUnit artifacts,
and gates the release **hold** on that job. **IntegrationTests README**
documents running Edit Mode tests locally via Test Runner.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a45f0a2. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Base automatically changed from cesar/unity-edit-mode-test-infra to main July 27, 2026 12:03
@vegaro
vegaro force-pushed the cesar/unity-tracking-model-tests branch 2 times, most recently from 6890f1d to af190db Compare July 28, 2026 13:57
vegaro and others added 2 commits August 6, 2026 13:37
Adds TrackingTests.cs for custom paywall parameter resolution and
ad-tracker forwarding/JSON serialization. Expands JsonModelTests.cs
with full/minimal CustomerInfo and SubscriptionOption payloads, the
epoch-vs-null date quirk, unrecognized-enum fallback, and
WebPurchaseRedemption / WebPurchaseRedemptionResult variants.
…oads

MinimalCustomerInfoJson omitted every field the mappers always send as an
explicit null, plus entitlements.verification: Android's convertToJson maps
Kotlin null to JSONObject.NULL and the iOS mappers use NSNull(), so those keys
are present on the wire rather than absent. Spelled them out.

The web redemption error fixture paired code 11 with readableErrorCode
"UNKNOWN_ERROR", which neither platform produces and which contradicts the code.
Code 11 is InvalidCredentialsError, so it now carries the iOS values for that
code and the deprecated readable_error_code key that ships alongside.

Left the deliberately synthetic values alone and documented why: "UNRECOGNIZED"
and "BOGUS" stand in for enum members added natively before Unity knows the name,
which is what those two fallback tests exist to pin down.

Co-Authored-By: Claude <noreply@anthropic.com>
@vegaro
vegaro force-pushed the cesar/unity-tracking-model-tests branch from af190db to b497178 Compare August 6, 2026 11:42
@vegaro vegaro added the pr:other Changes to our CI configuration files and scripts label Aug 6, 2026
@vegaro
vegaro marked this pull request as ready for review August 6, 2026 11:44
@vegaro
vegaro requested a review from a team as a code owner August 6, 2026 11:44
Comment thread IntegrationTests/Assets/Tests/EditMode/JsonModelTests.cs Outdated
Comment thread IntegrationTests/Assets/Tests/EditMode/JsonModelTests.cs Outdated
vegaro and others added 3 commits August 6, 2026 14:47
The pinned version went stale within a day of being written — it was bumped from
18.25.0 to 18.29.0 while this branch was in review. The mapper names alone are
enough to find the source.

Co-Authored-By: Claude <noreply@anthropic.com>
@vegaro
vegaro enabled auto-merge (squash) August 6, 2026 13:53

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit cd17929. Configure here.

Assert.That(json["mediatorName"].Value, Is.EqualTo("AdMob"));
Assert.That(json["adFormat"].Value, Is.EqualTo("banner"));
Assert.That(json["adUnitId"].Value, Is.EqualTo("unit_1"));
Assert.That(json.HasKey("impressionId"), Is.False);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Wrong optional-field assertion in test

Low Severity

AdFailedToLoadDataToJsonStringOmitsOptionalFieldsWhenAbsent asserts that impressionId is absent, but AdFailedToLoadData has no ImpressionId member and never serializes that key. The check always passes and misdocuments the optional fields this type actually supports (placement, mediatorErrorCode).

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit cd17929. Configure here.

@vegaro
vegaro merged commit 9e0ac77 into main Aug 6, 2026
16 of 18 checks passed
@vegaro
vegaro deleted the cesar/unity-tracking-model-tests branch August 6, 2026 14:13
RCGitBot added a commit that referenced this pull request Aug 13, 2026
**This is an automatic release.**

## RevenueCat SDK
### ✨ New Features
* feat(ads): expose reward verification primitives (#971) via Peter
Porfy (@peterporfy)
### 🐞 Bugfixes
* Stop sending the purchase response twice on iOS errors (#1042) via
Cesar de la Vega (@vegaro)
* fix: surface native errors from GetCurrentOfferingForPlacement (#1019)
via Cesar de la Vega (@vegaro)
### 📦 Dependency Updates
* [AUTOMATIC BUMP] Updates purchases-hybrid-common to 18.30.0 (#1046)
via RevenueCat Git Bot (@RCGitBot)
* [Android
10.16.1](https://github.com/RevenueCat/purchases-android/releases/tag/10.16.1)
* [iOS
5.83.1](https://github.com/RevenueCat/purchases-ios/releases/tag/5.83.1)

### 🔄 Other Changes
* feat(ads): ad reward sample app (#1045) via Peter Porfy (@peterporfy)
* test: cover custom paywall tracking, ad tracker, and model parsing
(#1013) via Cesar de la Vega (@vegaro)
* test: cover missing Purchases functions (#1012) via Cesar de la Vega
(@vegaro)
* Bump fastlane-plugin-revenuecat_internal from `b4e1e7f` to `7fbbe66`
(#1040) via dependabot[bot] (@dependabot[bot])
* Bump fastlane-plugin-revenuecat_internal from `dd577ee` to `b4e1e7f`
(#1038) via dependabot[bot] (@dependabot[bot])
* Bump fastlane-plugin-revenuecat_internal from `3421c88` to `dd577ee`
(#1036) via dependabot[bot] (@dependabot[bot])
* Bump danger from 9.6.0 to 9.6.1 (#1035) via dependabot[bot]
(@dependabot[bot])

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches iOS purchase callback behavior and offerings/placement error
paths, plus new ads reward-verification APIs backed by a native SDK
bump.
> 
> **Overview**
> This **automatic release** cuts **9.8.0** by bumping package/plugin
versions (`.version`, `package.json`, Android/iOS `PLUGIN_VERSION`) and
publishing **CHANGELOG** / **VERSIONS.md** for **purchases-hybrid-common
18.30.0** (iOS **5.83.1**, Android **10.16.1**).
> 
> Shipped in this version (from prior merges, summarized in the
changelog): **ad reward verification** primitives
(`generateRewardVerificationToken` / `pollRewardVerification` on the
native bridge), fixes so **iOS purchase errors** no longer emit the
purchase callback twice, and **GetCurrentOfferingForPlacement** now
surfaces native failures instead of swallowing them.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a2f2846. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:other Changes to our CI configuration files and scripts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants