Runner planuje każdą obowiązkową asercję przed otwarciem przeglądarki. report.json przechowuje check_plan,
checks, cell_plan, cells, pokrycie i wynik gate. Brak kroku, duplikat, nieplanowany wynik, błąd wykonania
lub brak wymaganego dowodu oznacza niekompletność. Pojedyncze failed oznacza niepowodzenie niezależnie od
liczby powtórzeń i statusu kandydata w analizie GUI. Niekompletność ma pierwszeństwo przed kodem niepowodzenia.
testwins gate artifacts/run-id
testwins verify artifacts/run-id
Gate na katalogu najpierw sprawdza integralność artefaktów. Gate na samym report.json może sprawdzić wyłącznie
strukturę i wynik, nie obecność zewnętrznych plików. verify jest kontrolą hashy, nie kontrolą zachowania aplikacji.
Stare raporty bez planu kroków nie są automatycznie traktowane jako zaliczone w 0.4.
Sesja jest jawnym wejściem. Nie pobieramy automatycznie profilu ani cookies z hostowej przeglądarki. Plik musi być regularny, niesymlinkowany, do 5 MB, na POSIX z uprawnieniami 0600. Originy i domeny cookies muszą należeć do allowlisty konfiguracji. Oddzielne konta = oddzielne pliki i nazwane sesje.
base_url: http://127.0.0.1:8080
allowed_origins: []
sessions:
customer:
storage_state: .auth/customer.storage-state.json
default_session: customer
journeys:
- id: account
path: /billing
setup_path: /account
session: customer
steps:
- id: invoice-list
action: assert
expect:
kind: visible
selector: '#invoice-list'
Fragment należy połączyć z konfiguracją utworzoną przez testwins init; setup_path i path są względne
wobec tego samego originu. Przygotowanie i właściwy widok działają w tym samym nowym kontekście. Kontekst nie
przecieka między scenami. Każdy wymagany warunek dotyczący przygotowania należy zapisać jako jawny krok —
setup_path jest nawigacją rozgrzewającą, a nie deklaracją sukcesu biznesowego.
testwins auth-save --config audit.yaml \
--output .auth/customer.storage-state.json \
--ready-selector '#signed-in-user'
Polecenie otwiera osobną przeglądarkę w trybie graficznym. Operator loguje się lokalnie; zapis następuje po
widoczności jawnego selektora. Nie ma tu uniwersalnego generatora danych logowania. Plik nie jest nadpisywany.
Ścieżki są liczone względem YAML. Nie publikuj plików sesji i nie przekazuj ich modelowi LLM.
Zapisywana kopia konfiguracji redaguje ścieżki, ale screenshot/DOM nadal może zawierać dane konta — stosuj maski,
izolowane dane i odpowiednią retencję. W Dockerze AUTH_DIR=/lokalny/prywatny/folder montuje pliki tylko do
labu read-only jako /auth; konfiguracja wskazuje wtedy /auth/customer.storage-state.json. Pliki nie trafiają do SUT.
Akcje: istniejące click/fill/press/hover/check/uncheck/select/assert/wait oraz goto, scroll, download.
Mutujące akcje wymagają allow_mutation: true. goto musi być same-origin i mieć oczekiwanie.
Oczekiwania: visible/hidden/text/count/url/changed oraz contains_text/count_min/enabled/disabled/checked/unchecked/
focused/value/attribute/download. attribute ma name i value; count_min jest ograniczonym czasowo oczekiwaniem,
a nie pojedynczym pomiarem przed zakończeniem renderowania.
journeys:
- id: search
path: /
steps:
- id: open
action: press
selector: body
value: Control+k
allow_mutation: true
expect: {kind: visible, selector: '#palette'}
- id: query
action: fill
selector: '#palette input'
value: taskand
allow_mutation: true
expect: {kind: contains_text, selector: '#palette', value: taskand}
Przed krokiem zapisuje się dowód (capture.before_steps: true), a po nim rezultat. Nie klikamy wszystkich
przycisków ani nie uznajemy samej obecności kontrolki za wykonanie jej funkcji.
downloads:
enabled: true
max_bytes: 10485760
retain: false
journeys:
- id: invoice
path: /invoices
steps:
- id: download-invoice
action: download
selector: '#download-pdf'
allow_mutation: true
expect:
kind: download
filename_regex: '.*\.pdf'
min_bytes: 5
max_bytes: 10485760
starts_with_hex: '255044462d'
Krok czeka na prawdziwe zdarzenie pobrania. Sprawdza rozmiar, nazwę, opcjonalny prefix i sha256.
Prefix %PDF- nie dowodzi poprawności danych faktury ani kompletności PDF. Podane oczekiwania są kontraktem,
nie ekstrakcją semantyczną dokumentu. Domyślnie zapisuje się tylko metadane z zredagowaną nazwą i hash.
retain: true zachowuje plik pod kontrolowaną nazwą payload.bin, nigdy pod ścieżką narzuconą przez serwer.
Limit bytes sprawdzany jest po zakończeniu pobrania, nie ogranicza transferu w przeglądarce ani jego zapisu
przejściowego. Twardą ochronę dysku/pamięci realizuj limitem kontenera/tmpfs; używaj zaufanego środowiska testowego.
schema: testwins.api/v1
id: menu
base_url: http://127.0.0.1:8080
requests:
- id: menu-readable
method: GET
path: /v1/menu
expect:
status: 200
json_min_length: {'/searchIndex': 15}
json_any:
- {path: '/searchIndex', field: endpointId, contains: taskand}
testwins api --config api.yaml --output artifacts/api
# Nie wykonuj poniższego bez przeglądu środowiska i skutków:
testwins api --config api/mutations.review.yaml --output artifacts/api --approve-mutations
POST/PUT/PATCH/DELETE wymagają jednocześnie allow_mutation: true w żądaniu i --approve-mutations.
Domyślna suite nie udziela tej zgody. Same-origin, bez automatycznych przekierowań i bez odziedziczonego proxy.
Opcjonalne header_env mapuje nazwę nagłówka do zmiennej środowiskowej, nie sekretu w YAML. Domyślnie limit
odpowiedzi 1 MB, konfigurowalny do 10 MB. Raport nie zachowuje nagłówków ani body, ale hash/rozmiar też należy
traktować jako metadane testowe, nie dowód anonimizacji. Każde żądanie ma wymagany jawny status.
API wykonuje się raz w suite, a nie raz na urządzenie. Nie jest częścią skanera ograniczonego do DOM/obrazów.
performance:
enabled: true
required: true
budgets:
JSHeapUsedSize: 104857600
To jawne maksima wybranych liczników Chromium. Brak wymaganej metryki daje niekompletność, przekroczenie — niepowodzenie. Liczniki czasowe/counters są kumulatywne, nie automatycznymi deltami działania i nie Core Web Vitals. Konfigurację stosuj w oddzielnym zakresie Chromium. Firefox/WebKit nie dostają fikcyjnych pomiarów CDP.
# tests/test_gui.py
from pathlib import Path
def test_portal(testwins_run):
report = testwins_run(Path('testwins/audit.yaml'))
assert report['gate']['exit_code'] == 0
pytest -p testwins.pytest_plugin tests/test_gui.py
Plugin jest ładowany jawnie. testwins_assert_report(path) pozwala bramkować istniejący raport; dla katalogu
sprawdza też hashe. Nie rejestruje niejawnych hooków skanujących i nie zastępuje specjalistycznych testów API.
make test
make test-browser
make install-testql-source TESTQL_REF=PRZEJRZANY_COMMIT
make test-final
make landing-check MATRIX=engines
Dwa testy integracyjne w aktualnym środowisku utknęły na ograniczeniach zarządzanej przeglądarki: pełne storage_state
z localStorage oraz download. Pozostają aktywne, nie są oznaczone jako poprawne. Testy renderer-only można uruchomić
pytest -m 'browser and not integration'; nie należy mylić tego podzbioru z pełnym testem instalacji.
Przygotowanie: 2026-09-22. Dokumentacja Playwright: auth,
download, Docker.
Weryfikacja API zależności nie zastępuje lokalnego testu po przypięciu konkretnej wersji. Pełne ograniczenia: verification/STATUS.md.