Files
comun/docs/testare-ui-vfp.md
Marius Mutu ca465641e8 docs: compactare depanare/testare VFP (dedup + eliminare cazuri specifice)
depanare_testare_vfp.md 226->118 linii, testare-ui-vfp.md 133->90.
- regula SAFETY/dialog modal si -A -T erau enuntate de 3 ori -> o data
- cele 3 capcane "proces agatat" -> un singur algoritm de diagnostic in 3 pasi
- studiul de caz CNRCRT si detaliile ROAGEST (jtva_coloane2, achizitie_import)
  reduse la regula generala + pointer catre scriptul de test
- reguli_lucru pct.4 ramane doar pointer, fara detaliile duplicate de mediu
- sters docs/bash.exe.stackdump (fisier de gunoi, negitat)
Masuratorile si datele concrete pastrate integral.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RqJ7D5ftMbChDyz5mpVkCd
2026-07-24 10:59:30 +03:00

6.9 KiB

Testare UI VFP headless cu harness + screenshots

Harness reutilizabil pentru teste care afiseaza un formular REAL (cu dependinte dummy, fara Oracle), executa actiuni si valideaza vizual prin capturi. Valabil pentru toate proiectele VFP din suita ROA. Alternativa la testare-vfp-mcp.md (care porneste programul principal intreg); capcanele generale de rulare headless (-A -T, SAFETY, script agatat) sunt in depanare_testare_vfp.md.

Fisiere in COMUN\utile\Teste\: vfp_ui_harness.ps1 (orchestrator generic, parametrizat), _precompile.ps1 (precompilare izolata), ui_harness.prg (proceduri de handshake), mock_amessagebox.prg (mock dialog) — infrastructura sta in radacina Teste\; suitele stau in subfoldere pe subiect. Exemplu complet: achizitie_import\test_import_nota_ui.prg + .ps1.

REGULA (Marius, 17/07/2026): testele pe aplicatii frontend exerseaza fluxul REAL al utilizatorului — formularul/butonul/metoda pe care o apeleaza aplicatia, NU introducerea directa a randurilor in cursoare/tabele. Popularea directa sare peste validari/filtre/efecte laterale si da PASS fals (caz real: un articol "adaugat" direct in cursor trecea testul, dar prin fluxul real nu se adauga deloc). Mock-urile raman permise doar pe INFRASTRUCTURA (Oracle, dialoguri modale), nu pe pasii fluxului testat.

Test UI nou in 5 pasi

  1. .prg de test: PUBLIC gcUILog, gcSyncDir; SET SAFETY OFF + SET TALK OFF ca PRIMA linie (vezi capcana a); SET PATH/CLASSLIB/PROCEDURE ca in aplicatie; incarca ULTIMELE ui_harness.prg si (daca ai dialoguri) mock_amessagebox.prg, cu ADDITIVE.
  2. Creeaza dummy-urile minime (goExecutor cu metode reale, goApp pt. ReadIni, poAct pt. curs valutar) + cursoarele cerute de Init (RecordSource-urile grilelor).
  3. Instantiaza clasa, WindowType=0 (modeless - Show() pe modal nu returneaza), Show(), WindowState=2.
  4. Pe fiecare pas: fa actiunea, verifica efectul in date (PASS/FAIL cu helper local), apoi DO HarnessStep WITH <n>, '<mesaj>' (scrie ready_n, asteapta cont_n de la orchestrator sau auto-continua dupa ~30s). La final DO HarnessDone WITH 'done'.
  5. powershell -File vfp_ui_harness.ps1 -TestPrg <test.prg> -Steps @('pas0',...). PNG-uri in screenshots\step_<n>_<eticheta>.png; log in <test>_log.txt.

Capcane / deblocari (toate confirmate in sesiune)

