Verificare ANAF la alegerea partenerului
ocautare.prg - miezul functionalitatii: - anaf_verif_cautare: verdictul ANAF pe randul curent din formularul de cautare (label sub grid), la data documentului; discordantele si codurile fiscale invalide cu rosu; F4 sau click deschide detaliile. - ANAF_StarePartener, cu cache pe sesiune, excludere parteneri externi si persoane fizice; ANAF_ValidareCod pentru CIF/CNP. - ANAF_NivelVerificare: cascada RC_ANAF_VERIF_SELECTIE (kill-switch settings.ini > optiuni utilizator > optiuni firma > implicit 1), cu cache invalidat la schimbarea firmei sau utilizatorului; ANAF_ComutaVerificare pentru punctul de meniu. - Detalii: alegerea variantei corecte de partener din perechea RO / fara RO, cu discriminator "are documente in perioada"; dupa Da sau Nu se inchide cautarea si se revine in formular cu partenerul ales (AplicaInlocuirePartenerANAF). - ANAF_CaData: data documentului poate veni si ca DateTime (tact.dataact). - Banda proprie sub grid pentru label: formularul creste cu 54, gridul isi pierde ancorarea de jos si primeste inaltimea din AjusteazaBanda, legata de Resize si Activate - formularul isi reaseaza gridul dupa Show, deci Activate e momentul util. validare.prg: ANAF_VerificaCuiSingle, wrapper single-CUI peste serviciul ANAF, cu data verificarii si o singura eroare logata pe sesiune. cauta_alfa.prg: hook generic - ataseaza poVerifAlegere pe formularul de cautare inainte de Show si il detaseaza dupa. Apelanti opt-in (lVerificaANAF): baza.vc2 (lookup-ul generic de partener din formularele actbaza/actbaza2007 lansate din meniuri), onote_contabile.vc2 (partener debit/credit), omodificari.vc2 (do_cauta din cele trei clase de modificare, cu data notei), ofacturare.vc2 (client, furnizor). Casa/banca ramane in afara: acolo partenerul se alege pentru imperecherea facturilor. cauta_alfa_forms.vc2: F4 deschide detaliile, iar terminarea cautarii trece prin VerificaAlegere. Teste: suita headless pentru fluxul de verificare (utile/Teste/partener_anaf/), cu mock pentru apelul ANAF si pentru dialoguri. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019H3r66sVojGhgaKq5niu1u
This commit is contained in:
33
utile/Teste/mock_ainputbox.prg
Normal file
33
utile/Teste/mock_ainputbox.prg
Normal file
@@ -0,0 +1,33 @@
|
||||
* mock_ainputbox.prg - inlocuieste FUNCTION aInputBox (din oproceduri_comune.prg) in teste, ca
|
||||
* fereastra modala de introducere sa NU blocheze testul headless. Se incarca cu SET PROCEDURE ...
|
||||
* ADDITIVE langa mock_amessagebox.prg (aceeasi rezolutie de nume: castiga fisierul de proceduri
|
||||
* deschis cel mai recent).
|
||||
* gnMockInputBox (PUBLIC, optional): valoarea returnata la fiecare apel (implicit 1).
|
||||
* gcMockInputSecventa (PUBLIC, optional): lista de valori separate prin virgula, returnate pe rand
|
||||
* (apelul N ia valoarea N, ultimul apel se repeta) - pentru fluxuri care reiau intrebarea, ex.
|
||||
* numar de varianta invalid urmat de unul valid. Are prioritate fata de gnMockInputBox.
|
||||
* gnMockInputCount (PUBLIC, optional): contor de apeluri - pentru aserti de tipul "nu s-a cerut
|
||||
* numarul variantei cand exista o singura varianta".
|
||||
* gcMockUltimPrompt (PUBLIC, optional): textul ultimului prompt primit.
|
||||
FUNCTION aInputBox
|
||||
LPARAMETERS tcPrompt, tcTitle, txDefaultValue, tnLeft, tnTop, tcFormat, tcInputMask, tcPasswordChar
|
||||
LOCAL luRaspuns, lnApel, lcValoare
|
||||
IF TYPE('gnMockInputCount') = 'N'
|
||||
gnMockInputCount = gnMockInputCount + 1
|
||||
lnApel = gnMockInputCount
|
||||
ELSE
|
||||
lnApel = 1
|
||||
ENDIF
|
||||
luRaspuns = IIF(TYPE('gnMockInputBox') = 'N', gnMockInputBox, 1)
|
||||
IF TYPE('gcMockInputSecventa') = 'C' AND !EMPTY(gcMockInputSecventa)
|
||||
lcValoare = GETWORDNUM(gcMockInputSecventa, MIN(m.lnApel, GETWORDCOUNT(gcMockInputSecventa, ',')), ',')
|
||||
luRaspuns = VAL(m.lcValoare)
|
||||
ENDIF
|
||||
IF TYPE('gcMockUltimPrompt') = 'C'
|
||||
gcMockUltimPrompt = TRANSFORM(tcPrompt)
|
||||
ENDIF
|
||||
IF TYPE('gcUILog') = 'C'
|
||||
DO HarnessLog WITH 'MOCK aInputBox apelat: [' + ALLTRIM(TRANSFORM(tcPrompt)) + '] -> returnez ' + TRANSFORM(luRaspuns)
|
||||
ENDIF
|
||||
RETURN luRaspuns
|
||||
ENDFUNC
|
||||
@@ -10,6 +10,8 @@
|
||||
* mock-ul raspunde cu ACEASTA valoare in loc de gnMockRaspuns - necesar cand doua dialoguri
|
||||
* diferite (recalculare suma in lei / actualizare total factura) apar in ACELASI apel de metoda
|
||||
* si trebuie sa primeasca raspunsuri diferite (ex. Da la primul, Nu la al doilea).
|
||||
* gcMockUltimMesaj / gnMockUltimTip (PUBLIC, optional): daca testul declara gcMockUltimMesaj ca
|
||||
* sir, mock-ul memoreaza in ele mesajul si tipul ultimului apel - pentru aserti pe TEXTUL dialogului.
|
||||
FUNCTION amessagebox
|
||||
LPARAMETERS tcMessage, tnDialogBoxType, tcTitle, tcFont, tnTimeOut, tnTimeoutValue
|
||||
LOCAL lnRaspuns
|
||||
@@ -18,6 +20,10 @@ FUNCTION amessagebox
|
||||
ELSE
|
||||
lnRaspuns = IIF(TYPE('gnMockRaspuns') = 'N', gnMockRaspuns, 6)
|
||||
ENDIF
|
||||
IF TYPE('gcMockUltimMesaj') = 'C'
|
||||
gcMockUltimMesaj = TRANSFORM(tcMessage)
|
||||
gnMockUltimTip = IIF(TYPE('tnDialogBoxType') = 'N', tnDialogBoxType, 0)
|
||||
ENDIF
|
||||
IF TYPE('gcUILog') = 'C'
|
||||
DO HarnessLog WITH 'MOCK amessagebox apelat: [' + ALLTRIM(TRANSFORM(tcMessage)) + '] -> returnez ' + TRANSFORM(lnRaspuns)
|
||||
ENDIF
|
||||
|
||||
34
utile/Teste/partener_anaf/mock_anaf_verificare.prg
Normal file
34
utile/Teste/partener_anaf/mock_anaf_verificare.prg
Normal file
@@ -0,0 +1,34 @@
|
||||
* mock_anaf_verificare.prg - inlocuieste FUNCTION ANAF_VerificaCuiSingle (validare.prg) cu raspunsuri
|
||||
* preconfigurate, ca testul UI sa NU faca apeluri reale la serviciul ANAF (lent/nedeterminist).
|
||||
* Se incarca cu SET PROCEDURE ... ADDITIVE INAINTEA lui test_init_env_auto (care incarca validare.prg
|
||||
* real) - la nume duplicat de FUNCTION, VFP foloseste fisierul cautat PRIMUL (verificat empiric,
|
||||
* vezi COMUN\docs\testare-ui-vfp.md capcana g). NormalizeazaCUI (validare.prg) NU e suprascrisa -
|
||||
* se foloseste cea reala.
|
||||
* IMPORTANT: goANAFMockData (Collection cu raspunsuri, cheie 'C'+cui normalizat) si gnANAFCallCount
|
||||
* (contor apeluri reale, nu din cache) se construiesc INLINE in programul principal al testului,
|
||||
* NU aici si NU intr-o PROCEDURE - vezi capcana l din depanare_testare_vfp.md (CREATEOBJECT/
|
||||
* ADDPROPERTY apelate dintr-o PROCEDURA se comporta gresit in acest runtime headless; SET PROCEDURE
|
||||
* nici nu executa codul de top-level al acestui fisier, doar inregistreaza FUNCTION-ul de mai jos).
|
||||
* Contor apeluri: gnANAFCallCount creste doar cand mock-ul e efectiv apelat (ANAF_StarePartener
|
||||
* verifica intai goCacheANAF_Sesiune - cache-hit NU ajunge aici).
|
||||
* runda 12: tdData (data documentului, trimisa de ANAF_StarePartener) e retinuta in gdANAFUltimaData,
|
||||
* ca testul sa poata verifica ca data ajunge efectiv la wrapper.
|
||||
FUNCTION ANAF_VerificaCuiSingle
|
||||
LPARAMETERS tcCui, tdData
|
||||
LOCAL lcCui, lcKey
|
||||
IF TYPE('goANAFMockData') <> 'O'
|
||||
RETURN .NULL.
|
||||
ENDIF
|
||||
IF TYPE('gnANAFCallCount') = 'N'
|
||||
gnANAFCallCount = gnANAFCallCount + 1
|
||||
ENDIF
|
||||
IF VARTYPE(m.tdData) = 'D'
|
||||
gdANAFUltimaData = m.tdData
|
||||
ENDIF
|
||||
lcCui = NormalizeazaCUI(m.tcCui)
|
||||
lcKey = 'C' + m.lcCui
|
||||
IF goANAFMockData.GetKey(m.lcKey) = 0
|
||||
RETURN .NULL. && CUI neconfigurat - simuleaza "fara raspuns" (degradare tacuta)
|
||||
ENDIF
|
||||
RETURN goANAFMockData.Item(m.lcKey)
|
||||
ENDFUNC
|
||||
146
utile/Teste/partener_anaf/shot_dialog_anaf.prg
Normal file
146
utile/Teste/partener_anaf/shot_dialog_anaf.prg
Normal file
@@ -0,0 +1,146 @@
|
||||
* shot_dialog_anaf.prg - captureaza dialogul REAL (AMESSAGEBOX neinlocuit) generat de
|
||||
* anaf_verif_cautare.VerificaAlegere() (ocautare.prg), pt. o captura de ecran cu mesajul de
|
||||
* PRODUCTIE real (AntetDialog/ListaCorecti/TextAnaf) - nu text scris de mana in script.
|
||||
* Mock ANAF (raspunsuri preconfigurate, fara apel real la anaf.ro) ca in suita principala, dar
|
||||
* FARA mock_amessagebox.prg: AMESSAGEBOX ramane cea reala din oproceduri_comune.prg. Acea functie
|
||||
* suporta DOUA ramuri: formularul MessageBox.vcx (daca acea clasa e incarcata) sau MESSAGEBOX()
|
||||
* nativ altfel (fereastra Windows separata, clasa #32770) - formularul VCX nu se randeaza in acest
|
||||
* mediu minimal headless (confirmat: se blocheaza fara eroare, indiferent de suita testata), asa ca
|
||||
* acest script elibereaza clasa (RELEASE CLASSLIB, doar in sesiunea proprie, niciun fisier atins)
|
||||
* ca AMESSAGEBOX sa aleaga singura ramura nativa. Fereastra nativa BLOCHEAZA scriptul pana e inchisa
|
||||
* din exterior (shot_dialog_anaf.ps1 o gaseste dupa semnalul ready_0, o captureaza cu PrintWindow
|
||||
* si o inchide cu WM_CLOSE).
|
||||
SET SAFETY OFF
|
||||
SET TALK OFF
|
||||
SET DELETED ON
|
||||
SET EXACT ON
|
||||
SET CENTURY ON
|
||||
SET DATE DMY
|
||||
SET NULLDISPLAY TO ''
|
||||
CLOSE DATABASES
|
||||
|
||||
PUBLIC gcUILog, gcSyncDir
|
||||
gcUILog = "D:\ROA\ROACONT\COMUN\utile\Teste\partener_anaf\shot_dialog_anaf_log.txt"
|
||||
gcSyncDir = "D:\ROA\ROACONT\COMUN\utile\Teste\partener_anaf\uisync_dialog\"
|
||||
STRTOFILE("START " + TTOC(DATETIME()) + CHR(13)+CHR(10), gcUILog)
|
||||
|
||||
ON ERROR DO VpaErrD WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
|
||||
ON SHUTDOWN QUIT
|
||||
|
||||
*-- doar mock-ul ANAF (raspunsuri) - FARA mock_amessagebox: AMESSAGEBOX ramane cea reala din productie
|
||||
SET PROCEDURE TO "D:\ROA\ROACONT\COMUN\utile\Teste\ui_harness.prg" ADDITIVE
|
||||
SET PROCEDURE TO "D:\ROA\ROACONT\COMUN\utile\Teste\partener_anaf\mock_anaf_verificare.prg" ADDITIVE
|
||||
DO VpaLogD WITH 'mock ANAF incarcat (fara mock amessagebox - dialog REAL)'
|
||||
|
||||
DO D:\ROA\ROACONT\COMUN\utile\Teste\test_init_env_auto.prg WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
|
||||
IF gnHandle <= 0
|
||||
DO VpaLogD WITH 'EROARE: conectare Oracle esuata - GATA'
|
||||
DO HarnessDone WITH 'done-error'
|
||||
QUIT
|
||||
ENDIF
|
||||
DO VpaLogD WITH 'mediu OK, schema=' + gcS
|
||||
|
||||
*-- test_init_env_auto incarca "Set Classlib To Messagebox Additive" (ca in roacont.prg) - cu ea
|
||||
*-- incarcata, AMESSAGEBOX (productie) afiseaza formularul MessageBox.vcx (nu s-a randat in acest
|
||||
*-- mediu minimal headless, fara legatura cu suita testata). RELEASE CLASSLIB doar in acest script
|
||||
*-- de captura (nu atinge niciun fisier) - AMESSAGEBOX ramane codul REAL, foloseste doar cealalta
|
||||
*-- ramura pe care el insusi o suporta: MESSAGEBOX() nativ, fereastra Windows separata (#32770).
|
||||
RELEASE CLASSLIB Messagebox
|
||||
DO VpaLogD WITH 'Set(Classlib) dupa RELEASE: [' + SET('Classlib') + ']'
|
||||
|
||||
PUBLIC goANAFMockData, gnANAFCallCount, gdANAFUltimaData
|
||||
goANAFMockData = CREATEOBJECT('Collection')
|
||||
gnANAFCallCount = 0
|
||||
gdANAFUltimaData = {}
|
||||
LOCAL loRespDiscord
|
||||
loRespDiscord = CREATEOBJECT('Empty')
|
||||
ADDPROPERTY(loRespDiscord, 'cui', '7654321')
|
||||
ADDPROPERTY(loRespDiscord, 'scpTVA', .T.)
|
||||
ADDPROPERTY(loRespDiscord, 'statusInactivi', .F.)
|
||||
ADDPROPERTY(loRespDiscord, 'denumire', 'DISCORD SRL ANAF')
|
||||
ADDPROPERTY(loRespDiscord, 'mesaj', '')
|
||||
goANAFMockData.Add(loRespDiscord, 'C7654321')
|
||||
DO VpaLogD WITH 'mock ANAF: CUI 7654321 configurat'
|
||||
|
||||
PUBLIC gnIdDiscord, gnIdPereche
|
||||
|
||||
TRY
|
||||
DO CurataDateTestD
|
||||
DO CreeazaDateTestD
|
||||
|
||||
LOCAL lnOk
|
||||
lnOk = goExecutor.oExecute([SELECT DISTINCT DENUMIRE, NUME, COD_FISCAL, ID_PART, INACTIV FROM NOM_PARTENERI ] + ;
|
||||
[WHERE ID_PART IN (] + TRANSFORM(gnIdDiscord) + [,] + TRANSFORM(gnIdPereche) + [) AND INACTIV = 0 ORDER BY ID_PART], 'ctestdialog')
|
||||
|
||||
PUBLIC goFormD, poVerifD
|
||||
goFormD = CREATEOBJECT('cauta_alfa_form', 'ctestdialog', '', 'Denumire,Nume,Cod fiscal,Id,Inactiv', ;
|
||||
'denumire,nume,cod_fiscal,id_part,inactiv', .F., '', 1, '', '', '', '')
|
||||
goFormD.crs_cursor = 'ctestdialog'
|
||||
goFormD.lAles = .F.
|
||||
poVerifD = CREATEOBJECT('anaf_verif_cautare')
|
||||
ADDPROPERTY(goFormD, 'oVerifAlegere', poVerifD)
|
||||
poVerifD.Activeaza(goFormD)
|
||||
goFormD.WindowType = 0
|
||||
goFormD.Show()
|
||||
SELECT ctestdialog
|
||||
LOCATE FOR id_part = gnIdDiscord
|
||||
goFormD._GRID1.AfterRowColChange(1)
|
||||
poVerifD.VerificaRand(.T.)
|
||||
DO VpaLogD WITH 'stare pregatita, label=[' + ALLTRIM(goFormD.lb_anaf.Caption) + ']'
|
||||
|
||||
DO HarnessReady WITH 0, 'gata sa afisez dialogul REAL'
|
||||
*-- BLOCHEAZA aici (MESSAGEBOX() nativ) pana harnessul extern inchide fereastra (WM_CLOSE)
|
||||
LOCAL llRez
|
||||
llRez = poVerifD.VerificaAlegere(goFormD)
|
||||
DO VpaLogD WITH 'dialog inchis, VerificaAlegere a intors ' + TRANSFORM(llRez)
|
||||
|
||||
DO HarnessDone WITH 'done'
|
||||
CATCH TO loExcD
|
||||
DO VpaLogD WITH 'CATCH ErrorNo=' + TRANSFORM(loExcD.ErrorNo) + ' Message=' + loExcD.Message + ' Line=' + TRANSFORM(loExcD.LineNo)
|
||||
DO HarnessDone WITH 'done-error'
|
||||
FINALLY
|
||||
DO CurataDateTestD
|
||||
ENDTRY
|
||||
|
||||
QUIT
|
||||
|
||||
PROCEDURE CurataDateTestD
|
||||
LOCAL lnOk
|
||||
lnOk = goExecutor.oExecuta([DELETE FROM NOM_PARTENERI WHERE COD_FISCAL IN ('7654321','RO7654321')])
|
||||
=goExecutor.oExecuta('COMMIT')
|
||||
DO VpaLogD WITH 'CurataDateTestD: sters=' + TRANSFORM(m.lnOk)
|
||||
ENDPROC
|
||||
|
||||
PROCEDURE CreeazaDateTestD
|
||||
LOCAL lcIns
|
||||
lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ;
|
||||
[('TEST ANAF DISCORD SRL','TEST ANAF DISCORD SRL','7654321',0,0,0,1,0,0)]
|
||||
=goExecutor.oExecuta(m.lcIns)
|
||||
lcIns = [INSERT INTO NOM_PARTENERI (NUME,DENUMIRE,COD_FISCAL,STERS,ID_MOD,INACTIV,TIP_PERSOANA,INSTITUTIE_PUBLICA,ENTITATE_AFILIATA) VALUES ] + ;
|
||||
[('TEST ANAF DISCORD SRL','TEST ANAF DISCORD SRL','RO7654321',0,0,1,1,0,0)]
|
||||
=goExecutor.oExecuta(m.lcIns)
|
||||
=goExecutor.oExecuta('COMMIT')
|
||||
gnIdDiscord = 0
|
||||
gnIdPereche = 0
|
||||
=goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = '7654321'], @gnIdDiscord)
|
||||
=goExecutor.oSelect2Value([SELECT ID_PART AS NR FROM NOM_PARTENERI WHERE COD_FISCAL = 'RO7654321'], @gnIdPereche)
|
||||
DO VpaLogD WITH 'CreeazaDateTestD: discord=' + TRANSFORM(gnIdDiscord) + ' pereche=' + TRANSFORM(gnIdPereche)
|
||||
ENDPROC
|
||||
|
||||
PROCEDURE VpaErrD
|
||||
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
|
||||
DO VpaLogD WITH 'ON ERROR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg
|
||||
TRY
|
||||
DO CurataDateTestD
|
||||
CATCH
|
||||
ENDTRY
|
||||
QUIT
|
||||
ENDPROC
|
||||
|
||||
PROCEDURE VpaLogD
|
||||
LPARAMETERS tcMsg
|
||||
SET SAFETY OFF
|
||||
LOCAL lcL
|
||||
lcL = IIF(FILE(gcUILog), FILETOSTR(gcUILog), '')
|
||||
STRTOFILE(lcL + tcMsg + CHR(13)+CHR(10), gcUILog)
|
||||
ENDPROC
|
||||
177
utile/Teste/partener_anaf/shot_dialog_anaf.ps1
Normal file
177
utile/Teste/partener_anaf/shot_dialog_anaf.ps1
Normal file
@@ -0,0 +1,177 @@
|
||||
# shot_dialog_anaf.ps1 - lanseaza shot_dialog_anaf.prg (dialog ANAF REAL, neinlocuit) si
|
||||
# captureaza fereastra nativa MESSAGEBOX() (clasa #32770) aparuta in acelasi proces vfp9,
|
||||
# apoi o inchide cu WM_CLOSE (fara SendKeys, fara sa fure focus - fereastra e mutata off-screen
|
||||
# inainte de captura, ca in vfp_ui_harness.ps1).
|
||||
param(
|
||||
[string]$Prg = (Join-Path $PSScriptRoot 'shot_dialog_anaf.prg'),
|
||||
[string]$OutPng = (Join-Path $PSScriptRoot 'screenshots\dialog_anaf_real.png'),
|
||||
[int]$ReadyTimeoutSec = 150,
|
||||
[int]$DialogTimeoutSec = 20,
|
||||
[string]$Vfp = 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe'
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$TestDir = [System.IO.Path]::GetDirectoryName($Prg)
|
||||
$TestFxp = [System.IO.Path]::ChangeExtension($Prg, 'fxp')
|
||||
$TestLog = Join-Path $TestDir 'shot_dialog_anaf_log.txt'
|
||||
$SyncDir = Join-Path $TestDir 'uisync_dialog'
|
||||
$Precompile = Join-Path (Split-Path $TestDir -Parent) '_precompile.ps1'
|
||||
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
|
||||
Add-Type @"
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
public class Win32Dlg {
|
||||
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT { public int Left, Top, Right, Bottom; }
|
||||
[DllImport("user32.dll")] public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
|
||||
[DllImport("user32.dll")] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
|
||||
[DllImport("user32.dll")] public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
|
||||
[DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
|
||||
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr hWnd);
|
||||
[DllImport("user32.dll")] public static extern bool IsWindow(IntPtr hWnd);
|
||||
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
|
||||
[DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
|
||||
[DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdc, uint nFlags);
|
||||
[DllImport("user32.dll")] public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
public static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
|
||||
public const uint SWP_NOSIZE = 0x0001;
|
||||
public const uint SWP_NOACTIVATE = 0x0010;
|
||||
public const uint WM_CLOSE = 0x0010;
|
||||
|
||||
public static List<IntPtr> FindByPidAndClass(int pid, string className) {
|
||||
var result = new List<IntPtr>();
|
||||
EnumWindows((hWnd, lParam) => {
|
||||
int wpid;
|
||||
GetWindowThreadProcessId(hWnd, out wpid);
|
||||
if (wpid == pid && IsWindowVisible(hWnd)) {
|
||||
var sb = new StringBuilder(256);
|
||||
GetClassName(hWnd, sb, sb.Capacity);
|
||||
if (sb.ToString() == className) { result.Add(hWnd); }
|
||||
}
|
||||
return true;
|
||||
}, IntPtr.Zero);
|
||||
return result;
|
||||
}
|
||||
public static string GetTitle(IntPtr hWnd) {
|
||||
var sb = new StringBuilder(512);
|
||||
GetWindowText(hWnd, sb, sb.Capacity);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
"@
|
||||
|
||||
function Push-Offscreen([IntPtr]$Hwnd) {
|
||||
if ($Hwnd -eq [IntPtr]::Zero -or -not [Win32Dlg]::IsWindow($Hwnd)) { return }
|
||||
[Win32Dlg]::SetWindowPos($Hwnd, [Win32Dlg]::HWND_BOTTOM, -4000, 0, 0, 0, ([Win32Dlg]::SWP_NOSIZE -bor [Win32Dlg]::SWP_NOACTIVATE)) | Out-Null
|
||||
}
|
||||
|
||||
function Wait-MainWindowHandle([System.Diagnostics.Process]$Proc, [int]$TimeoutSec) {
|
||||
$deadline = (Get-Date).AddSeconds($TimeoutSec)
|
||||
while ((Get-Date) -lt $deadline) {
|
||||
try {
|
||||
$Proc.Refresh()
|
||||
if ($Proc.HasExited) { return [IntPtr]::Zero }
|
||||
if ($Proc.MainWindowHandle -ne [IntPtr]::Zero) { return $Proc.MainWindowHandle }
|
||||
} catch {}
|
||||
Start-Sleep -Milliseconds 200
|
||||
}
|
||||
return [IntPtr]::Zero
|
||||
}
|
||||
|
||||
function Wait-File([string]$Path, [int]$TimeoutSec, [IntPtr]$Hwnd = [IntPtr]::Zero) {
|
||||
$deadline = (Get-Date).AddSeconds($TimeoutSec)
|
||||
while (-not (Test-Path $Path)) {
|
||||
if ((Get-Date) -gt $deadline) { return $false }
|
||||
if ($Hwnd -ne [IntPtr]::Zero) { Push-Offscreen $Hwnd }
|
||||
Start-Sleep -Milliseconds 300
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
function Take-Screenshot([IntPtr]$Hwnd, [string]$Path) {
|
||||
$rect = New-Object Win32Dlg+RECT
|
||||
[Win32Dlg]::GetWindowRect($Hwnd, [ref]$rect) | Out-Null
|
||||
$w = $rect.Right - $rect.Left
|
||||
$h = $rect.Bottom - $rect.Top
|
||||
if ($w -le 0 -or $h -le 0) { $w = 600; $h = 300 }
|
||||
$bmp = New-Object System.Drawing.Bitmap $w, $h
|
||||
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
||||
$hdc = $g.GetHdc()
|
||||
$ok = [Win32Dlg]::PrintWindow($Hwnd, $hdc, 2)
|
||||
$g.ReleaseHdc($hdc)
|
||||
$g.Dispose()
|
||||
if (-not $ok) {
|
||||
$g2 = [System.Drawing.Graphics]::FromImage($bmp)
|
||||
$hdc2 = $g2.GetHdc()
|
||||
[Win32Dlg]::PrintWindow($Hwnd, $hdc2, 0) | Out-Null
|
||||
$g2.ReleaseHdc($hdc2)
|
||||
$g2.Dispose()
|
||||
}
|
||||
$bmp.Save($Path, [System.Drawing.Imaging.ImageFormat]::Png)
|
||||
$bmp.Dispose()
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path $OutPng -Parent) | Out-Null
|
||||
if (Test-Path $SyncDir) { Get-ChildItem $SyncDir -File | Remove-Item -Force -ErrorAction SilentlyContinue } else { New-Item -ItemType Directory -Path $SyncDir | Out-Null }
|
||||
|
||||
Write-Host "Precompilez .fxp (izolat): $Precompile -Prg $Prg"
|
||||
Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
Start-Sleep -Milliseconds 500
|
||||
Start-Process powershell -WindowStyle Hidden -ArgumentList @('-ExecutionPolicy','Bypass','-File',"`"$Precompile`"",'-Prg',"`"$Prg`"") -Wait | Out-Null
|
||||
Start-Sleep -Seconds 2
|
||||
Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
Start-Sleep -Seconds 2
|
||||
if (-not (Test-Path $TestFxp)) { Write-Warning "Nu s-a generat $TestFxp - compilare esuata."; exit 1 }
|
||||
|
||||
$ready0 = Join-Path $SyncDir 'ready_0.txt'
|
||||
if (Test-Path $ready0) { Remove-Item $ready0 -Force }
|
||||
if (Test-Path $TestLog) { Remove-Item $TestLog -Force }
|
||||
$t0 = Get-Date
|
||||
Write-Host "Lansez VFP: $Vfp -A $TestFxp"
|
||||
$proc = Start-Process -FilePath $Vfp -ArgumentList @('-A', "`"$TestFxp`"") -PassThru
|
||||
$hwnd = Wait-MainWindowHandle $proc 15
|
||||
Push-Offscreen $hwnd
|
||||
|
||||
if (-not (Wait-File $ready0 $ReadyTimeoutSec $hwnd)) {
|
||||
Write-Warning "Nu am primit ready_0 in ${ReadyTimeoutSec}s. Ultima linie log: '$(Get-Content $TestLog -Tail 1 -ErrorAction SilentlyContinue)'"
|
||||
if (-not $proc.HasExited) { try { $proc.Kill() } catch {} }
|
||||
Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
exit 1
|
||||
}
|
||||
Write-Host "ready_0 primit - astept fereastra MESSAGEBOX() nativa (clasa #32770, acelasi PID)"
|
||||
|
||||
$dlgHwnd = [IntPtr]::Zero
|
||||
$deadline = (Get-Date).AddSeconds($DialogTimeoutSec)
|
||||
while ((Get-Date) -lt $deadline -and $dlgHwnd -eq [IntPtr]::Zero) {
|
||||
$cands = [Win32Dlg]::FindByPidAndClass($proc.Id, '#32770')
|
||||
foreach ($h in $cands) { $dlgHwnd = $h; break }
|
||||
if ($dlgHwnd -eq [IntPtr]::Zero) { Start-Sleep -Milliseconds 300 }
|
||||
}
|
||||
|
||||
if ($dlgHwnd -eq [IntPtr]::Zero) {
|
||||
Write-Warning "Fereastra dialogului nu a aparut in ${DialogTimeoutSec}s."
|
||||
if (-not $proc.HasExited) { try { $proc.Kill() } catch {} }
|
||||
Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
exit 1
|
||||
}
|
||||
Write-Host ("dialog gasit: hwnd={0} titlu=[{1}]" -f $dlgHwnd, [Win32Dlg]::GetTitle($dlgHwnd))
|
||||
Push-Offscreen $dlgHwnd
|
||||
Start-Sleep -Milliseconds 600
|
||||
Push-Offscreen $dlgHwnd
|
||||
Take-Screenshot $dlgHwnd $OutPng
|
||||
Write-Host "screenshot: $OutPng"
|
||||
|
||||
# inchide dialogul (echivalent Escape/Cancel) - nu SendKeys, ca sa nu ceara focus
|
||||
[Win32Dlg]::PostMessage($dlgHwnd, [Win32Dlg]::WM_CLOSE, [IntPtr]::Zero, [IntPtr]::Zero) | Out-Null
|
||||
|
||||
$done = Join-Path $SyncDir 'done.txt'
|
||||
if (Wait-File $done 30 $hwnd) { Write-Host "done: $((Get-Content $done -Raw).Trim())" } else { Write-Warning "Nu am primit done.txt dupa inchiderea dialogului." }
|
||||
Start-Sleep -Milliseconds 500
|
||||
if (-not $proc.HasExited) { try { $proc.Kill() } catch {} }
|
||||
Get-Process vfp9 -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "GATA. Screenshot in $OutPng"
|
||||
1660
utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.prg
Normal file
1660
utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.prg
Normal file
File diff suppressed because it is too large
Load Diff
12
utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.ps1
Normal file
12
utile/Teste/partener_anaf/test_verif_partener_anaf_v2_ui.ps1
Normal file
@@ -0,0 +1,12 @@
|
||||
# test_verif_partener_anaf_v2_ui.ps1 - wrapper peste harness-ul generic pentru testul UI V2'
|
||||
# (verdict ANAF in formularul de cautare, cauta_alfa_form + anaf_verif_cautare, decizie prin AMESSAGEBOX).
|
||||
# Rulare: powershell -ExecutionPolicy Bypass -File test_verif_partener_anaf_v2_ui.ps1
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$Teste = $PSScriptRoot
|
||||
& (Join-Path (Split-Path $Teste -Parent) 'vfp_ui_harness.ps1') `
|
||||
-TestPrg (Join-Path $Teste 'test_verif_partener_anaf_v2_ui.prg') `
|
||||
-Steps @('concordant','discordant','mesaj_decizie','decizii_6_7_2','gata') `
|
||||
-ShotsDir (Join-Path $Teste 'screenshots') `
|
||||
-SyncDir (Join-Path $Teste 'uisync') `
|
||||
-StepTimeoutSec 90 `
|
||||
-ReadyTimeoutSec 150
|
||||
Reference in New Issue
Block a user