test: write tests for controllers #24
@@ -64,7 +64,7 @@ class FilmRepository(
|
||||
override fun findByTitle(title: String): Film? {
|
||||
val films =
|
||||
jdbc.query(
|
||||
"SELECT id, title, description FROM films WHERE title = ?",
|
||||
"SELECT id, title, description FROM films WHERE title = ? ORDER BY id LIMIT 1",
|
||||
filmRowMapper,
|
||||
title,
|
||||
)
|
||||
|
||||
@@ -86,7 +86,8 @@ class UserRepository(
|
||||
val entities =
|
||||
jdbc.query(
|
||||
"""
|
||||
SELECT id, name, email, provider, provider_id, created_at FROM users
|
||||
SELECT id, name, email, provider, provider_id, created_at
|
||||
FROM users
|
||||
WHERE provider = ? AND provider_id = ?
|
||||
""".trimIndent(),
|
||||
userEntityRowMapper,
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.project.movienight.application.ports.input.GetAllFilmsUseCase
|
||||
import com.project.movienight.application.ports.input.GetFilmByIdUseCase
|
||||
import com.project.movienight.application.ports.input.SearchFilmByTitleUseCase
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PatchMapping
|
||||
@@ -75,11 +76,18 @@ class FilmController(
|
||||
@PathVariable id: UUID,
|
||||
): FilmResponse = FilmResponse.fromDomain(getFilmByIdUseCase.getById(id))
|
||||
|
||||
@GetMapping
|
||||
fun getAll(): List<FilmResponse> = getAllFilmsUseCase.getAll().map { FilmResponse.fromDomain(it) }
|
||||
|
||||
@GetMapping("/search")
|
||||
fun searchByTitle(
|
||||
@RequestParam title: String,
|
||||
): FilmResponse? = searchFilmByTitleUseCase.searchByTitle(title)?.let { FilmResponse.fromDomain(it) }
|
||||
|
||||
@GetMapping
|
||||
fun getAll(): List<FilmResponse> = getAllFilmsUseCase.getAll().map { FilmResponse.fromDomain(it) }
|
||||
): ResponseEntity<FilmResponse> {
|
||||
val film = searchFilmByTitleUseCase.searchByTitle(title)
|
||||
return if (film != null) {
|
||||
ResponseEntity.ok(FilmResponse.fromDomain(film))
|
||||
} else {
|
||||
ResponseEntity.notFound().build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.project.movienight.application.ports.input.GetFilmLibraryQuery
|
||||
import com.project.movienight.application.ports.input.GetFilmLibraryUseCase
|
||||
import com.project.movienight.application.ports.input.RemoveFilmFromLibraryCommand
|
||||
import com.project.movienight.application.ports.input.RemoveFilmFromLibraryUseCase
|
||||
import com.project.movienight.domain.exception.EntityNotFoundException
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
@@ -67,9 +68,7 @@ class FilmLibraryController(
|
||||
getFilmLibraryUseCase.getLibrary(
|
||||
GetFilmLibraryQuery(userId = userId),
|
||||
)
|
||||
|
||||
val film = getFilmByIdUseCase.getById(library.filmId)
|
||||
|
||||
return listOf(FilmResponse.fromDomain(film))
|
||||
}
|
||||
|
||||
@@ -107,13 +106,24 @@ class FilmLibraryController(
|
||||
@PathVariable userId: UUID,
|
||||
): List<FilmResponse> {
|
||||
val userLibrary =
|
||||
getFilmLibraryUseCase.getLibrary(
|
||||
GetFilmLibraryQuery(userId = userId),
|
||||
)
|
||||
runCatching {
|
||||
getFilmLibraryUseCase.getLibrary(
|
||||
GetFilmLibraryQuery(userId = userId),
|
||||
)
|
||||
}.onFailure { exception ->
|
||||
if (exception !is EntityNotFoundException) {
|
||||
throw exception
|
||||
}
|
||||
}.getOrNull()
|
||||
|
||||
val allFilms = getAllFilmsUseCase.getAll()
|
||||
|
||||
val availableFilms = allFilms.filter { it.id != userLibrary.filmId }
|
||||
val availableFilms =
|
||||
if (userLibrary != null) {
|
||||
allFilms.filter { it.id != userLibrary.filmId }
|
||||
} else {
|
||||
allFilms
|
||||
}
|
||||
|
||||
return availableFilms.map { FilmResponse.fromDomain(it) }
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ class FilmControllerSearchTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `search returns empty body when title is missing`() {
|
||||
fun `search returns 404 when title is not found`() {
|
||||
val title = "Unknown Title"
|
||||
|
||||
every { searchFilmByTitleUseCase.searchByTitle(title) } returns null
|
||||
@@ -68,7 +68,7 @@ class FilmControllerSearchTest {
|
||||
.get("/api/films/search") {
|
||||
param("title", title)
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
status { isNotFound() }
|
||||
content { string("") }
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.project.movienight.controllers
|
||||
|
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.project.movienight.adapters.web.dto.request.CreateFilmRequest
|
||||
import com.project.movienight.adapters.web.dto.request.EditFilmRequest
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
class FilmControllerTest {
|
||||
@Autowired
|
||||
private lateinit var mockMvc: MockMvc
|
||||
|
||||
@Autowired
|
||||
private lateinit var objectMapper: ObjectMapper
|
||||
|
||||
@Test
|
||||
fun `create film should return 201 CREATED`() {
|
||||
val request =
|
||||
CreateFilmRequest(
|
||||
title = "The Matrix",
|
||||
description = "A computer hacker learns about the true nature of reality",
|
||||
)
|
||||
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/films")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)),
|
||||
).andExpect(status().isCreated)
|
||||
.andExpect(jsonPath("$.title").value("The Matrix"))
|
||||
.andExpect(jsonPath("$.description").value("A computer hacker learns about the true nature of reality"))
|
||||
.andExpect(jsonPath("$.id").exists())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `edit film should return updated film`() {
|
||||
val createRequest =
|
||||
CreateFilmRequest(
|
||||
title = "Old Title",
|
||||
description = "Old Description",
|
||||
)
|
||||
|
||||
val response =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/films")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(createRequest)),
|
||||
).andReturn()
|
||||
|
||||
val filmId = objectMapper.readTree(response.response.contentAsString).get("id").asText()
|
||||
|
||||
val editRequest =
|
||||
EditFilmRequest(
|
||||
title = "New Title",
|
||||
description = "New Description",
|
||||
)
|
||||
|
||||
mockMvc
|
||||
.perform(
|
||||
patch("/api/films/$filmId")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(editRequest)),
|
||||
).andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.title").value("New Title"))
|
||||
.andExpect(jsonPath("$.description").value("New Description"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `search film by title should return film`() {
|
||||
val request =
|
||||
CreateFilmRequest(
|
||||
title = "Inception",
|
||||
description = "Dream within a dream",
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
post("/api/films")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)),
|
||||
)
|
||||
|
||||
mockMvc
|
||||
.perform(
|
||||
get("/api/films/search")
|
||||
.param("title", "Inception"),
|
||||
).andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.title").value("Inception"))
|
||||
.andExpect(jsonPath("$.description").value("Dream within a dream"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `search film by non-existent title should return 404`() {
|
||||
mockMvc
|
||||
.perform(
|
||||
get("/api/films/search")
|
||||
.param("title", "NonExistentFilm12345"),
|
||||
).andExpect(status().isNotFound)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `delete film should return 204 NO CONTENT`() {
|
||||
val request =
|
||||
CreateFilmRequest(
|
||||
title = "Film To Delete",
|
||||
description = "This film will be deleted",
|
||||
)
|
||||
|
||||
val response =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/films")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)),
|
||||
).andReturn()
|
||||
|
||||
val filmId = objectMapper.readTree(response.response.contentAsString).get("id").asText()
|
||||
|
||||
mockMvc
|
||||
.perform(delete("/api/films/$filmId"))
|
||||
.andExpect(status().isNoContent())
|
||||
|
||||
mockMvc
|
||||
.perform(
|
||||
get("/api/films/search").param("title", "Film To Delete"),
|
||||
).andExpect(status().isNotFound)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
package com.project.movienight.controllers
|
||||
|
These wildcard imports ( These wildcard imports (`MockMvcRequestBuilders.*`, `MockMvcResultMatchers.*`) will fail ktlint's `no-wildcard-imports` rule (ktlintCheck is part of `check`). Replace them with explicit imports for only the methods/matchers used in this test file.
```suggestion
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
```
There are consecutive blank lines in this file (e.g., here before the first test), which will fail ktlint formatting checks. Remove extra blank lines so there's at most one blank line between members. There are consecutive blank lines in this file (e.g., here before the first test), which will fail ktlint formatting checks. Remove extra blank lines so there's at most one blank line between members.
```suggestion
```
This This `mockMvc.perform(...)` call is formatted as a multiline call-site but is missing the trailing comma after the single argument. The main source files consistently use trailing commas in multiline call-sites, and with ktlint experimental rules enabled this can fail formatting checks; update this (and similar call-sites in the file) to include the trailing comma.
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.project.movienight.adapters.web.dto.request.CreateFilmRequest
|
||||
import com.project.movienight.adapters.web.dto.request.CreateUserRequest
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@Transactional
|
||||
class FilmLibraryControllerTest {
|
||||
@Autowired
|
||||
private lateinit var mockMvc: MockMvc
|
||||
|
||||
@Autowired
|
||||
private lateinit var objectMapper: ObjectMapper
|
||||
|
||||
@Test
|
||||
fun `add film to library should work`() {
|
||||
val userRequest =
|
||||
CreateUserRequest(
|
||||
name = "Film Adder",
|
||||
email = "adder@example.com",
|
||||
)
|
||||
val userResponse =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/users")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(userRequest)),
|
||||
).andReturn()
|
||||
val userId = objectMapper.readTree(userResponse.response.contentAsString).get("id").asText()
|
||||
|
||||
val filmRequest =
|
||||
CreateFilmRequest(
|
||||
title = "Library Film",
|
||||
description = "Film description",
|
||||
)
|
||||
val filmResponse =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/films")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(filmRequest)),
|
||||
).andReturn()
|
||||
val filmId = objectMapper.readTree(filmResponse.response.contentAsString).get("id").asText()
|
||||
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/users/$userId/library/films/$filmId"),
|
||||
).andExpect(status().isCreated())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `remove film from library should return 204`() {
|
||||
val userRequest =
|
||||
CreateUserRequest(
|
||||
name = "Remove Film",
|
||||
email = "remove@example.com",
|
||||
)
|
||||
val userResponse =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/users")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(userRequest)),
|
||||
).andReturn()
|
||||
val userId = objectMapper.readTree(userResponse.response.contentAsString).get("id").asText()
|
||||
|
||||
val filmRequest =
|
||||
CreateFilmRequest(
|
||||
title = "Film To Remove",
|
||||
description = "Will be removed",
|
||||
)
|
||||
val filmResponse =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/films")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(filmRequest)),
|
||||
).andReturn()
|
||||
val filmId = objectMapper.readTree(filmResponse.response.contentAsString).get("id").asText()
|
||||
|
||||
mockMvc.perform(post("/api/users/$userId/library/films/$filmId"))
|
||||
mockMvc
|
||||
.perform(delete("/api/users/$userId/library/films/$filmId"))
|
||||
.andExpect(status().isNoContent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get available films should exclude film in user's library`() {
|
||||
val userRequest =
|
||||
CreateUserRequest(
|
||||
name = "Available Films User",
|
||||
email = "availablefilms@example.com",
|
||||
)
|
||||
val userResponse =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/users")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(userRequest)),
|
||||
).andReturn()
|
||||
val userId = objectMapper.readTree(userResponse.response.contentAsString).get("id").asText()
|
||||
|
||||
val film1Request =
|
||||
CreateFilmRequest(
|
||||
title = "Film In Library",
|
||||
description = "This will be in the library",
|
||||
)
|
||||
val film1Response =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/films")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(film1Request)),
|
||||
).andReturn()
|
||||
val film1Id = objectMapper.readTree(film1Response.response.contentAsString).get("id").asText()
|
||||
|
||||
val film2Request =
|
||||
CreateFilmRequest(
|
||||
title = "Film Not In Library",
|
||||
description = "This will not be in the library",
|
||||
)
|
||||
val film2Response =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/films")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(film2Request)),
|
||||
).andReturn()
|
||||
val film2Id = objectMapper.readTree(film2Response.response.contentAsString).get("id").asText()
|
||||
|
||||
mockMvc.perform(post("/api/users/$userId/library/films/$film1Id"))
|
||||
|
||||
val result =
|
||||
mockMvc
|
||||
.perform(
|
||||
get("/api/users/$userId/library/available-films"),
|
||||
).andExpect(status().isOk)
|
||||
.andReturn()
|
||||
|
||||
val responseBody = result.response.contentAsString
|
||||
val films = objectMapper.readTree(responseBody)
|
||||
val returnedIds = films.toList().map { it.get("id").asText() }
|
||||
assert(!returnedIds.contains(film1Id)) { "Film in library should not appear in available films" }
|
||||
assert(returnedIds.contains(film2Id)) { "Film not in library should appear in available films" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get available films for user without library returns all films`() {
|
||||
val userRequest =
|
||||
CreateUserRequest(
|
||||
name = "No Library User",
|
||||
email = "nolibrary@example.com",
|
||||
)
|
||||
val userResponse =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/users")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(userRequest)),
|
||||
).andReturn()
|
||||
val userId = objectMapper.readTree(userResponse.response.contentAsString).get("id").asText()
|
||||
|
||||
val filmRequest =
|
||||
CreateFilmRequest(
|
||||
title = "Available Film",
|
||||
description = "Should appear in available films",
|
||||
)
|
||||
val filmResponse =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/films")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(filmRequest)),
|
||||
).andReturn()
|
||||
val filmId = objectMapper.readTree(filmResponse.response.contentAsString).get("id").asText()
|
||||
|
||||
val result =
|
||||
mockMvc
|
||||
.perform(
|
||||
get("/api/users/$userId/library/available-films"),
|
||||
).andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$[*].id").isArray)
|
||||
.andReturn()
|
||||
|
||||
val responseBody = result.response.contentAsString
|
||||
val films = objectMapper.readTree(responseBody)
|
||||
val returnedIds = films.toList().map { it.get("id").asText() }
|
||||
assert(returnedIds.contains(filmId)) { "Film should appear in available films when user has no library" }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.project.movienight.controllers
|
||||
|
This multiline This multiline `CreateUserRequest(...)` call is missing a trailing comma after the last argument. The main codebase consistently uses trailing commas in multiline argument lists, and with ktlint experimental rules enabled this can fail formatting checks; update this (and other multiline calls in the file) to include trailing commas.
These wildcard imports ( These wildcard imports (`MockMvcRequestBuilders.*`, `MockMvcResultMatchers.*`) will fail ktlint's `no-wildcard-imports` rule (ktlintCheck is part of `check`). Replace them with explicit imports for only the methods/matchers used in this test file.
```suggestion
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
```
This file has consecutive blank lines (e.g., between test cases), which will fail ktlint's standard formatting rules. Remove extra blank lines so there's at most one blank line between members. This file has consecutive blank lines (e.g., between test cases), which will fail ktlint's standard formatting rules. Remove extra blank lines so there's at most one blank line between members.
```suggestion
```
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.project.movienight.adapters.web.dto.request.CreateUserRequest
|
||||
import com.project.movienight.adapters.web.dto.request.EditUserRequest
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@Transactional
|
||||
class UserControllerTest {
|
||||
@Autowired
|
||||
private lateinit var mockMvc: MockMvc
|
||||
|
||||
@Autowired
|
||||
private lateinit var objectMapper: ObjectMapper
|
||||
|
||||
@Test
|
||||
fun `create user should return 201 CREATED`() {
|
||||
val request =
|
||||
CreateUserRequest(
|
||||
name = "John Doe",
|
||||
email = "john@example.com",
|
||||
)
|
||||
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/users")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)),
|
||||
).andExpect(status().isCreated)
|
||||
.andExpect(jsonPath("$.name").value("John Doe"))
|
||||
.andExpect(jsonPath("$.email").value("john@example.com"))
|
||||
.andExpect(jsonPath("$.id").exists())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `edit user should return updated user`() {
|
||||
val createRequest =
|
||||
CreateUserRequest(
|
||||
name = "Old Name",
|
||||
email = "edit@example.com",
|
||||
)
|
||||
|
||||
val response =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/users")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(createRequest)),
|
||||
).andReturn()
|
||||
|
||||
val userId = objectMapper.readTree(response.response.contentAsString).get("id").asText()
|
||||
|
||||
val editRequest = EditUserRequest(name = "New Name")
|
||||
|
||||
mockMvc
|
||||
.perform(
|
||||
patch("/api/users/$userId")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(editRequest)),
|
||||
).andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.name").value("New Name"))
|
||||
.andExpect(jsonPath("$.email").value("edit@example.com"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `delete user should return 204 NO CONTENT`() {
|
||||
val request =
|
||||
CreateUserRequest(
|
||||
name = "User To Delete",
|
||||
email = "delete@example.com",
|
||||
)
|
||||
|
||||
val response =
|
||||
mockMvc
|
||||
.perform(
|
||||
post("/api/users")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)),
|
||||
).andReturn()
|
||||
|
||||
val userId = objectMapper.readTree(response.response.contentAsString).get("id").asText()
|
||||
|
||||
mockMvc
|
||||
.perform(delete("/api/users/$userId"))
|
||||
.andExpect(status().isNoContent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `delete non-existent user should return 404`() {
|
||||
val nonExistentId = "123e4567-e89b-12d3-a456-426614174000"
|
||||
mockMvc
|
||||
.perform(delete("/api/users/$nonExistentId"))
|
||||
.andExpect(status().isNotFound())
|
||||
}
|
||||
}
|
||||
This multiline
EditFilmRequest(...)call is missing a trailing comma after the last argument; with ktlint experimental rules enabled in this repo, that often fails formatting checks. Add the trailing comma to match the style used throughout the codebase.These wildcard imports (
MockMvcRequestBuilders.*,MockMvcResultMatchers.*) will fail ktlint'sno-wildcard-importsrule (ktlintCheck is part ofcheck). Replace them with explicit imports for only the methods/matchers used in this test file.There are consecutive blank lines between tests (e.g., around here), which will fail ktlint's standard formatting rules. Remove the extra blank line(s) so there's at most one blank line between members.
This multiline
CreateFilmRequest(...)call is missing a trailing comma after the last argument; with ktlint experimental rules enabled in this repo, that often fails formatting checks. Add the trailing comma to match the style used throughout the main source files.This
mockMvc.perform(...)is formatted as a multiline call-site but is missing the trailing comma after the argument. The main codebase uses trailing commas for multiline call-sites, and with ktlint experimental rules enabled this can fail formatting checks; update this (and similar call-sites in the file) to include the trailing comma.