feat(reporting): add role dashboard template contracts

This commit is contained in:
sechmachine
2026-08-15 00:11:42 +07:00
parent eadf6a7528
commit 5638286b90
10 changed files with 337 additions and 9 deletions
@@ -0,0 +1,30 @@
package com.lab.labtimesheet.feature.reporting;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
class ReportingArchitectureTest {
@Test
void reportingUsesFeaturePackageWithoutGlobalLayersOrPlaceholderBoundary() throws Exception {
Class<?> view = Class.forName("com.lab.labtimesheet.feature.reporting.model.dto.DashboardView");
assertTrue(view.isSealed());
assertFalse(view.getPackageName().startsWith("com.lab.labtimesheet.model"));
assertMissing("com.lab.labtimesheet.controller.DashboardController");
assertMissing("com.lab.labtimesheet.dto.DashboardView");
assertMissing("com.lab.labtimesheet.exception.DashboardAccessDeniedException");
assertMissing("com.lab.labtimesheet.model.DashboardAccount");
assertMissing("com.lab.labtimesheet.repository.DashboardRepository");
assertMissing("com.lab.labtimesheet.service.DashboardService");
assertMissing("com.lab.labtimesheet.reporting.ModuleBoundary");
assertMissing("com.lab.labtimesheet.feature.reporting.ModuleBoundary");
}
private void assertMissing(String className) {
assertThrows(ClassNotFoundException.class, () -> Class.forName(className));
}
}
@@ -0,0 +1,100 @@
package com.lab.labtimesheet.feature.reporting.controller;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.lab.labtimesheet.feature.reporting.model.dto.DashboardView;
import java.time.LocalDate;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
import org.springframework.context.annotation.Import;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@WebMvcTest(DashboardTemplateWebTest.TemplateController.class)
@Import(DashboardTemplateWebTest.TemplateController.class)
class DashboardTemplateWebTest {
private final MockMvc mvc;
@Autowired
DashboardTemplateWebTest(MockMvc mvc) {
this.mvc = mvc;
}
@Test
@WithMockUser(username = "admin@example.test", roles = "ADMIN")
void adminTemplateRendersSystemMetricsAndOnlyAdminAction() throws Exception {
mvc.perform(get("/template-contract/dashboard/admin"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("System overview")))
.andExpect(content().string(containsString("Active accounts</div><div class=\"metric-value\">3")))
.andExpect(content().string(containsString("Create account")))
.andExpect(content().string(not(containsString("Create Project"))))
.andExpect(content().string(not(containsString("Check in"))));
}
@Test
@WithMockUser(username = "mentor@example.test", roles = "MENTOR")
void mentorTemplateRendersOwnedScopeAndOnlyMentorAction() throws Exception {
mvc.perform(get("/template-contract/dashboard/mentor"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("Good morning, Minh Mentor")))
.andExpect(content().string(containsString("Active owned Projects</div><div class=\"metric-value\">1")))
.andExpect(content().string(containsString("Pending decisions</div><div class=\"metric-value\">2")))
.andExpect(content().string(containsString("Create Project")))
.andExpect(content().string(not(containsString("Create account"))))
.andExpect(content().string(not(containsString("Check in"))));
}
@Test
@WithMockUser(username = "intern@example.test", roles = "INTERN")
void internTemplateRendersOwnWorkAndAttendanceAction() throws Exception {
mvc.perform(get("/template-contract/dashboard/intern"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("Today")))
.andExpect(content().string(containsString("Checked in")))
.andExpect(content().string(containsString("My real task")))
.andExpect(content().string(containsString("18/08/2026")))
.andExpect(content().string(containsString("Check out")))
.andExpect(content().string(not(containsString("Create Project"))))
.andExpect(content().string(not(containsString("Create account"))));
}
@Controller
public static class TemplateController {
@GetMapping("/template-contract/dashboard/admin")
String admin(Model model) {
model.addAttribute("dashboard", new DashboardView.Admin(3, 1, 2, 1));
return "dashboard/admin";
}
@GetMapping("/template-contract/dashboard/mentor")
String mentor(Model model) {
model.addAttribute("dashboard", new DashboardView.Mentor("Minh Mentor", 1, 2, 1, 2));
return "dashboard/mentor";
}
@GetMapping("/template-contract/dashboard/intern")
String intern(Model model) {
model.addAttribute("dashboard", new DashboardView.Intern(
"Mai Intern",
DashboardView.AttendanceState.CHECKED_IN,
1,
1,
1,
List.of(new DashboardView.AssignedTask(
"My real task", "Intern Portal", "IN_PROGRESS", LocalDate.of(2026, 8, 18)))));
return "dashboard/intern";
}
}
}