M12e: contract pass (pair invite kind, admin name in invite links, sync failed flag, rejection actor, device version name, template id, update check result, untouched accounts, D-027 re-stamp, PushEvent in :core:model, snackbar hosts)
Server: E-3 invite_kind; E-12 link ?from=<admin name>, E-4 passes it into kvitt://invite; X-Kvitt-App-Version-Name stored in devices.app_version_name (migration 0003, schema 3); OpenAPI and examples follow. Phone: :core:model, :core:fakes, :data, features and :app updated together; goldens re-recorded for S-20 (version name) and new S-1/S-22 states. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
+15
@@ -29,6 +29,21 @@ class InviteLinkTest {
|
||||
assertNull(InviteLink.parse("kvitt://other?code=7K3MQX9D2HPA"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun linksMayNameTheAdmin_andABadNameIsDropped() {
|
||||
assertEquals(
|
||||
PastedInvite("7K3MQX9D2HPA", RELEASE_SERVER_URL, "Jacob"),
|
||||
InviteLink.parse("kvitt://invite?server=https%3A%2F%2Ficehack.asuscomm.com%3A8443&code=7K3MQX9D2HPA&from=Jacob"),
|
||||
)
|
||||
assertEquals(
|
||||
PastedInvite("7K3MQX9D2HPA", RELEASE_SERVER_URL, "Åsa Berg"),
|
||||
InviteLink.parse("https://icehack.asuscomm.com:8443/i/7K3MQX9D2HPA?from=%C3%85sa+Berg"),
|
||||
)
|
||||
for (bad in listOf("", "%20", "a%0Ab", "A".repeat(41))) {
|
||||
assertEquals(bad, PastedInvite("7K3MQX9D2HPA", RELEASE_SERVER_URL), InviteLink.parse("https://icehack.asuscomm.com:8443/i/7K3MQX9D2HPA?from=$bad"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theLandingLinkGivesCodeAndServer() {
|
||||
assertEquals(PastedInvite("7K3MQX9D2HPA", RELEASE_SERVER_URL), InviteLink.parse("https://icehack.asuscomm.com:8443/i/7K3MQX9D2HPA"))
|
||||
|
||||
+11
@@ -18,6 +18,7 @@ import se.hagstedt.kvitt.fakes.onboarding.CallOutcome
|
||||
import se.hagstedt.kvitt.fakes.onboarding.OnboardingScenarios
|
||||
import se.hagstedt.kvitt.fakes.onboarding.PairCall
|
||||
import se.hagstedt.kvitt.fakes.onboarding.ScriptedSessionRepository
|
||||
import se.hagstedt.kvitt.model.InviteKind
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class PairingViewModelTest {
|
||||
@@ -68,6 +69,16 @@ class PairingViewModelTest {
|
||||
assertEquals(PairingDone.ProfileStep, vm.state.value.done)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aDeviceInviteGoesHomeEvenForTheMember_andTheLinkNamesTheAdmin() {
|
||||
val (_, vm) = vm(OnboardingScenarios.unpairedPartner.copy(pairingInviteKind = InviteKind.DEVICE))
|
||||
vm.prefill(RELEASE_SERVER_URL, "7K3MQX9D2HPA", "Jacob")
|
||||
assertEquals("Jacob", vm.state.value.adminName)
|
||||
vm.onNameChange("Anna")
|
||||
vm.pair("Galaxy S26+")
|
||||
assertEquals(PairingDone.Home, vm.state.value.done)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theAdminGoesHomeAndTheAgainVariantSendsNoName() {
|
||||
val (_, admin) = vm(OnboardingScenarios.unpaired)
|
||||
|
||||
+8
@@ -76,6 +76,14 @@ object OnboardingStates {
|
||||
ScreenState("s1_pairing_empty", render = pairing(OnboardingScenarios.unpaired) {}),
|
||||
ScreenState("s1_pairing", largeFont = true, render = pairing(OnboardingScenarios.unpaired) { fillFromLink() }),
|
||||
ScreenState("s1_pairing_link_lan", render = pairing(OnboardingScenarios.unpaired, allowLanHttp = true) { fillFromLink(LAN_SERVER) }),
|
||||
// AC-2.6: a link that names the inviting admin fills the help line with the name.
|
||||
ScreenState(
|
||||
"s1_pairing_link_admin",
|
||||
render = pairing(OnboardingScenarios.unpaired) {
|
||||
prefill(RELEASE_SERVER_URL, CODE, "Jacob")
|
||||
onNameChange("Anna")
|
||||
},
|
||||
),
|
||||
ScreenState("s1_pairing_loading", render = pairing(OnboardingScenarios.unpaired, CallOutcome.Hang) { fillFromLink(); pair("Galaxy S26") }),
|
||||
ScreenState(
|
||||
"s1_pairing_error",
|
||||
|
||||
Reference in New Issue
Block a user