Fix continue_with:null decode crash + add auth decode/integration tests
Android UI Tests / ui-tests (push) Has been cancelled
Android UI Tests / ui-tests (push) Has been cancelled
Kratos serialises an empty `continue_with` as explicit `null` (not `[]` or an
absent key), which crashed the post-register login decode ("Expected start of
the array '[', but had 'n' at $.continue_with"). Make continue_with nullable on
the three Kratos models and add coerceInputValues as a backstop for other
null-vs-default fields.
Tests (all run + passing):
- KratosDecodeTest: null/absent continue_with on login + registration
- AuthFlowDecodeTest: real captured prod bodies (login, /auth/me, verification)
decoded with the real models + the real client Json configs
- LiveAuthIntegrationTest: live HTTP through the actual AuthApi against prod
(register -> login -> /auth/me -> start-verification -> wrong-code), gated by
RUN_LIVE_IT=1 so it never runs on a normal build
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+68
@@ -0,0 +1,68 @@
|
||||
package com.tt.honeyDue.network
|
||||
|
||||
import com.tt.honeyDue.data.DataManager
|
||||
import com.tt.honeyDue.models.RegisterRequest
|
||||
import com.tt.honeyDue.models.VerifyEmailRequest
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assume.assumeTrue
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* LIVE end-to-end integration test: drives the REAL [AuthApi] (the exact client
|
||||
* code the app runs, OkHttp engine, production URLs from ApiConfig) against the
|
||||
* live honeyDue API + Ory Kratos. No fixtures, no hand-written JSON — every
|
||||
* response is decoded by the real models over the wire, so a contract mismatch
|
||||
* between the API and the KMP client fails here.
|
||||
*
|
||||
* Skipped unless RUN_LIVE_IT=1 (it creates a real throwaway account and needs
|
||||
* network), so it never runs on a normal build/CI. Run explicitly:
|
||||
* RUN_LIVE_IT=1 ./gradlew :composeApp:testDebugUnitTest \
|
||||
* --tests "com.tt.honeyDue.network.LiveAuthIntegrationTest"
|
||||
*/
|
||||
class LiveAuthIntegrationTest {
|
||||
|
||||
private fun liveEnabled() = System.getenv("RUN_LIVE_IT") == "1"
|
||||
|
||||
@Test
|
||||
fun passwordSignupFlowAgainstProd() = runBlocking {
|
||||
assumeTrue("set RUN_LIVE_IT=1 to run the live integration test", liveEnabled())
|
||||
|
||||
val api = AuthApi() // ApiClient.httpClient (OkHttp) + PROD URLs
|
||||
val email = "kmpqa-" + System.currentTimeMillis() + "@example.com"
|
||||
val password = "KmpQa1!Test99"
|
||||
|
||||
// 1. Register: admin-create via /api/auth/register/ then immediate login.
|
||||
// Exercises the createAccount HTTP call AND the login decode that
|
||||
// crashed on "continue_with": null.
|
||||
val reg = api.register(
|
||||
RegisterRequest(username = "kmpqa", email = email, password = password, firstName = "Kmp", lastName = "Qa"),
|
||||
)
|
||||
assertTrue(reg is ApiResult.Success, "register should succeed, got: $reg")
|
||||
val auth = (reg as ApiResult.Success).data
|
||||
assertTrue(auth.token.isNotBlank(), "session token must be present")
|
||||
assertEquals(email, auth.user.email)
|
||||
assertFalse(auth.user.verified, "a fresh password account must start unverified")
|
||||
|
||||
// 2. /auth/me decodes through the ApiClient json config (User model).
|
||||
val me = api.getCurrentUser(auth.token)
|
||||
assertTrue(me is ApiResult.Success, "auth/me should succeed, got: $me")
|
||||
assertEquals(email, (me as ApiResult.Success).data.email)
|
||||
|
||||
// 3. Start the client-owned verification flow — decodes the flow body and
|
||||
// stores the flow id; sends the single code.
|
||||
val started = api.startEmailVerification(email)
|
||||
assertTrue(started is ApiResult.Success, "startEmailVerification should succeed, got: $started")
|
||||
assertNotNull(DataManager.pendingVerificationFlowId.value, "a verification flow id must be stored")
|
||||
|
||||
// 4. Submit a deliberately wrong code: must decode the re-rendered flow
|
||||
// and return a clean Error (not a parse crash).
|
||||
val wrong = api.verifyEmail(auth.token, VerifyEmailRequest(code = "000000"))
|
||||
assertTrue(wrong is ApiResult.Error, "wrong code must return Error, got: $wrong")
|
||||
|
||||
DataManager.setPendingVerificationFlowId(null)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user