test(ui): add design token guardrail tests

This commit is contained in:
Claudecio Martins
2026-10-20 20:16:54 -03:00
parent 6ba1a6a77f
commit caaa1de8a0
@@ -0,0 +1,143 @@
package br.com.cybercore.signer.ui.theme;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Testes de guarda-corpo arquitetural para o sistema de Design Tokens do CyberCore Signer.
* Assegura que nenhuma cor hexadecimal solta seja introduzida fora dos blocos canônicos de tokens,
* garantindo conformidade com o tema escuro/claro e consistência visual rigorosa.
*/
class DesignTokenGuardrailTest {
private static final Pattern HEX_COLOR_PATTERN = Pattern.compile("#([0-9a-fA-F]{3,8})\\b");
@Test
@DisplayName("theme.css não deve conter cores hexadecimais fora dos blocos de tokens (.theme-light e .theme-dark)")
void shouldNotHaveHardcodedHexColorsOutsideTokenDefinitions() throws Exception {
InputStream stream = getClass().getResourceAsStream("/styles/theme.css");
assertThat(stream).withFailMessage("Arquivo /styles/theme.css não encontrado no classpath!").isNotNull();
List<String> violations = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
String line;
int lineNumber = 0;
boolean insideTokenBlock = false;
int openBracesInBlock = 0;
while ((line = reader.readLine()) != null) {
lineNumber++;
String trimmed = line.trim();
// Ignora comentários de linha inteira
if (trimmed.startsWith("/*") && trimmed.endsWith("*/")) {
continue;
}
// Detecta entrada nos blocos de tokens .theme-light e .theme-dark
if (trimmed.contains(".theme-light") || trimmed.contains(".theme-dark")) {
insideTokenBlock = true;
}
if (insideTokenBlock) {
for (char c : line.toCharArray()) {
if (c == '{') {
openBracesInBlock++;
} else if (c == '}') {
openBracesInBlock--;
if (openBracesInBlock <= 0) {
insideTokenBlock = false;
openBracesInBlock = 0;
}
}
}
continue; // Cores hex dentro do bloco de tokens são permitidas
}
// Fora dos blocos de tokens: proibir qualquer cor hexadecimal
// Remove comentários inline antes de testar
String codeOnly = line.replaceAll("/\\*.*?\\*/", "");
Matcher matcher = HEX_COLOR_PATTERN.matcher(codeOnly);
while (matcher.find()) {
violations.add(String.format("Linha %d: '%s' contém cor hexadecimal solta '%s'",
lineNumber, trimmed, matcher.group()));
}
}
}
assertThat(violations)
.withFailMessage("Foram encontradas cores hexadecimais soltas fora dos blocos de tokens em theme.css:\n%s",
String.join("\n", violations))
.isEmpty();
}
@Test
@DisplayName("theme.css não deve conter seletores legados residuais serpro-*")
void shouldNotContainLegacySerproSelectors() throws Exception {
InputStream stream = getClass().getResourceAsStream("/styles/theme.css");
assertThat(stream).isNotNull();
List<String> legacySelectors = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
String line;
int lineNumber = 0;
while ((line = reader.readLine()) != null) {
lineNumber++;
if (line.toLowerCase().contains(".serpro-")) {
legacySelectors.add(String.format("Linha %d: %s", lineNumber, line.trim()));
}
}
}
assertThat(legacySelectors)
.withFailMessage("Foram encontrados seletores legados .serpro-* em theme.css:\n%s",
String.join("\n", legacySelectors))
.isEmpty();
}
@Test
@DisplayName("theme.css deve definir todos os tokens de cores semânticas primários e de superfície")
void shouldDefineAllRequiredSemanticColorTokens() throws Exception {
InputStream stream = getClass().getResourceAsStream("/styles/theme.css");
assertThat(stream).isNotNull();
String content;
try (stream) {
content = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
}
String[] requiredTokens = {
"-fx-color-primary",
"-fx-color-primary-hover",
"-fx-color-surface",
"-fx-color-surface-hover",
"-fx-color-background",
"-fx-color-border",
"-fx-color-text",
"-fx-color-text-muted",
"-fx-color-text-inverse",
"-fx-color-success",
"-fx-color-warning",
"-fx-color-error"
};
for (String token : requiredTokens) {
assertThat(content)
.withFailMessage("Token semântico obrigatório ausente em theme.css: %s", token)
.contains(token);
}
}
}