Skip to content

test: [SDK-5249] port the Android IV test matrix to Vitest - #1530

Merged
sherwinski merged 5 commits into
feat/identity-verificationfrom
sherwin/sdk-5249
Oct 26, 2026
Merged

sherwinski merged 5 commits into
feat/identity-verificationfrom
sherwin/sdk-5249

Conversation

@sherwinski

Copy link
Copy Markdown
Contributor

Description

1 Line Summary

Cross-cutting pass over the Android Identity Verification test matrix: the mapping to the Vitest suites, and the 2 cases that were missing.

Details

The ticket asks for a comparison against the Android matrix and tests for the gaps. The mapping below is the result. Every Android row has a web counterpart, or a reason why web has none. Two cases were missing, and this PR adds them to OneSignal.test.ts under login > a new user under Identity Verification:

  1. login(A, tokenA) → 401 on the create-user request → the login call rejects with _FailUnauthorized, userJwtInvalidated fires with the external id, the token is removed, the identity already points at A, and the operation waits → updateUserJwt(A, tokenB) → the create-user request goes out again with Authorization: Bearer token-b, and the identity gets the onesignal id. This is the "Also add" row of the ticket; the existing tests covered its pieces (a tag update 401, the event, a held operation released by updateUserJwt) but not the chain where the login request itself is the one the server rejects.
  2. The same request with a non-401 failure (400): the call rejects with the pause result, the token stays, the queue pauses, and no event fires. This maps the Android row "login logs error when operation fails"; on web the error reaches the caller through _enqueueAndWait (SDK-5233).

Mapping

Android counts are test rows in the files the ticket names.

Android file Rows Web file(s) Status
IdentityVerificationServiceTests.kt 12 identityVerification.test.ts 6 gate combinations, derived-on-read, and the local override: covered. start subscribes to ConfigModelStore and the 4 hydrate handler rows: no web counterpart. Web has no hydrate handler; the page fetches the config before the repo starts, and OperationRepo._start runs the purge. Covered by the anonymous operation purge on start and JWT requirement UNKNOWN blocks in OperationRepo.test.ts.
JwtTokenStoreTests.kt 20 JwtTokenStore.test.ts All 20 covered, plus web-only rows (prototype keys, failed write, malformed entries, a listener that removes itself).
ExecutorsIvExtensionsTests.kt 9 ivResolver.test.ts, executorsIv.test.ts resolveIvBackendParams and resolveIvJwt rows: covered. shouldFailLoginUserFromSubscription: no web counterpart. That guard belongs to LoginUserFromSubscriptionOperationExecutor, the Android v4→v5 migration path, which web does not have.
OperationRepoTests.kt (IV rows 1013-1161) 7 OperationRepo.test.ts Pre-hydrate deferral and post-hydrate resume: JWT requirement UNKNOWN block. removeOperationsWithoutExternalId and onJwtConfigHydrated(true/false): anonymous operation purge on start block (IV active and inactive). 401 requeue and 401 drop when inactive: FailUnauthorized block, plus the in-flight newer token and the no-spin case.
LoginHelperTests.kt 8 LoginManager.test.ts, OneSignal.test.ts Same id early return, different id switch, existing onesignal id for the anonymous conversion, no existing id under IV, token stored before the operation, same id with a new or an empty token: covered. "login logs error when operation fails": added here as the 400 case.
LogoutHelperTests.kt 6 LoginManager.test.ts No external id, with external id, order, one switch at a time (a login during the logout waits, a logout during the login waits for it), disable push on the old user under IV, legacy path when IV is inactive: covered.
HttpClientTests.kt (rows 263-291) 3 executorsIv.test.ts Bearer set with a token and absent without one, per executor path: covered. "POST + JWT does not throw (headers before body write)": no web counterpart; fetch has no such ordering.
Shared mock identityVerificationService(newCodePathsRun, ivBehaviorActive) — setJwtRequirement + setFeatureFlags Web drives the gates from storage, as the ticket notes.

The other "Also add" row

"A test that the token store prune method is called on init, if web calls it." Web does not call _pruneToExternalIds from production code, and neither does Android (pruneToExternalIds has no caller outside its tests). Nothing to test; noted on the ticket.

Bundle size

Test-only change. No change to the bundles.

Systems Affected

  • WebSDK
  • Backend
  • Dashboard

Validation

Tests

Info

  • vp test run — 71 files, 822 tests pass.
  • vp check — 0 errors, 5 pre-existing warnings.

Checklist

  • All the automated tests pass or I explained why that is not possible
  • I have personally tested this on my machine or explained why that is not possible
  • I have included test coverage for these changes or explained why they are not needed

Programming Checklist
Interfaces:

  • Don't use default export
  • New interfaces are in model files

Functions:

  • Don't use default export
  • All function signatures have return types
  • Helpers should not access any data but rather be given the data to operate on.

Typescript:

  • No Typescript warnings
  • Avoid silencing null/undefined warnings with the exclamation point

Other:

  • Iteration: refrain from using elem of array syntax. Prefer forEach or use map
  • Avoid using global OneSignal accessor for context if possible. Instead, we can pass it to function/constructor so that we don't call OneSignal.context

Screenshots

Info

Not needed: test-only change.

Checklist

  • I have included screenshots/recordings of the intended results or explained why they are not needed

Related Tickets


login(A, tokenA) gets a 401 on the create-user request: the login call
rejects, userJwtInvalidated fires with the external id, the token is
removed, and the operation waits. updateUserJwt(A, tokenB) releases it,
and the create-user request goes out again with the new bearer.

A second test pins a non-401 failure on the same request: the call
rejects with the pause result, the token stays, and no event fires.

@abdulraqeeb33 abdulraqeeb33 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.

Both cases reject for the result they name. A 401 on create-user removes the token and the follow-up request uses the new one. A 400 pauses the repo and keeps the token. The 401 case never shows that the operation stays held in between.

Comment thread src/onesignal/OneSignal.test.ts
Comment thread src/onesignal/OneSignal.test.ts
Comment thread src/onesignal/OneSignal.test.ts

@abdulraqeeb33 abdulraqeeb33 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.

The 401 case now waits five queue intervals and shows the login stays held before updateUserJwt.

Comment thread src/onesignal/OneSignal.test.ts Outdated
Comment thread src/onesignal/OneSignal.test.ts
Comment thread src/onesignal/OneSignal.test.ts Outdated
Comment thread src/onesignal/OneSignal.test.ts Outdated
The queue also holds the create-subscription operation with a local id, so a
length check cannot tell a held login from a dropped one. The 401 case checks
the queue holds a LoginUserOperation. The 400 case counts one create-user
request, checks the repo is still paused after the wait, and checks the login
is still at the head of the queue.
@sherwinski
sherwinski merged commit 55e0801 into feat/identity-verification Oct 26, 2026
1 check passed
@sherwinski
sherwinski deleted the sherwin/sdk-5249 branch October 26, 2026 18:35
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