feat(infra): auto-commit con 10 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -169,6 +169,39 @@ Para diagnosticar un diff: revisar el PNG actual en
|
||||
`cpp/build/tests/visual_actual/<demo>.png` vs el golden en
|
||||
`cpp/tests/golden/<demo>.png`.
|
||||
|
||||
### Tests de UI headless (Dear ImGui Test Engine)
|
||||
|
||||
`fn::run_app_test` (el harness del Test Engine usado por `/e2e-cpp`) crea la
|
||||
ventana GLFW **oculta por defecto** (`GLFW_VISIBLE=FALSE`). El contexto OpenGL
|
||||
real se crea igual, así que el render que el Test Engine ejercita sigue siendo
|
||||
fiel, pero la ventana nunca se mapea en pantalla: cero parpadeo y no roba foco
|
||||
mientras corre la suite. Es el comportamiento preferente para tests de
|
||||
frontend en C++.
|
||||
|
||||
Control del modo (en orden de prioridad):
|
||||
|
||||
| Mecanismo | Efecto |
|
||||
|---|---|
|
||||
| `FN_HEADLESS=0` (env) | Fuerza ventana **visible** — para depurar un test a ojo. |
|
||||
| `FN_HEADLESS=1` (env) | Fuerza oculta (es el default del path de test). |
|
||||
| `cfg.headless = true` | Oculta también `fn::run_app` (apps reales, p.ej. smoke/capture). |
|
||||
| sin nada | `run_app_test` → oculta; `run_app` → visible. |
|
||||
|
||||
Cómo correr la suite sin parpadeo:
|
||||
|
||||
```bash
|
||||
# Host con GL nativo (GPU real): binario directo, ventana oculta, sin parpadeo.
|
||||
./build/linux_tests/apps/<app>/<app>_tests
|
||||
|
||||
# CI / WSL sin display: display virtual en RAM (también headless).
|
||||
xvfb-run -a -s "-screen 0 1280x800x24" \
|
||||
env LIBGL_ALWAYS_SOFTWARE=1 GALLIUM_DRIVER=llvmpipe \
|
||||
./build/linux_tests/apps/<app>/<app>_tests
|
||||
|
||||
# Ver un test a ojo (desactiva headless):
|
||||
FN_HEADLESS=0 ./build/linux_tests/apps/<app>/<app>_tests
|
||||
```
|
||||
|
||||
### CI gate `check_tested.sh`
|
||||
|
||||
`cpp/scripts/check_tested.sh [days]` (default `30`) consulta `registry.db` y
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
@@ -647,6 +648,25 @@ static void draw_header_badge_on_floating_panels(const AppConfig& cfg) {
|
||||
}
|
||||
}
|
||||
|
||||
// Resuelve si la ventana GLFW debe crearse oculta (GLFW_VISIBLE=FALSE).
|
||||
// default_hidden : politica base del path de entrada (apps reales = false,
|
||||
// tests de UI = true).
|
||||
// config_headless: AppConfig.headless explicito de la app.
|
||||
// El entorno FN_HEADLESS gana sobre ambos: "0"/"false" fuerza visible,
|
||||
// cualquier otro valor no vacio fuerza oculta. Sin la variable, se respeta
|
||||
// default_hidden || config_headless.
|
||||
static bool resolve_headless(bool default_hidden, bool config_headless) {
|
||||
bool hidden = default_hidden || config_headless;
|
||||
if (const char* e = std::getenv("FN_HEADLESS")) {
|
||||
if (std::strcmp(e, "0") == 0 || std::strcmp(e, "false") == 0) {
|
||||
hidden = false;
|
||||
} else if (e[0] != '\0') {
|
||||
hidden = true;
|
||||
}
|
||||
}
|
||||
return hidden;
|
||||
}
|
||||
|
||||
int run_app(AppConfig config, std::function<void()> render_fn) {
|
||||
// Logger primero para capturar fallos del propio init (GLFW, ventana, GL).
|
||||
if (config.log.file_path != nullptr) {
|
||||
@@ -672,6 +692,11 @@ int run_app(AppConfig config, std::function<void()> render_fn) {
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
|
||||
// Apps reales: ventana visible por defecto. Solo se oculta si la app pide
|
||||
// headless o el entorno FN_HEADLESS lo fuerza (smoke/capture sin parpadeo).
|
||||
const bool hidden = resolve_headless(/*default_hidden=*/false, config.headless);
|
||||
glfwWindowHint(GLFW_VISIBLE, hidden ? GLFW_FALSE : GLFW_TRUE);
|
||||
|
||||
GLFWwindow* window = glfwCreateWindow(config.width, config.height, config.title, nullptr, nullptr);
|
||||
if (!window) {
|
||||
fprintf(stderr, "Failed to create GLFW window\n");
|
||||
@@ -1178,6 +1203,13 @@ int run_app_test(AppConfig config,
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
|
||||
// Tests de frontend: ventana OCULTA por defecto (headless) para no parpadear
|
||||
// en la pantalla del desarrollador ni robar foco mientras el Test Engine
|
||||
// ejercita la UI. El contexto GL real se crea igual, asi que el render sigue
|
||||
// siendo fiel. Opt-out para depurar visualmente: FN_HEADLESS=0.
|
||||
const bool hidden = resolve_headless(/*default_hidden=*/true, config.headless);
|
||||
glfwWindowHint(GLFW_VISIBLE, hidden ? GLFW_FALSE : GLFW_TRUE);
|
||||
|
||||
GLFWwindow* window = glfwCreateWindow(
|
||||
config.width, config.height,
|
||||
config.title ? config.title : "fn_test", nullptr, nullptr);
|
||||
|
||||
@@ -101,6 +101,21 @@ struct AppConfig {
|
||||
int height = 720;
|
||||
bool vsync = true;
|
||||
bool viewports = true; // Multi-viewport ON por defecto: ventanas ImGui arrastrables fuera del main window
|
||||
|
||||
// Headless: si true, la ventana GLFW se crea oculta (GLFW_VISIBLE=FALSE).
|
||||
// El contexto OpenGL real se sigue creando y el render ocurre offscreen,
|
||||
// por lo que las pruebas visuales y de UI siguen siendo fieles, pero la
|
||||
// ventana nunca se mapea en pantalla (cero parpadeo, no roba foco).
|
||||
//
|
||||
// Politica por path:
|
||||
// - run_app (apps reales): default visible (headless = false).
|
||||
// - run_app_test (Dear ImGui Test Engine): default OCULTA. Los tests de
|
||||
// frontend corren headless salvo opt-out explicito para debug visual.
|
||||
//
|
||||
// Override por entorno (gana sobre el default del path y sobre este flag):
|
||||
// FN_HEADLESS=1 / true -> fuerza ventana oculta.
|
||||
// FN_HEADLESS=0 / false -> fuerza ventana visible (ej. ver un test).
|
||||
bool headless = false;
|
||||
ThemeMode theme = ThemeMode::FnDark; // Identidad visual unificada por defecto
|
||||
float bg_r = 0.102f; // fn_tokens::colors::bg (dark.7 #1A1B1E)
|
||||
float bg_g = 0.106f;
|
||||
|
||||
Reference in New Issue
Block a user