feat: add user selection flow

This commit is contained in:
Urban Modig
2026-07-24 20:21:33 +02:00
parent 9957383e88
commit 1ec7a72908
22 changed files with 778 additions and 40 deletions

View File

@ -0,0 +1,108 @@
package se.rubble.hemhub.user;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
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.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
class UserApiTest {
@Autowired
private WebApplicationContext context;
@Autowired
private UserRepository userRepository;
private MockMvc mockMvc;
@BeforeEach
void setUp() {
userRepository.deleteAll();
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
void listsNoUsersWhenDatabaseIsEmpty() throws Exception {
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$").isEmpty());
}
@Test
void createsAndListsUserWithTrimmedName() throws Exception {
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"name": " Urban "}
"""))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").isString())
.andExpect(jsonPath("$.name").value("Urban"))
.andExpect(jsonPath("$.createdAt").isString())
.andExpect(jsonPath("$.normalizedName").doesNotExist());
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].name").value("Urban"));
}
@Test
void rejectsInvalidNames() throws Exception {
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"name": " "}
"""))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value("INVALID_USER_NAME"));
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\": \"%s\"}".formatted("a".repeat(51))))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value("INVALID_USER_NAME"));
}
@Test
void rejectsDuplicateNameIgnoringCase() throws Exception {
createUser("Urban");
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"name": "urban"}
"""))
.andExpect(status().isConflict())
.andExpect(jsonPath("$.code").value("USER_NAME_ALREADY_EXISTS"));
}
@Test
void listsUsersSortedByDisplayName() throws Exception {
createUser("Urban");
createUser("Anna");
createUser("Bertil");
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].name").value("Anna"))
.andExpect(jsonPath("$[1].name").value("Bertil"))
.andExpect(jsonPath("$[2].name").value("Urban"));
}
private void createUser(String name) throws Exception {
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\": \"%s\"}".formatted(name)))
.andExpect(status().isCreated());
}
}

View File

@ -0,0 +1,7 @@
spring.datasource.url=jdbc:h2:mem:hemhub-test;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DEFAULT_NULL_ORDERING=HIGH;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.open-in-view=false
spring.flyway.enabled=true