test(ui): add design token guardrail tests
This commit is contained in:
+143
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user