sync SVN r17998: pret cu TVA pe linie si editarea liniei la introducerea facturii
ofacturare.vc2: - frm_articol_factura: bifa "Pret cu TVA inclus" (preturi_cu_tva) editabila in dialogul per-articol; activa doar pe tipurile unde pretul e editabil. - frm_facturare_articole: buton de modificare deasupra listei + dublu-clic pe linie, ambele redeschid dialogul pe linia curenta (do_modifica); Renunta lasa randul neschimbat. - Plafonul de cantitate la modificare se recalculeaza din stocul disponibil (reversul decrementarii din do_adauga_articol), nu ramane la cantitatea aflata deja pe linie. - Articolele gestionabile: modificarea redeschide tabelul cu gestiuni, pozitionat pe gestiunea liniei; do_alege_stoc primeste tnIdTempExclus, ca linia sa nu se scada pe ea insasi din stoc. Multi-selectia actualizeaza linia si adauga restul ca linii noi. - frm_articol_gest_factura: bifa era desenata sub grd_gestiuni; forma inaltata si bifa mutata sub grid. ofacturare_comun.vc2: scos un SET STEP ON ramas in cod. docs/testare-ui-vfp.md: sectiune noua despre conducerea dialogurilor modale Show(1) din teste (Timer pe _SCREEN, detectie prin _SCREEN.Forms, inchidere prin do_termin/do_renunt) si capcanele platite pe parcurs. Testat headless: Nivel 1 dialog 14 asertii, Nivel 2 factura in compunere 7, Nivel 2 retur 4, Nivel 3 ramura gestionabila 13 - toate PASS, zero FAIL. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
This commit is contained in:
@@ -33,6 +33,56 @@ dialoguri modale), nu pe pasii fluxului testat.
|
||||
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`.
|
||||
|
||||
## Dialoguri modale (`Show(1)`)
|
||||
|
||||
Doua situatii, cu solutii diferite:
|
||||
|
||||
**A. Testul instantiaza el dialogul** — `WindowType = 0` inainte de `Show()` (pasul 3 de mai sus).
|
||||
`Show()` revine imediat si conduci formularul pas cu pas. Prefera intotdeauna varianta asta.
|
||||
|
||||
**B. `Show(1)` e hardcodat in metoda aplicatiei** (ex. `frm_facturare_articole.do_adauga_articol` /
|
||||
`do_modifica`): testul nu are referinta la dialog, deci nu poate seta `WindowType`, iar fluxul real
|
||||
cere sa treaca prin buton. Se conduce dintr-un **Timer pe `_SCREEN`**, pregatit INAINTE de actiunea
|
||||
care deschide dialogul:
|
||||
|
||||
1. `_SCREEN.AddObject('tmrDrv','Timer')`, `Interval = 200`,
|
||||
`BINDEVENT(_SCREEN.tmrDrv, 'Timer', <obiect driver>, 'Executa')`, `Enabled = .T.`
|
||||
2. `Show(1)` **chiar pompeaza mesaje Windows** cat e modal — timerul ticaie normal (masurat: 229
|
||||
tick-uri in 46s). Bucla modala nu e oarba la evenimente externe.
|
||||
3. **Detectia formularului: `_SCREEN.Forms(i)` / `_SCREEN.FormCount`**, potrivit pe `.Class`.
|
||||
**`_SCREEN.ActiveForm` NU merge headless** — a ramas gol la toate cele 229 de tick-uri: depinde
|
||||
de `WM_ACTIVATE`, care nu se declanseaza fara focus real, pe cand colectia `Forms` contine
|
||||
formularul indiferent de activare.
|
||||
4. **Referinta la controale**: `loForm.<nume>` merge normal; iterarea `loForm.Controls(i)` cu
|
||||
potrivire pe `.Name` e alternativa robusta (utila si ca diagnostic, pentru ca listeaza ce EXISTA
|
||||
cu adevarat). **Daca accesul da 1925 "Unknown member" pe un control care sigur e in clasa,
|
||||
suspecteaza mediul de test, nu colectia**: o eroare in constructia unui obiect adaugat mai
|
||||
devreme opreste adaugarea celor de dupa, iar formularul ramane incomplet fara sa se plange (caz
|
||||
real: lipsa cursorului `saft_taxtable`, capcana j, a lasat instanta cu 21 de controale in loc de
|
||||
25, iar controlul urmator din ordinea de adaugare "disparea"). Verifica intai `ControlCount` si
|
||||
lista de nume.
|
||||
5. **Inchiderea**: `do_termin()` (gateaza pe `inainte_de_do_termin()`, seteaza `gnButon = 1` si
|
||||
elibereaza — `_frm_base.vc2:363-371`) sau `do_renunt()`. **Daca validarea respinge, `do_termin()`
|
||||
nu seteaza `gnButon` si NU elibereaza formularul, deci `Show(1)` ramane blocat** — in testele
|
||||
care asteapta o respingere de validare, iesi prin `do_renunt()`.
|
||||
6. **Driverul se instrumenteaza obligatoriu**: log pe fiecare pas, `TRY/CATCH` cu
|
||||
`ErrorNo`/`Message`/`LineNo`, iar steagul "am tratat dialogul" se seteaza **dupa** interactiunea
|
||||
reusita, nu inainte. Altfel prima eroare e invizibila si blocheaza orice reincercare — simptomul
|
||||
e tick-uri la nesfarsit pana la timeout, fara nicio urma in log.
|
||||
|
||||
**Regula de metoda, invatata scump**: mediul unei suite noi se mosteneste din suita care **TRECE**,
|
||||
nu din una care esueaza. Un mediu copiat dintr-un test nevalidat a produs trei defecte succesive
|
||||
(cursor `saft_taxtable` lipsa, mock `poArticol` incomplet, nume de variabila coliziv), fiecare
|
||||
descoperit dupa cate o rulare, si toate aratau ca defecte de aplicatie sau ca "test agatat". Cand
|
||||
doua suite au nevoie de acelasi mediu, **extrage-l intr-un singur loc** (cu grija la capcana l
|
||||
pentru constructia obiectelor).
|
||||
|
||||
Doua non-dovezi, ca sa nu se piarda timp pe ele:
|
||||
- `AMEMBERS(a, o)` **fara flagul 2** intoarce proprietati/metode, **nu** obiectele continute —
|
||||
absenta unui control din acea lista nu inseamna ca lipseste din clasa.
|
||||
- `==` pe doua obiecte da eroare **107** "Operator/operand type mismatch"; pentru identitate se
|
||||
foloseste `COMPOBJ()`.
|
||||
|
||||
## Capcane / deblocari
|
||||
|
||||
a. **`SET SAFETY OFF` + `SET TALK OFF` inaintea primului `STRTOFILE`.** Cu SAFETY ON, scrierea
|
||||
@@ -90,7 +140,10 @@ j. **Mock-urile de date trebuie sa reproduca structura si semantica REALA a surs
|
||||
`saft_taxtable` real (nu doar mock pe `goExecutor` - `update_jtva_coloane` face
|
||||
`USE saft_taxtable` direct pe alias). Fara ele, simptomul e dialog nativ Windows "Open" (cauta
|
||||
`saft_taxtable.dbf`) care blocheaza headless la nesfarsit, fara linie noua in log si CPU 0% -
|
||||
vezi `depanare_testare_vfp.md` pentru diagnostic cu `EnumWindows`/`PrintWindow`.
|
||||
vezi `depanare_testare_vfp.md` pentru diagnostic cu `EnumWindows`/`PrintWindow`. Acelasi
|
||||
simptom apare si FARA `gl406`: un control cu `RowSourceType=3` legat direct in clasa de un SQL
|
||||
pe `saft_taxtable` (ex. combo pe explicatie SAFT) isi evalueaza `RowSource` la constructia
|
||||
formularului indiferent de `gl406` sau de `Visible=.F.` - cursorul mock trebuie creat oricum.
|
||||
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
|
||||
@@ -115,3 +168,10 @@ o. **Formularul resincronizeaza singur dupa o alegere din grid** (`lSyncPending`
|
||||
realiniaza dupa el). Scrie assert-urile pe starea de DUPA resincronizare, pe un efect pe care
|
||||
resincronizarea NU il repara (acolo: `scc`-ul randului T, atins doar la schimbarea explicatiei)
|
||||
- altfel testul pica fara sa fie ceva gresit in cod.
|
||||
p. **Nu numi variabilele ca functii built-in VFP.** VFP e insensibil la litere mari/mici, iar la
|
||||
coliziune **functia castiga**. Caz real: `LOCAL loCk` pentru referinta la un checkbox se ciocneste
|
||||
cu `LOCK()` — `loCk.Value = 1` da eroarea **1924 "LOCK is not an object"**, iar `VARTYPE(loCk)`
|
||||
evalueaza `LOCK()` si intoarce `'L'`, deci verificarile de tipul `VARTYPE(lo...) == 'O'` ies
|
||||
**tacut false** si par sa spuna ca obiectul nu a fost gasit — masuratoarea e stricata, nu
|
||||
rezultatul. Simptom de recunoscut: mesajul de eroare contine numele **cu majuscule** al unei
|
||||
functii VFP, nu numele variabilei asa cum ai scris-o. Prefixeaza distinctiv (`loBifa`, `loCtrl`).
|
||||
|
||||
Reference in New Issue
Block a user