a. SET SAFETY OFF + SET TALK OFF inaintea primului STRTOFILE. Cu SAFETY ON, scrierea log-ului existent scoate un dialog modal care blocheaza rularea (proces viu, "instanta moarta"). Cu TALK ON, SUM/CALCULATE isi echo-eaza rezultatele peste formular in screenshots. b. Lansarea orchestratorului: prin tool cu timeout implicit (~120s) e omorat inainte de final. Ruleaza-l in background + asteapta done.txt, sau timeout 300-600s. NU porni VFP separat de orchestrator - si-l lanseaza singur. c. Asteptarea ready_0: cu .fxp cald START apare in ~2s, la rece mult mai mult (zeci de classlib-uri). -ReadyTimeoutSec generos (implicit 180s); retry NUMAI la "start ratat", nu la "start lent". Detectia "a pornit" se face pe mtime-ul log-ului > momentul lansarii (un log stale tinut de un vfp9 zombi pacaleste verificarea "log ne-gol") - omoara zombii inainte de fiecare lansare. d. vfp9 -A test.prg deschide INTERMITENT editorul in loc sa ruleze (log gol). Lanseaza .fxp-ul PRECOMPILAT. Precompilarea (COMPILE+QUIT) atarna dupa COMPILE si, rulata in ACEEASI sesiune powershell, otraveste lansarile ulterioare - ruleaza-o intr-un proces copil izolat (Start-Process -Wait _precompile.ps1). e. Suitele NU se ruleaza in paralel: _precompile.ps1 face Get-Process vfp9 | Stop-Process -Force (omoara toate instantele), deci un test lansat in paralel il ucide pe cel in curs. f. FARA FURT DE FOCUS (17/07/2026): Graphics.CopyFromScreen fura focus si se corupe daca utilizatorul lucreaza in paralel - nu se mai foloseste. Capturile se fac cu PrintWindow (user32, P/Invoke) pe Process.MainWindowHandle, flag 2 = PW_RENDERFULLCONTENT (fallback 0 daca iese goala); merge cu fereastra acoperita, dar NU minimizata. Fereastra se muta OFF-SCREEN (SetWindowPos, HWND_BOTTOM, x=-4000, SWP_NOACTIVATE) imediat ce apare handle-ul si SE RE-IMPINGE la fiecare pas (VFP se reactiveaza singur la Show()/dialoguri). Consolele powershell copil sunt -WindowStyle Hidden (sigur pentru consola, NU pentru GUI VFP - ascunsa, PrintWindow poate reda gol). Implementat in vfp_ui_harness.ps1 (Take-Screenshot, Push-Offscreen, Wait-MainWindowHandle) si _precompile.ps1. g. Mock de messagebox: FUNCTION amessagebox care returneaza direct valoarea butonului (6=Da), incarcat cu SET PROCEDURE ... ADDITIVE PRIMUL, inaintea fisierelor aplicatiei: la nume duplicat de procedura VFP foloseste fisierul cautat PRIMUL (verificat empiric). Astfel umbreste amessagebox si in apelurile din metodele de clasa. h. Cursorii ceruti de Init: pre-populeaza-i INAINTE de instantiere (Init-ul recreeaza din Oracle cursoarele goale, iar recrearea lasa grid-ul fara coloane, eroare 1925). Pune 1 rand placeholder inainte, apoi ZAP dupa Show() — NU DELETE ALL, care lasa un rand fizic sters si pointerul la EOF (cod care face GO <recno> da eroare 5, vezi conventie_go_recno.md). i. Cursorii trebuie sa aiba EXACT indecsii creati de fluxul real inainte de instantiere (fluxul real ii creeaza in metoda apelanta, ex. un INDEX ON ... TAG ord_doc + SET ORDER TO inainte de CREATEOBJECT). Fara ei cursorul ramane pe ordinea FIZICA, iar logica de tip GO TOP + LOCATE FOR ... alege alt rand decat in productie - rezultat fals, uneori in cascada la apeluri repetate. Verifica in codul apelant ce indecsi se creeaza si replica-i identic. j. Mock-urile de date trebuie sa reproduca structura si semantica REALA a sursei (view Oracle: toate coloanele; relatii intre randuri: toate randurile implicate, nu unul singur cu valori "compuse" manual in test). Un mock incomplet lasa campuri mereu NULL sau ascunde pasul care se testeaza. Cand un flag global activeaza cod suplimentar (ex. gl406), acel cod cere mock-uri in plus - verifica ce apeleaza si adauga metodele lipsa din dummy. k. LOCATE FOR camp == 'literal' pe camp C(n) padded nu gaseste nimic (== e exact) - foloseste ALLTRIM(camp) == 'literal'. l. CREATEOBJECT/ADDPROPERTY se comporta gresit apelate DINTR-O PROCEDURA in acest runtime headless (obiect returnat ca string de 30 spatii; ADDPROPERTY da eroare 11). Din programul PRINCIPAL merg. Construieste obiectele-parametru INLINE in main, nu intr-un helper. (Cauza neclara; reproductibil.) m. Fara SELECT-SQL pe cursorul legat de grid: SELECT ... FROM <cursor> INTO CURSOR cat timp cursorul e RecordSource-ul unui grid viu poate omori procesul vfp9 silentios (fara eroare catchabila, fara semafor). Foloseste xBase nativ (COUNT FOR ... TO, CALCULATE, LOCATE), care nu comuta zona de lucru a grid-ului.