Testy automatyczne nie są specjalnym narzędziem dla programistów w dużych projektach, szczególnie w przypadku rozszerzeń, testy automatyczne pomagają szybko zidentyfikować problemy, pomagają zapewnić płynne działanie rozszerzeń w nowszych wersjach Joomla.
Deweloperzy Joomla Core chcą, aby zewnętrzni programiści testowali ich rozszerzenia, aby znajdowali błędy, zanim znajdzie je użytkownik. To wymaga dużo czasu i jest nudną pracą. Dlatego często się tego nie robi. Szczególnie nie, jeśli trzeba to zrobić ręcznie przez ludzi dla każdej nowej wersji. Zautomatyzowane testowanie umożliwia powtórzenie ręcznych kroków dla każdej wersji bez konieczności wykonywania tych czynności przez człowieka. W ten sposób błędy są wykrywane, zanim użytkownik napotka je podczas uzyskiwania dostępu do działającego systemu.
Nawiasem mówiąc, każdy, kto chce sprawdzić Cypress, uzna ten tekst za dobry początek.Możesz testować problemy bez konieczności instalowania i konfigurowania wszystkiego samodzielnie.W repozytorium Github projektu Joomla wszystko jest gotowe.
Wprowadzenie
„Chociaż prawdą jest, że jakości nie można przetestować, równie oczywiste jest, że bez testowania niemożliwe jest opracowanie czegokolwiek, co ma jakość” – [James A. Whittaker]
Zanim po raz pierwszy zetknąłem się z Cypressem, nie mogłem sobie wyobrazić, że bariery, które często stawały na drodze moich testów, zostaną nieco przesunięte.Spędziłem dużo czasu na testowaniu oprogramowania - a wcześniej jeszcze więcej czasu zajmowałem się problemami które powstały z powodu braku testów!Teraz jestem przekonany, że testy, które są:
- jak najbliżej czasu programowania,
- automatycznie,
- często – najlepiej po każdej zmianie programu,
przynieś więcej niż kosztują, a co więcej: testowanie może być nawet zabawne.
Metod testowych warto się uczyć!Metody testowe są trwałe, ponieważ można je stosować nie tylko w każdym języku programowania, można je zastosować do niemal każdej ludzkiej pracy.Prawie wszystko, co ważne w życiu, należy przetestować raz na jakiś czas. Metody testowe są niezależne od konkretnych narzędzi programowych.W przeciwieństwie do technik programowania lub języków programowania, które często są modne i wychodzą z mody, wiedza o tym, jak skonfigurować dobre testy, jest ponadczasowa.
Kto powinien przeczytać ten tekst?
Każdy, kto uważa, że testowanie oprogramowania to strata czasu, powinien zapoznać się z tym artykułem.W szczególności chciałbym zaprosić do przeczytania ten programistów, którzy zawsze chcieli pisać testy dla swojego oprogramowania - ale nigdy nie robili tego dla odmiany z powodów Cyprys może być sposobem na usunięcie takich barier.
Jakaś teoria
Magiczny trójkąt
Magiczny trójkąt opisuje zależność między kosztami, wymaganym czasem i możliwą do osiągnięcia jakością.Pierwotnie ta zależność była rozpoznawana i opisywana w zarządzaniu projektami.Jednakże pewnie słyszeliście o tym napięciu również w innych obszarach.problem w prawie wszystkich operacjach procesów w firmie.
Na przykład ogólnie przyjmuje się, że wyższy koszt ma pozytywny wpływ na jakość i/lub termin realizacji, czyli czas.
Odwrotnie, oszczędność kosztów wymusi obniżenie jakości i/lub opóźnienie ukończenia.
Teraz w grę wchodzi magia: pokonujemy korelację między czasem, kosztami i jakością, ponieważ na dłuższą metę można to przezwyciężyć.
Związek między czasem, kosztami i jakością można przezwyciężyć na dłuższą metę.
Być może również Państwo przekonali się w praktyce, że obniżenie jakości nie prowadzi w dłuższej perspektywie do oszczędności kosztów.Dług techniczny, który to powoduje, często prowadzi nawet do wzrostu kosztów i dodatkowego czasu.
Dług techniczny odnosi się do dodatkowego wysiłku związanego z wprowadzaniem zmian i ulepszeń w źle zaprogramowanym oprogramowaniu w porównaniu z dobrze napisanym oprogramowaniem. Martin Fowler wyróżnia następujące rodzaje długu technicznego: ten, w który się zaciągnęło celowo i ten, w który się zaciągnęło nieumyślnie Rozróżnia także ostrożne i lekkomyślne zaciąganie długów technicznych.
Koszty i korzyści
W literaturze można znaleźć druzgocące statystyki dotyczące szans powodzenia projektów programistycznych. Niewiele zmieniło się w negatywnym obrazie, który został już zarejestrowany w badaniu AW Feyhla w latach 90. Tutaj, w analizie 162 projektów w 50 organizacjach , ustalono odchylenie kosztów w porównaniu z pierwotnym planem: 70% projektów wykazało odchylenie kosztów co najmniej 50%! Coś jest nie tak! Nie możesz tego tak po prostu zaakceptować, prawda?
Jednym z rozwiązań byłoby całkowite zrezygnowanie z kosztorysów i podążanie za argumentacją ruchu #NoEstimates , który uważa, że kosztorysy w projekcie oprogramowania są bezsensowne. Projekt oprogramowania zawiera według opinii #NoEstimates zawsze produkcję czegoś nowego.Nowego nie da się porównać z już istniejącymi doświadczeniami, a tym samym nie da się przewidzieć.
Im więcej doświadczenia tym bardziej dochodzę do wniosku, że skrajne poglądy nie są dobre. Rozwiązanie jest prawie zawsze pośrodku. Unikaj skrajności również w projektach programistycznych i szukaj środka. Nie trzeba mieć 100% pewien plan. Ale nie należy też zaczynać nowego projektu naiwnie. Chociaż zarządzanie projektami programistycznymi, a zwłaszcza szacowanie kosztów, to ważny temat, nie będę Cię już tym zanudzał w tym tekście. Celem tego artykułu jest pokazanie, jak E2E testowanie można zintegrować z praktycznym procesem tworzenia oprogramowania.
Zintegruj testowanie oprogramowania ze swoim przepływem pracy
Zdecydowałeś się przetestować swoje oprogramowanie. Świetnie! Kiedy najlepiej to zrobić? Przyjrzyjmy się kosztowi naprawy błędu w różnych fazach projektu. Im wcześniej znajdziesz błąd, tym niższy koszt naprawy .
Testowanie i debugowanie: istnieją słowa, które są często wymieniane jednym tchem i których znaczenie jest zatem zrównane. Jednak po bliższym przyjrzeniu się, terminy te oznaczają różne interpretacje. Testowanie i debugowanie należą do tych słów. Te dwa terminy mają wspólną cechę że wykrywają awarie, ale są też różnice w znaczeniu.
- Testy wykrywają nieznane usterki podczas opracowywania. Znalezienie usterki jest kosztowne, a lokalizacja i eliminacja błędu jest tania.
- Debugery naprawiają awarie wykryte po ukończeniu produktu.Znalezienie usterki jest bezpłatne, ale zlokalizowanie i naprawienie błędu jest kosztowne.
Wniosek: jak najwcześniejsze rozpoczęcie integracji testów ma sens, niestety jest to trudne do zaimplementowania w projekcie typu open source, takim jak Joomla, z większością dobrowolnych współpracowników.
Ciągła integracja (CI)
Ciągła integracja testów
Wyobraź sobie następujący scenariusz. Wkrótce ma zostać wydana nowa wersja popularnego systemu zarządzania treścią. Wszystko, co programiści z zespołu wnieśli od czasu ostatniej wersji, jest teraz po raz pierwszy używane razem. Napięcie rośnie! praca? Czy wszystkie testy zakończą się sukcesem - jeśli projekt w ogóle integruje testy, czy też wydanie nowej wersji trzeba będzie ponownie przełożyć i czekają nas nerwowe godziny naprawiania błędów? dobre dla wizerunku oprogramowania! Żaden programista nie lubi doświadczać takiego scenariusza. O wiele lepiej jest wiedzieć w dowolnym momencie, w jakim stanie jest aktualnie projekt oprogramowania. Kod, który nie pasuje do istniejącego, należy zintegrować dopiero po zostały „szyte na miarę”.Zwłaszcza w czasach, gdy coraz częściej trzeba naprawiać luki w zabezpieczeniach, projekt zawsze powinien być w stanie stworzyć wydanie!I tu w grę wchodzi ciągła integracja.
W ciągłej integracji poszczególne elementy oprogramowania są trwale zintegrowane. Oprogramowanie jest tworzone i testowane w małych cyklach. W ten sposób problemy podczas integracji lub wadliwe testy pojawiają się na wczesnym etapie, a nie kilka dni lub tygodni później. Przy udanej integracji, Rozwiązywanie problemów jest znacznie łatwiejsze, ponieważ błędy są wykrywane blisko czasu programowania i zwykle dotyczy to tylko niewielkiej części programu. Joomla integruje nowy kod przy użyciu ciągłej integracji. Nowy kod jest integrowany tylko wtedy, gdy wszystkie testy zakończą się pomyślnie.
Dzięki ciągłej integracji nowego oprogramowania rozwiązywanie problemów jest znacznie łatwiejsze, ponieważ błędy są wykrywane blisko czasu programowania i zwykle dotyczy to tylko niewielkiej części programu.
Aby mieć pewność, że testy dla wszystkich części programu są dostępne przez cały czas podczas ciągłej integracji, należy opracować oprogramowanie oparte na testach.
Rozwój oparty na testach (TDD)
Programowanie sterowane testami to technika programowania, która wykorzystuje programowanie małymi krokami. Najpierw piszesz kod testowy. Dopiero potem tworzysz kod programu, który ma być testowany. Wszelkie zmiany w programie są wprowadzane dopiero po wprowadzeniu kodu testowego dla tej zmiany. został utworzony. Więc twoje testy kończą się niepowodzeniem natychmiast po utworzeniu. Wymagana funkcja nie jest jeszcze zaimplementowana w programie. Dopiero wtedy tworzysz rzeczywisty kod programu - to znaczy kod programu, który spełnia wymagania testu.
Testy TDD pomagają poprawnie napisać program .
Kiedy po raz pierwszy słyszysz o tej technice, możesz nie czuć się komfortowo z tą koncepcją. „Człowiek” zawsze chce najpierw zrobić coś produktywnego. A pisanie testów na pierwszy rzut oka nie wydaje się produktywne. Wypróbuj. Czasami z nową techniką zaprzyjaźniasz się dopiero po zapoznaniu się z nią!W projektach z dużym pokryciem testów czuję się bardziej komfortowo, gdy dodaję nowe funkcje.
Jeśli przejdziesz przez część ćwiczeniową na końcu tekstu, możesz to wypróbować. Najpierw utwórz test, a następnie napisz kod dla Joomla Core. Następnie prześlij wszystko razem jako PR na Github. Jeśli wszyscy by to zrobili , Joomla miałby idealne pokrycie testowe.
Rozwój oparty na zachowaniu (BDD)
BDD nie jest kolejną techniką programowania ani techniką testowania, ale swego rodzaju najlepszą praktyką w tworzeniu oprogramowania. BDD idealnie sprawdza się w połączeniu z TDD. Zasadniczo Behaviour-Driven-Development oznacza testowanie nie implementacji kodu programu, ale jego wykonania - czyli zachowanie programu Test sprawdza, czy spełniona jest specyfikacja, czyli wymaganie klienta.
Kiedy tworzysz oprogramowanie w sposób oparty na zachowaniu, testy nie tylko pomagają poprawnie napisać program, ale także pomagają napisać właściwy program .
Co mam na myśli mówiąc: „Napisz odpowiedni program"? Zdarza się, że użytkownicy widzą rzeczy inaczej niż programiści. Przykładem jest proces usuwania artykułu w Joomla. Raz po raz spotykam się z użytkownikami, którzy klikają ikonę statusu w do kosza i są zaskoczeni. Użytkownik zazwyczaj intuicyjnie zakłada, że element jest teraz trwale usunięty, ale jest przełączany z kosza na aktywację. Dla programisty kliknięcie ikony stanu to zmiana statusu, przełączenie we wszystkich innych widokach. Dlaczego w koszu miałoby być inaczej?Dla programisty funkcja jest zaimplementowana bez błędów.Jomla działa poprawnie.Ale moim zdaniem funkcja nie jest właściwa w tym miejscu, ponieważ większość użytkowników opisałaby/zażądała jej zupełnie inaczej .
W Behaviour Driven Development wymagania dotyczące oprogramowania są opisane za pomocą przykładów zwanych scenariuszami lub historiami użytkownika.
- silne zaangażowanie użytkownika końcowego w proces tworzenia oprogramowania,
- dokumentacja wszystkich faz projektu wraz z historiami użytkowników/przykładami przypadków w formie tekstowej - zwykle w języku opisu w języku opisu Gherkin,
- automatyczne testowanie tych historii użytkowników/studium przypadku,
- sukcesywnej implementacji. Dzięki temu w każdej chwili można uzyskać dostęp do opisu oprogramowania, które ma zostać wdrożone. Za pomocą tego opisu można na bieżąco zapewniać poprawność już zaimplementowanego kodu programu.
Projekt Joomla wprowadził BDD w projekcie Google Summer of Code . Spodziewano się, że użytkownicy bez wiedzy programistycznej będą mogli łatwiej uczestniczyć za pomocą Gherkin ). Podejście to nie było konsekwentnie stosowane. W tamtym czasie Joomla używała Codeception jako narzędzie do testowania.Dzięki Cypress rozwój BDD jest również możliwy do opracowania w sposób BDD.
Planowanie
Typy testów
- Testy jednostkowe: Test jednostkowy to test, który niezależnie testuje najmniejsze jednostki programu.
- Testy integracyjne: Test integracyjny to test, który sprawdza interakcję poszczególnych jednostek.
- Testy E2E lub Testy Akceptacyjne: Test akceptacyjny sprawdza, czy program spełnia określone na początku zadanie.
Strategie
Jeśli chcesz dodać nową funkcję w Joomla i zabezpieczyć ją testami, możesz postąpić na dwa sposoby.
Top-down i bottom-up to dwa zasadniczo różne podejścia do rozumienia i przedstawiania złożonych zagadnień. Top-down przechodzi krok po kroku od abstrakcji i ogółu do konkretu i konkretu. Aby zilustrować to na przykładzie: system zarządzania treścią, taki jak Joomla generalnie prezentuje strony internetowe w przeglądarce.Konkretnie jednak w tym procesie jest kilka małych podzadań.Jednym z nich jest zadanie wyświetlenia określonego tekstu w nagłówku.
Oddolny opisuje kierunek odwrotny: w tym miejscu warto jeszcze raz przypomnieć, że jednym z elementów behawioralnego programowania jest tworzenie tekstowego opisu zachowania oprogramowania.Ten opis kryteriów akceptacji pomaga w tworzeniu testów – zwłaszcza górnych -poziomowe testy end-to-end lub testy akceptacyjne.
Zwykłe podejście do tworzenia testów jest dzisiaj od dołu. Jeśli wolisz rozwój oprogramowania oparty na zachowaniu, powinieneś zastosować odwrotną strategię. Powinieneś użyć strategii top-down. W przypadku strategii top-down nieporozumienie jest identyfikowane wcześnie w fazie projektowej.
-
Testowanie odgórne: Stosując strategię odgórną, zaczyna się od testów akceptacyjnych, czyli od części systemu, która jest najściślej powiązana z wymaganiami użytkownika.W przypadku oprogramowania pisanego dla użytkowników jest to zwykle interfejs użytkownika Nacisk kładziony jest na testowanie interakcji użytkownika z systemem. Wadą testowania odgórnego jest to, że trzeba poświęcić dużo czasu na tworzenie duplikatów testów. Komponenty, które nie są jeszcze zintegrowane, muszą zostać zastąpione symbolami zastępczymi. Nie nie jest na początku prawdziwym kodem programu.Dlatego brakujące części muszą być tworzone sztucznie.Stopniowo te sztuczne dane są zastępowane przez naprawdę obliczone dane.
-
Testy oddolne: jeśli stosujesz strategię oddolną, zaczynasz od testów jednostkowych.Na początku programista ma na myśli stan docelowy.Jednakże najpierw rozbija ten cel na poszczególne komponenty.Problem z Podejście oddolne polega na tym, że trudno jest przetestować, jak komponent będzie później używany w rzeczywistych sytuacjach. Zaletą testowania oddolnego jest to, że bardzo szybko kończymy części oprogramowania. Części te należy jednak używać ostrożnie. Działają poprawnie, co zapewniają testy jednostkowe, ale nie ma pewności, czy efekt końcowy jest rzeczywiście taki, jaki klient sobie wyobraża.
Piramida testów autorstwa Mike'a Cohna
Ile testów jakiego typu należy zaimplementować? Piramida testów Mike'a Cohna opisuje koncepcję wykorzystania automatycznych testów oprogramowania. Piramida składa się z trzech poziomów, ułożonych według częstotliwości użycia i trafności.
Idealnie, podstawa piramidy testów jest utworzona przez wiele szybkich i łatwych w utrzymaniu testów jednostkowych.W ten sposób większość błędów można szybko wykryć.
Na średnim poziomie znajdują się testy integracyjne, świadczące usługi ukierunkowanego testowania krytycznych interfejsów.Czasy wykonania testów integracyjnych są dłuższe, a ich utrzymanie bardziej złożone niż w przypadku testów jednostkowych.
Wierzchołek piramidy to powolne testy E2E, które czasami wymagają dużo konserwacji.Testy E2E są bardzo przydatne do testowania aplikacji jako kompletnego systemu.
Wymagania
Jakiego sprzętu potrzebujesz do pracy nad następującą częścią praktyczną?
Jakie wymagania musisz spełnić, aby aktywnie pracować nad poniższą częścią praktyczną?Nie musisz spełniać bardzo wielu wymagań, aby móc pracować nad treścią tego podręcznika.Oczywiście musisz mieć komputer.Środowisko programistyczne z Git, NodeJS i Composer oraz lokalny serwer WWW powinny być na nim zainstalowane lub możliwe do zainstalowania.
Jaką wiedzę powinieneś posiadać osobiście?
Powinieneś znać podstawowe techniki programowania.Najlepiej, jeśli masz już zaprogramowaną małą aplikację internetową.W każdym razie powinieneś wiedzieć, gdzie przechowywać pliki na komputerze programistycznym i jak je ładować w przeglądarce internetowej.out new things.
Wypróbuj to. Włącz testy do swojego następnego projektu. Być może twoje pierwsze doświadczenie z testami zaoszczędzi ci żmudnej sesji debugowania lub kłopotliwego błędu w prawdziwym systemie. W końcu dzięki sieci bezpieczeństwa testów możesz tworzyć oprogramowanie przy mniejszych nakładach stres.
Ustawianie
Konfigurowanie Cypress z Joomla!
W wersji deweloperskiej dostępnej na Github, Joomla jest skonfigurowana jako Cypress. Istnieją już testy, które można wykorzystać jako przewodnik. Nie jest więc konieczne konfigurowanie wszystkiego samodzielnie, aby uzyskać pierwszy przegląd. W ten sposób możesz eksperymentować z Cypress , poznaj jego zalety i wady oraz sam zdecyduj, czy chcesz korzystać z narzędzia testowego.
Kroki konfiguracji środowiska lokalnego:
Sklonuj repozytorium do katalogu głównego lokalnego serwera WWW:
$ git clone https://github.com/joomla/joomla-cms.git
Przejdź do folderu joomla-cms:
$ cd joomla-cms
Zgodnie z Joomla Roadmap następna główna wersja 5.0 zostanie wydana w październiku 2023. Aby być na bieżąco, używam tutaj tej wersji rozwojowej.
Zmień na gałąź 5.0-dev :
$ git checkout 5.0-dev
Zainstaluj wszystkie potrzebne pakiety kompozytora:
$ composer install
Zainstaluj wszystkie potrzebne pakiety npm:
$ npm install
Aby uzyskać więcej informacji i pomoc na temat konfigurowania stacji roboczej, zobacz artykuł dokumentacji Joomla „Konfigurowanie stacji roboczej do programowania Joomla" . Informacje dotyczące Cypress znajdują się na stronie cypress.io . Ale w tym momencie nie jest to konieczne. Joomla ustawia wszystko dla Ciebie Wystarczy, że ustawisz swoje indywidualne dane za pomocą pliku konfiguracyjnego joomla-cms/cypress.config.js
.
Skonfiguruj swoje indywidualne dane.W tym celu możesz użyć szablonu joomla-cms/cypress.config.dist.js
jako orientacji.W moim przypadku ten plik wygląda tak:
const { defineConfig } = require('cypress')
module.exports = defineConfig({
fixturesFolder: 'tests/cypress/fixtures',
videosFolder: 'tests/cypress/output/videos',
screenshotsFolder: 'tests/cypress/output/screenshots',
viewportHeight: 1000,
viewportWidth: 1200,
e2e: {
setupNodeEvents(on, config) {},
baseUrl: 'http://localhost/joomla-cms',
specPattern: [
'tests/cypress/integration/install/*.cy.{js,jsx,ts,tsx}',
'tests/cypress/integration/administrator/**/*.cy.{js,jsx,ts,tsx}',
'tests/cypress/integration/module/**/*.cy.{js,jsx,ts,tsx}',
'tests/cypress/integration/site/**/*.cy.{js,jsx,ts,tsx}'
],
supportFile: 'tests/cypress/support/index.js',
scrollBehavior: 'center',
browser: 'firefox',
screenshotOnRunFailure: true,
video: false
},
env: {
sitename: 'Joomla CMS Test',
name: 'admin',
email: Ten adres pocztowy jest chroniony przed spamowaniem. Aby go zobaczyć, konieczne jest włączenie w przeglądarce obsługi JavaScript. ',
username: 'admin',
password: 'adminadminadmin',
db_type: 'MySQLi',
db_host: 'mysql',
db_name: 'test_joomla',
db_user: 'root',
db_password: 'root',
db_prefix: 'j4_',
},
})
Konkretnie dodałem katalog tests/cypress/integration/module/**/*.cy.{js,jsx,ts,tsx}
do specPattern
Array, ponieważ chcę tam później zapisać test dla modułów.Potem zmieniłem nazwę użytkownika i hasła, ponieważ chcę też ręcznie przetestować instalację i lepiej zapamiętać te, które sam sobie przypisałem.Używam kontenera Docker jako bazę danych.W związku z tym zmieniłem serwer bazy danych i dane dostępowe.I na koniec musiałem ustawić główny adres URL http://localhost/joomla-cms
mojej instalacji Joomla.
Użyj Cyprysu
Przez przeglądarkę internetową
Zadzwoń npm run cypress:open
przez CLI w katalogu głównym Joomla.Krótki czas później otworzy się aplikacja Cypress.Utworzyliśmy wcześniej plik.To, joomla-cms/cypress.config.dist.js
że zostało to wykryte, wynika z faktu, że testowanie E2E jest określone jako skonfigurowane.
Tutaj możesz wybrać, czy chcesz uruchomić testy E2E i jakiej przeglądarki chcesz użyć.Dla przykładu wybrałem opcję „Rozpocznij testowanie w Firefoksie”.
Wszystkie dostępne zestawy testów zostaną wyświetlone i możesz kliknąć ten, który chcesz uruchomić.Po wybraniu zestawu testów, testy zostaną uruchomione i będziesz mógł zobaczyć przebieg testów w czasie rzeczywistym w przeglądarce.
Podczas gdy testy są uruchomione, możesz zobaczyć wykonywany skrypt po jednej stronie i wynik w przeglądarce po prawej stronie. To nie są zwykłe zrzuty ekranu, ale rzeczywiste migawki przeglądarki w tym momencie, dzięki czemu możesz zobaczyć rzeczywisty kod HTML Możliwe są również zrzuty ekranu, a nawet filmy z testów.
Wypróbuj, jeśli używasz, db_host: 'localhost',
możesz przetestować instalację i tym samym poprawnie skonfigurować Joomla do pracy w dalszej części tego tekstu.
Jeśli tak jak ja korzystasz z zewnętrznego źródła (nie lcoalhost; ja używam kontenera dokera) jako db_host
, test dla tego rodzaju instalacji nie jest jeszcze gotowy. W takim przypadku pojawia się kwestia bezpieczeństwa w procedurze instalacyjnej, czyli jeszcze nie uwzględnione w testach.W takim przypadku zainstaluj Joomla ręcznie z informacjami wprowadzonymi w pliku.Następne joomla-cms/cypress.config.js
testy będą wykorzystywać ustawienia z tego pliku konfiguracyjnego, na przykład do logowania się do obszaru administracyjnego Joomla.W ten sposób twórca testu nie nie musisz przejmować się wprowadzaniem danych do logowania.Zgadzający się użytkownik i hasło są zawsze pobierane automatycznie z pliku konfiguracyjnego.
Bezgłowy
Domyślnie cypress run
uruchamia wszystkie testy headless .Następująca komenda wykonuje wszystkie już zakodowane testy i zapisuje zrzuty ekranu w katalogu /joomla-cms/tests/cypress/output/screenshots
w przypadku błędu.Katalog wyjściowy został ustawiony w cypress.config.js
pliku.
$ npm run cypress:run
Inne polecenia CLI
Istnieją inne pomocne polecenia, które nie są zaimplementowane jako skrypty w package.json
projekcie Joomla.Wykonuję je przez npx [docs.npmjs.com/commands/npx].
zweryfikować cyprys
Polecenie cypress verify
sprawdza, czy Cypress jest poprawnie zainstalowany i czy można go uruchomić.
$ npx cypress verify
✔ Verified Cypress! /.../.cache/Cypress/12.8.1/Cypress
informacje o cyprysie
Polecenie cypress info
wyświetla informacje o Cypress i bieżącym środowisku.
$ npx cypress info
Displaying Cypress info...
Detected 2 browsers installed:
1. Chromium
- Name: chromium
- Channel: stable
- Version: 113.0.5672.126
- Executable: chromium
- Profile: /.../snap/chromium/current
2. Firefox
- Name: firefox
- Channel: stable
- Version: 113.0.1
- Executable: firefox
- Profile: /.../snap/firefox/current/Cypress/firefox-stable
Note: to run these browsers, pass : to the '--browser' field
Examples:
- cypress run --browser chromium
- cypress run --browser firefox
Learn More: https://on.cypress.io/launching-browsers
Proxy Settings: none detected
Environment Variables: none detected
Application Data: /.../.config/cypress/cy/development
Browser Profiles: /.../.config/cypress/cy/development/browsers
Binary Caches: /.../.cache/Cypress
Cypress Version: 12.8.1 (stable)
System Platform: linux (Ubuntu - 22.04)
System Memory: 4.08 GB free 788 MB
wersja cyprysowa
Polecenie cypress version
drukuje zainstalowaną wersję binarną Cypress, wersję pakietu Cypress, wersję Electron użytą do utworzenia Cypress oraz wersję dołączonego węzła.
$ npx cypress version
Cypress package version: 12.8.1
Cypress binary version: 12.8.1
Electron version: 21.0.0
Bundled Node version: 16.16.0
Dokumentacja Cypress zawiera bardziej szczegółowe informacje.
Pisanie pierwszego własnego testu
Jeśli do tej pory wszystko działało, możemy przystąpić do tworzenia własnych testów.
Uzyskaj przegląd
Uczenie się na podstawie już opracowanych testów
W rozwojowej wersji CMS Joomla są już testy Cypress, które znajdują się w folderze .Ci, /tests/System/integration
którzy lubią uczyć się na przykładach, znajdą tu odpowiednie wprowadzenie.
Importuj kod dla powtarzalnych zadań
Deweloperzy Joomla pracują nad projektem NodeJs joomla-cypress , który zapewnia kod testowy dla typowych przypadków testowych. Są one importowane podczas instalacji deweloperskiej wersji CMS za npm install
pomocą
package.json
i przez- plik wsparcia
/tests/System/support/index.js
Plik wsparcia jest zdefiniowany w konfiguracjicypress.config.js
.
// package.json
{
"name": "joomla",
"version": "5.0.0",
"description": "Joomla CMS",
"license": "GPL-2.0-or-later",
"repository": {
"type": "git",
"url": "https://github.com/joomla/joomla-cms.git"
},
...
"devDependencies": {
...
"joomla-cypress": "^0.0.16",
...
}
}
Przykładem jest kliknięcie przycisku paska narzędzi. Na przykład Cypress.Commands.add('clickToolbarButton', clickToolbarButton)
powoduje, że polecenie clickToolbarButton()
jest dostępne w niestandardowych testach, a cy.clickToolbarButton('new')
kliknięcie przycisku New
jest symulowane. Wymagany do tego kod jest pokazany w skrawku kodu poniżej.
// node_modules/joomla-cypress/src/common.js
...
const clickToolbarButton = (button, subselector = null) => {
cy.log('**Click on a toolbar button**')
cy.log('Button: ' + button)
cy.log('Subselector: ' + subselector)
switch (button.toLowerCase())
{
case "new":
cy.get("#toolbar-new").click()
break
case "publish":
cy.get("#status-group-children-publish").click()
break
case "unpublish":
cy.get("#status-group-children-unpublish").click()
break
case "archive":
cy.get("#status-group-children-archive").click();
break
case "check-in":
cy.get("#status-group-children-checkin").click()
break
case "batch":
cy.get("#status-group-children-batch").click()
break
case "rebuild":
cy.get('#toolbar-refresh button').click()
break
case "trash":
cy.get("#status-group-children-trash").click()
break
case "save":
cy.get("#toolbar-apply").click()
break
case "save & close":
cy.get(".button-save").contains('Save & Close').click()
break
case "save & new":
cy.get("#save-group-children-save-new").click()
break
case "cancel":
cy.get("#toolbar-cancel").click()
break
case "options":
cy.get("#toolbar-options").click()
break
case "empty trash":
case "delete":
cy.get("#toolbar-delete").click()
break
case "feature":
cy.get("#status-group-children-featured").click()
break
case "unfeature":
cy.get("#status-group-children-unfeatured").click()
break
case "action":
cy.get("#toolbar-status-group").click()
break
case "transition":
cy.get(".button-transition.transition-" + subselector).click()
break
}
cy.log('--Click on a toolbar button--')
}
Cypress.Commands.add('clickToolbarButton', clickToolbarButton)
...
Poniższy kod pokazuje inny przykład logowania do obszaru administracyjnego.
// /node_modules/joomla-cypress/src/user.js
...
const doAdministratorLogin = (user, password, useSnapshot = true) => {
cy.log('**Do administrator login**')
cy.log('User: ' + user)
cy.log('Password: ' + password)
cy.visit('administrator/index.php')
cy.get('#mod-login-username').type(user)
cy.get('#mod-login-password').type(password)
cy.get('#btn-login-submit').click()
cy.get('h1.page-title').should('contain', 'Home Dashboard')
cy.log('--Do administrator login--')
}
Cypress.Commands.add('doAdministratorLogin', doAdministratorLogin)
...
Typowe zadania w indywidualnym środowisku
W katalogu /tests/System/support
znajdziesz typowe zadania w poszczególnych środowiskach.Aby można je było łatwo ponownie wykorzystać, są importowane za pośrednictwem pliku pomocy.Przykładem /tests/System/support/index.js
często powtarzającego się zadania jest logowanie do obszaru administracyjnego, które jest obsługiwane w pliku /tests/System/support/commands.js
za pomocą funkcji doAdministratorLogin
.
Poniższy kod pokazuje również, w jaki sposób informacje z cypress.config.js
konfiguracji są wykorzystywane w testach. Cypress.env('username')
ma przypisaną wartość właściwości username
w ramach grupy env
.
Widzimy też tutaj jak nadpisuje komendy Cypress.Commands.overwrite('doAdministratorLogin' ...),
nadpisuje kod, który właśnie widzieliśmy w paczce joomla-cypress
Zaletą jest to, że użytkownik i hasło są automatycznie używane z indywidualnej konfiguracji.
// /tests/System/support/commands.js
...
Cypress.Commands.overwrite('doAdministratorLogin', (originalFn, username, password, useSnapshot = true) => {
// Ensure there are valid credentials
const user = username ?? Cypress.env('username');
const pw = password ?? Cypress.env('password');
// Do normal login when no snapshot should be used
if (!useSnapshot) {
// Clear the session data
Cypress.session.clearAllSavedSessions();
// Call the normal function
return originalFn(user, pw);
}
// Do login through the session
return cy.session([user, pw, 'back'], () => originalFn(user, pw), { cacheAcrossSpecs: true });
});
...
Zainstaluj własne rozszerzenie Joomla
Aby zobaczyć, jak przetestować własny kod, zainstalujemy prosty przykładowy komponent za pośrednictwem backendu Joomla.Plik do instalacji można pobrać ze strony Codeberg .
Po instalacji możesz znaleźć link do widoku komponentu Foo w lewym pasku bocznym backendu Joomla.
Mamy teraz skonfigurowane środowisko testowe i kod do testowania.
Pierwszy własny test
Haki
Podczas testowania backendu zauważysz, że każdy test musisz zaczynać od logowania.Możemy zapobiec temu nadmiarowemu kodowi za pomocą funkcji.Ten beforeEach()
tak zwany hak wykonuje kod, który wpisujemy przed uruchomieniem każdego testu.Stąd nazwa beforeEach()
.
Cypress udostępnia kilka typów haczyków , w tym before
haczyki after
uruchamiane przed lub po testach w grupie testowej oraz beforeEach
haczyki afterEach
uruchamiane przed lub po każdym indywidualnym teście w grupie.Haczyki można definiować globalnie lub w ramach określonego described
bloku.Następny przykładowy kod w pliku tests/System/integration/administrator/components/com_foos/FoosList.cy.js
powoduje wykonanie logowania w backendzie przed każdym testem w ramach described
bloku test com_foos features
.
Zaczynamy teraz od części praktycznej i przed napisaniem pierwszego produktywnego testu tworzymy plik tests/System/integration/administrator/components/com_foos/FoosList.cy.js
z następnym kodem. Nasz pierwszy przykład powinien pomyślnie zalogować nas do backendu przed jakimkolwiek testem! Przetestujemy to po utworzeniu pierwszego testu.
// tests/System/integration/administrator/components/com_foos/FoosList.cy.js
describe('Test com_foos features', () => {
beforeEach(() => {
cy.doAdministratorLogin()
})
})
Uwaga: Haki, które są zaimplementowane w file /tests/System/support/index.js
, mają zastosowanie do każdego pliku testowego w zestawie testowym.
Udany test
Komponent, który zainstalowaliśmy do testowania, zawiera trzy elementy Astrid
oraz Nina
. Elmar
Najpierw sprawdzamy, czy te elementy zostały pomyślnie utworzone.
// tests/System/integration/administrator/components/com_foos/FoosList.cy.js
describe('Test com_foos features', () => {
beforeEach(() => {
cy.doAdministratorLogin()
})
it('list view shows items', function () {
cy.visit('administrator/index.php?option=com_foos')
cy.get('main').should('contain.text', 'Astrid')
cy.get('main').should('contain.text', 'Nina')
cy.get('main').should('contain.text', 'Elmar')
cy.checkForPhpNoticesOrWarnings()
})
})
Uwaga: Funkcja, checkForPhpNoticesOrWarnings()
którą znajdziesz w pliku /node_modules/joomla-cypress/src/support.js
.
Element DOM uzyskujemy main
za pomocą polecenia Cypress get
Powinieneś znaleźć właśnie utworzony test FooList.cy.js
na liście dostępnych testów w lewym pasku bocznym. Jeśli tak nie jest, zamknij przeglądarkę i uruchom npm run cypress:open
ponownie.
Kliknij nazwę testu, aby go uruchomić. Powinien zakończyć się pomyślnie i zobaczysz zielone komunikaty.
Nieudany test
Dodaj linię cy.get('main').should('contain.text', 'Sami')
do pliku testowego, aby przebieg się nie powiódł. Nie ma elementu o tej nazwie. Po zapisaniu pliku testowego Cypress zauważa zmianę. Po każdej zmianie Cypress automatycznie ponownie uruchamia wszystkie testy w pliku testowym.
// tests/System/integration/administrator/components/com_foos/FoosList.cy.js
describe('Test com_foos features', () => {
beforeEach(() => {
cy.doAdministratorLogin()
})
it('list view shows items', function () {
cy.visit('administrator/index.php?option=com_foos')
cy.get('main').should('contain.text', 'Astrid')
cy.get('main').should('contain.text', 'Nina')
cy.get('main').should('contain.text', 'Elmar')
cy.get('main').should('contain.text', 'Sami')
cy.checkForPhpNoticesOrWarnings()
})
})
Zgodnie z oczekiwaniami test nie powiódł się. Pojawiają się czerwone komunikaty. Możesz zobaczyć kod każdego kroku testu na lewym pasku bocznym. Możliwe jest więc znalezienie przyczyny błędu. Dla każdego kroku znajduje się migawka dokumentu HTML, więc możesz sprawdzić znaczniki w dowolnym momencie. Jest to pomocne, szczególnie podczas programowania.
Uruchom tylko jeden test w pliku
Nasze rozszerzenie demonstracyjne zawiera więcej niż jeden układ. Dodaj test do testowania układu stanu pustego. Ponieważ mamy teraz dwa testy w tym pliku, Cypress będzie zawsze przeprowadzał oba testy za każdym razem, gdy zapiszemy plik. Możemy użyć tak, aby tylko jeden .only()
test jest wykonywany:
// tests/System/integration/administrator/components/com_foos/FoosList.cy.js
describe('Test com_foos features', () => {
beforeEach(() => {
cy.doAdministratorLogin()
})
it('list view shows items', function () {
cy.visit('administrator/index.php?option=com_foos')
cy.get('main').should('contain.text', 'Astrid')
cy.get('main').should('contain.text', 'Nina')
cy.get('main').should('contain.text', 'Elmar')
cy.checkForPhpNoticesOrWarnings()
})
it.only('emptystate layout', function () {
cy.visit('administrator/index.php?option=com_foos&view=foos&layout=emptystate')
cy.get('main').should('contain.text', 'No Foo have been created yet.')
})
})
Podczas opracowywania jest to bardzo wygodne.
Specjalne atrybuty testu
Teraz lubimy testować frontend dla naszego komponentu, robimy to w osobnym pliku /tests/System/integration/site/components/com_foos/FooItem.cy.js
.
Przez większość czasu używamy klasy CSS, aby uzyskać elementy w testach Joomla. Chociaż jest to całkowicie poprawne i będzie działać, nie jest tak naprawdę zalecane. Dlaczego nie? Kiedy używasz klas lub identyfikatorów CSS, wiążesz swoje testy z rzeczami, które najprawdopodobniej zmienią się z czasem. Klasy i identyfikatory służą do projektowania, układu, a czasami za pomocą JavaScript do sterowania, które można łatwo zmienić. Jeśli ktoś zmieni nazwę klasy lub identyfikator, twoje testy przestaną działać. Aby twoje testy były mniej kruche i bardziej przyszłościowe, Cypress zaleca tworzenie specjalnych atrybutów danych dla twoich elementów specjalnie do celów testowych.
Użyję data-test
atrybutu dla elementów.Najpierw dodam atrybut data-test="foo-main"
do kodu produkcyjnego.
// /components/com_foos/tmpl/foo/default.php
\defined('_JEXEC') or die;
?>
<div data-test="foo-main">
Hello Foos
</div>
Następnie testuję kod produkcyjny, wyszukując atrybut [data-test="foo-main"]
.
// tests/System/integration/site/components/com_foos/FooItem.cy.js
describe('Test com_foo frontend', () => {
it('Show frondend via query in url', function () {
cy.visit('index.php?option=com_foos&view=foo')
cy.get('[data-test="foo-main"]').should('contain.text', 'Hello Foos')
cy.checkForPhpNoticesOrWarnings()
})
})
Testowanie pozycji menu i kilka przemyśleń na temat wydarzeń, oczekiwania i najlepszych praktyk
Teraz lubię testować tworzenie elementu menu dla naszego komponentu.Robię to w osobnym pliku.Ten /tests/System/integration/administrator/components/com_foos/MenuItem.cy.js
kod jest złożony i pokazuje wiele specjalnych funkcji.
Najpierw zdefiniowałem stałą, w której ustawiam wszystkie istotne właściwości pozycji menu.Ma to tę zaletę, że w przypadku zmiany odpowiedniej właściwości muszę dostosować tylko w jednym miejscu:
const testMenuItem = {
'title': 'Test MenuItem',
'menuitemtype_title': 'COM_FOOS',
'menuitemtype_entry': 'COM_FOOS_FOO_VIEW_DEFAULT_TITLE'
}
Następnie zobaczysz cały kod pliku MenuItem.cy.js
:
// tests/System/integration/administrator/components/com_foos/MenuItem.cy.js
describe('Test menu item', () => {
beforeEach(() => {
cy.doAdministratorLogin(Cypress.env('username'), Cypress.env('password'))
})
it('creates a new menu item', function () {
const testMenuItem = {
'title': 'Test MenuItem',
'menuitemtype_title': 'COM_FOOS',
'menuitemtype_entry': 'COM_FOOS_FOO_VIEW_DEFAULT_TITLE'
}
cy.visit('administrator/index.php?option=com_menus&view=item&client_id=0&menutype=mainmenu&layout=edit')
cy.checkForPhpNoticesOrWarnings()
cy.get('h1.page-title').should('contain', 'Menus: New Item')
cy.get('#jform_title').clear().type(testMenuItem.title)
cy.contains('Select').click()
cy.get('.iframe').iframe('#collapse1-heading').contains(testMenuItem.menuitemtype_title).click()
cy.get('.iframe').iframe('#collapse1-heading').contains(testMenuItem.menuitemtype_entry).click()
cy.intercept('index.php?option=com_menus&view=items&menutype=mainmenu').as('item_list')
cy.clickToolbarButton('Save & Close')
cy.wait('@item_list')
cy.get('#system-message-container').contains('Menu item saved.').should('exist')
// Frontend
cy.visit('index.php')
cy.get('.sidebar-right').contains(testMenuItem.title).click()
cy.get('[data-test="foo-main"]').should('contain.text', 'Hello Foos')
cy.checkForPhpNoticesOrWarnings()
// Trash
cy.visit('administrator/index.php?option=com_menus&view=items&menutype=mainmenu')
cy.searchForItem(testMenuItem.title)
cy.checkAllResults()
cy.clickToolbarButton('Action')
cy.intercept('index.php?option=com_menus&view=items&menutype=mainmenu').as('item_trash')
cy.clickToolbarButton('trash')
cy.wait('@item_trash')
cy.get('#system-message-container').contains('Menu item trashed.').should('exist')
// Delete
cy.visit('administrator/index.php?option=com_menus&view=items&menutype=mainmenu')
cy.setFilter('published', 'Trashed')
cy.searchForItem(testMenuItem.title)
cy.checkAllResults()
cy.on("window:confirm", (s) => {
return true;
});
cy.intercept('index.php?option=com_menus&view=items&menutype=mainmenu').as('item_delete')
cy.clickToolbarButton('empty trash');
cy.wait('@item_delete')
cy.get('#system-message-container').contains('Menu item deleted.').should('exist')
})
})
- W tym kodzie widać przykład testowania czegoś, a następnie usuwania wszystkiego - przywracania w ten sposób stanu początkowego. W ten sposób możesz powtarzać testy tyle razy, ile chcesz. Bez przywrócenia stanu początkowego drugie uruchomienie testu zakończy się niepowodzeniem, ponieważ Joomla nie może przechowywać dwóch podobnych elementów.
Uwaga: Test powinien być:
- powtarzalne.
- Konkretnie oznacza to, że powinien testować ograniczony problem, a jego kod nie powinien być zbyt obszerny.
- niezależny od innych testów.
- Możesz zobaczyć, jak używać przechwyconej trasy zdefiniowanej za pomocą
cy.intercept()
[^docs.cypress.io/api/commands/intercept] jako aliasu, a następnie czekać na trasę zdefiniowaną jako alias za pomocący.wait()
.
Pisząc testy dla takich aplikacji, można pokusić się o użycie losowych wartości, takich jak
cy.wait(2000);
wcy.wait
poleceniu.Problem z tym podejściem polega na tym, że chociaż może to dobrze działać w fazie rozwoju.Jednak nie ma gwarancji, że zawsze będzie działać.Dlaczego?Bo leżący u podstaw system zależy od rzeczy, które trudno przewidzieć, dlatego zawsze lepiej jest dokładnie określić, na co się czeka.
- Kod pokazuje również, jak czekać na alert i potwierdzić go.
cy.on("window:confirm", (s) => { return true; });
- Co nie mniej ważne, kod testowy zawiera funkcje wbudowane w Cypress i typowe dla Joomla, które mogą być ponownie wykorzystane przez programistów rozszerzeń, na przykład lub są
cy.setFilter('published', 'Trashed')
funkcjamicy.clickToolbarButton('Save & Close')
, w których ogólnie można znaleźć rozwiązania dla poszczególnych testów i których programiści Joomla w szczególności często potrzebują .Mieszanie kodu asynchronicznego i synchronizacyjnego
Polecenia Cypress są asynchroniczne, to znaczy nie zwracają wartości, ale
generate
ją. Kiedy uruchamiamy Cypress, nie wykonuje on poleceń natychmiast, ale odczytuje je szeregowo i ustawia w kolejce. Jeśli mieszasz kod asynchroniczny i synchroniczny w testach, może uzyskać nieoczekiwane wyniki. Jeśli uruchomisz następujący kod, otrzymasz błąd wbrew oczekiwaniom. Z pewnością spodziewałbyś się również, żemainText = $main.text()
zmienia wartośćmainText
. AlemainText === 'Initial'
nadal jest ważny na końcu. Dlaczego? Cypress najpierw wykonuje kod synchroniczny w na początku i na końcu.Tylko wtedy wywołuje część asynchroniczną wewnątrz.Tothen()
znaczy, że zmiennamainText
jest inicjowana i zaraz potem sprawdzane, czy się zmieniła - co oczywiście nie ma miejsca.
let mainText = 'Initial'; cy.visit('administrator/index.php?option=com_foos&view=foos&layout=emptystate') cy.get("main").then( ($main) => (mainText = $main.text()) ); if (mainText === 'Initial') { throw new Error(`Der Text hat sich nicht geändert. Er lautet: ${mainText}`); }
Przetwarzanie kolejki staje się dość jasne i wizualne, jeśli obserwuje się wykonanie następującego kodu w konsoli przeglądarki: Tekst „Cypress Test.” pojawia się na długo przed wyświetleniem zawartości elementu, chociaż linie kodu
main
są w innej kolejności.
cy.get('main').then(function(e){ console.log(e.text()) }) console.log('Cypress Test.')
Zalążki i szpiedzy
A
stub
to sposób na symulację zachowania funkcji, od której zależą testy. Zamiast wywoływać rzeczywistą funkcję, kod pośredniczący zastępuje tę funkcję i zwraca predefiniowany obiekt. Zwykle jest używany w testach jednostkowych, ale może być również używany do celów końcowych -testy do końca.A
spy
jest podobne dostub
, ale nie dokładnie takie samo. Nie zmienia zachowania funkcji, ale pozostawia ją taką, jaka jest. Przechwytuje pewne informacje o sposobie wywoływania funkcji. Na przykład, aby sprawdzić, czy funkcja jest wywoływana z poprawnymi parametrami lub policzyć, jak często funkcja jest wywoływana.Poniższy przykład pokazuje a
spy
i astub
w akcji. Poprzezconst stub = cy.stub()
tworzymystub
element i określamy w następnym kroku, któryfalse
jest zwracany dla pierwszego wywołania i dlatrue
drugiego. Używająccy.on('window:confirm', stub)
używamystub
dowindow:confirm'
. W następnym kroku tworzymy zcy.spy(win, 'confirm').as('winConfirmSpy')
elementemSpy
, który obserwuje wywołanie'window:confirm'
. Teraz testujemy, że przy pierwszym wywołaniu usunięcie kategorii zostaje odrzucone, a przy drugim wywołaniu jest potwierdzone. Robiąc to, zapewniamy,stub
że możemy się na pewno spodziewać, jakie zostaną zwrócone wartości dostarczona'window:confirm'
jest hermetyzowana@winConfirmSpy
pomaga upewnić się, że funkcja została faktycznie wywołana - i jak często była wywoływana.
// tests/System/integration/administrator/components/com_foos/FoosList.cy.js ... const stub = cy.stub() stub.onFirstCall().returns(false) stub.onSecondCall().returns(true) cy.on('window:confirm', stub) cy.window().then(win => { cy.spy(win, 'confirm').as('winConfirmSpy') }) cy.intercept('index.php?option=com_categories&view=categories&extension=com_foos').as('cat_delete') cy.clickToolbarButton('empty trash'); cy.get('@winConfirmSpy').should('be.calledOnce') cy.get('main').should('contain.text', testFoo.category) cy.clickToolbarButton('empty trash'); cy.wait('@cat_delete') cy.get('@winConfirmSpy').should('be.calledTwice') cy.get('#system-message-container').contains('Category deleted.').should('exist') ...
Jeśli jest to tylko kwestia ustawienia stałej wartości dla wywołania
'window:confirm'
, poniższy kod wykona zadanie.
cy.on("window:confirm", (s) => { return true; });
wniosek
W tym artykule zapoznałeś się z podstawową teorią i praktycznymi cechami testowania E2E za pomocą Cypress. Użyłem instalacji Joomla, aby zademonstrować, jak napisać różne testy, aby upewnić się, że komponent Joomla na stronie internetowej działa zgodnie z oczekiwaniami. Pokazałem również, jak dostosować Cypress Przetestuj Runnera w pliku cypress.json i jak używać niestandardowych poleceń Cypress.Zrobiono to na łatwych do naśladowania przykładach.
Mam nadzieję, że podobała Ci się wycieczka po Cypress na przykładzie Joomla i że udało Ci się wynieść dużo wiedzy i inspiracji dla siebie.