test: add create endpoint contract coverage for api client

This commit is contained in:
2026-03-16 14:12:33 -04:00
parent 6a18d6679a
commit 6d313fdf60
3 changed files with 64 additions and 3 deletions

View File

@@ -24,6 +24,7 @@ Kanbn4Droid is an unofficial app to connect to and manipulate data stored in sel
- Baseline tests:
- JVM unit tests for auth URL normalization and auth error mapping in `app/src/test/`.
- JVM unit tests for boards repository and boards view model in `app/src/test/space/hackenslacker/kanbn4droid/app/boards/`.
- JVM API-client contract tests for board-detail parsing and create list/card endpoint payloads and id parsing in `app/src/test/java/space/hackenslacker/kanbn4droid/app/auth/HttpKanbnApiClientBoardDetailParsingTest.kt`.
- Instrumentation tests for login and boards flows in `app/src/androidTest/`.
## Command-line workflow

View File

@@ -778,7 +778,11 @@ class HttpKanbnApiClient : KanbnApiClient {
?: data
}
else -> root
else -> {
(root["card"] as? Map<*, *>)
?: (root["list"] as? Map<*, *>)
?: root
}
}
val publicId = extractString(entity, "publicId", "public_id", "id")

View File

@@ -18,12 +18,41 @@ import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import space.hackenslacker.kanbn4droid.app.boarddetail.BoardDetail
import space.hackenslacker.kanbn4droid.app.boarddetail.CreatedEntityRef
import space.hackenslacker.kanbn4droid.app.boards.BoardsApiResult
class HttpKanbnApiClientBoardDetailParsingTest {
@Test
fun createCardFormatsLocalDateAsUtcMidnightInPayload() = runTest {
fun createList_sendsAppendIndexPayload_andParsesPublicIdFallbacks() = runTest {
TestServer().use { server ->
server.register(
path = "/api/v1/lists",
method = "POST",
status = 200,
responseBody = """{"list":{"public_id":"list-new"}}""",
)
val result = HttpKanbnApiClient().createList(
baseUrl = server.baseUrl,
apiKey = "api",
boardPublicId = "board-1",
title = "Sprint",
appendIndex = 7,
)
assertTrue(result is BoardsApiResult.Success<*>)
val createdRef = (result as BoardsApiResult.Success<*>).value as CreatedEntityRef
assertEquals("list-new", createdRef.publicId)
val request = server.findRequest("POST", "/api/v1/lists")
assertNotNull(request)
assertEquals("{\"boardPublicId\":\"board-1\",\"name\":\"Sprint\",\"index\":7}", request?.body)
}
}
@Test
fun createCard_serializesLocalDateAsUtcMidnight() = runTest {
TestServer().use { server ->
server.register(path = "/api/v1/cards", method = "POST", status = 200, responseBody = """{"publicId":"card-new"}""")
@@ -46,7 +75,7 @@ class HttpKanbnApiClientBoardDetailParsingTest {
}
@Test
fun createCardOmitsNullDueDateAndDescriptionInPayload() = runTest {
fun createCard_sendsTopIndex_andOmittedDueDateWhenNull() = runTest {
TestServer().use { server ->
server.register(path = "/api/v1/cards", method = "POST", status = 200, responseBody = """{"publicId":"card-new"}""")
@@ -63,11 +92,38 @@ class HttpKanbnApiClientBoardDetailParsingTest {
assertTrue(result is BoardsApiResult.Success<*>)
val request = server.findRequest("POST", "/api/v1/cards")
assertNotNull(request)
assertTrue(request?.body?.contains("\"index\":0") == true)
assertTrue(request?.body?.contains("\"dueDate\"") == false)
assertTrue(request?.body?.contains("\"description\"") == false)
}
}
@Test
fun createCard_returnsCreatedRefWithNullPublicIdWhenResponseHasNoId() = runTest {
TestServer().use { server ->
server.register(
path = "/api/v1/cards",
method = "POST",
status = 200,
responseBody = """{"card":{"title":"Card without id"}}""",
)
val result = HttpKanbnApiClient().createCard(
baseUrl = server.baseUrl,
apiKey = "api",
listPublicId = "list-1",
title = "Card",
description = null,
dueDate = null,
tagPublicIds = emptyList(),
)
assertTrue(result is BoardsApiResult.Success<*>)
val createdRef = (result as BoardsApiResult.Success<*>).value as CreatedEntityRef
assertNull(createdRef.publicId)
}
}
@Test
fun getBoardDetailParsesWrappedPayloadWithDueDateVariants() = runTest {
TestServer().use { server ->