Przejdź do treści

Jak napisać testy end-to-end? Nightwatch.js & Chrome Headless?

Podczas tego weekendu poznałem Mateusza - testera oprogramowania, który chce się przebranżowić. Wiecie kim chce zostać? No nie uwierzycie. Chce zostać Front-end Developerem. To już kolejna osoba, której podoba się wytwarzanie oprogramowania klienckiego. Świetnie!

Bardzo się cieszę, że kolejna osoba się przebranżawia. Wymaga to od niej dużo odwagi, cierpliwości no i najważniejsze - samozaparcia.

Artykuł został zaktualizowany 🏆

Post skierowany jest do testerów oprogramowania, którzy znają składnię JavaScript.

Baner promujący artykuł

Historia Mateusza

Mati opowiedział mi o swoim doświadczeniu z poprzedniej pracy, w której to był testerem aplikacji webowych. Nudziło go klikanie non stop w tą samą aplikację za każdym razem, kiedy developerzy chcą wypuścić nową wersję aplikacji. Nie dziwi mnie to.

W mojej pracy też mamy zespół testerów, którzy muszą mieć mega silną psychikę powtarzać te same czynności non stop. Panowie jeśli to czytacie to szacun oraz 🏆 dla każdego z Was.

Zastanawiam się, jak ja bym sobie poradził w takiej roli. Nie wiem, czy nie denerwowałbym się, ponieważ:

  • jeśli nie znajdę błędu bo np. nie przetestuje jakiegoś przypadku, bo na przykład mam zły dzień, albo nie mogę się skupić bo wczoraj był grill z kolegami
  • jeśli znajdę błąd to developerzy są na mnie źli, bo pokazałem im, że się gdzieś pomylili, a przecież ja wykonuję tylko swoją pracę i jeśli znajdę błąd to chyba dobrze, bo oznacza to, że gdy zostanie on poprawiony to aplikacja będzie stabilniejsza.

Tak źle i tak nie dobrze.

Jak przechytrzyć programistę?

Uwielbiam pisać testy. Nie ma znaczenia jakie. Jestem wychowany tak, że gdy mam napisany test to czuję pewność napisanej przeze mnie implementacji, bo przecież nieważne jak ją napiszę, jeśli testy świecą się ciągle na zielono.

Pytanie 1: Czy można napisać testy, które zastąpią manualne klikanie testera?

Śmiem twierdzić, że tak.

Pytanie 2: Czy mógłbym zdefiniować kroki scenariusza testowego gdzieś w aplikacji, aby uruchamiać te kroki za każdym razem, aby zbadać czy nie ma regresu?

Pewnie!

Jednak wcale nie potrzebujesz dostępu do projektu. Możesz takie testy trzymać na swoim komputerze (oczywiście najlepiej źródła wypchnąć do prywatnego repozytorium na GitHubie), dzięki czemu żaden developer nawet nie będzie wiedział o Twoim pomyśle.

Walka z Selenium (jeśli znasz, to pomiń ten akapit)

Każdy developer kiedyś słyszał o Selenium. Jest to dość skomplikowane narzędzie do ogarnięcia. Pisanie testów odbywa się z wykorzystywaniem składni zdefiniowanej w Selenium. Wg mnie jest to średni pomysł. Ale jest na to sposób!

Nie wiesz co to jest Selenium?

Nie będę teraz tego wyjaśniał. Powstało sporo artykułów na ten temat.
Zobacz tutaj albo tutaj albo w Wikipedii.

Na ten moment chciałbym przedstawić Ci na obrazku jak cały mechanizm. Moim zdaniem jeden rysunek jest wart “tysiąc słów”.

Komunikacja Selenium serwera ze stroną internetową
Schemat działania Selenium.
Diagram stworzony z użyciem narzędzia: draw.io.

Straż nocna

Napiszemy testy end-to-end, które będę realizowały 2 scenariusze:

  • badanie czy po załadowaniu strony, zawiera ona pewien tekst,
  • czy strona prezentuje odpowiednią liczbę elementów w menu,

…oraz zrobimy screenshot testowanej strony internetowej, po to, aby móc np. pokazać developerowi jak wygląda błąd “zauważony przez testera”.

Yay

Piękna sprawa. Nie trzeba będzie powtarzać błędnego flow.
Narzędzie za nas zrobi zrzut ekranu.

Testy będziemy pisać korzystając z narzędzia Nightwatch.js.
Nie znasz? Strona domowa projektu dostępna jest tutaj.

Tylko dodam, że w narzędziu Nightwatch.js można pisać również testy jednostkowe. Więcej na ten temat dowiesz się z tego miejsca.

Krok po kroku 👣

Stworzyłem projekt na GitHubie, który posiada gotową (opisywaną w tym artykule) konfigurację Nightwatch.js (Selenium) + Chrome Headless.

1) Stworzenie pustego katalog (na projektu).

To chyba jasne i nie muszę tego pisać, jednak napiszę, aby rozwiać wszelkie wątpliwości.

2) Stworzenie pliku package.json

Masz dwie opcje aby posiadać taki plik:

  • manualna - ręcznie tworzysz taki plik i wpisuje odpowiednie pola
  • albo generujesz plik za pomocą polecenia npm init.

Ze swojej strony polecam drugą opcję. Jest szybsza.

3) Instalacja narzędzi

Copy + paste

npm install nightwatch selenium-standalone

Ważne aby, te dwie zależności znalazły się pliku package.json. Tym samym dasz możliwość uruchomienia przez innego testera Twojego projektu z testami, (albo nawet przez programistę).

4) Dodanie odpowiednich zadań do package.json

Proponuję dodać 2 następujące zadania:

{
    "scripts": {
        "selenium:start": "selenium-standalone install && selenium-standalone start",
        "test:e2e": "nightwatch"
    }
}

Pierwsze skonfiguruje i uruchomi serwer Selenium. Drugie natomiast uruchomi skrypty testujące napisane w JavaScript korzystające z API biblioteki Nightwatch.js.

5) Konfiguracja narzędzia Nightwatch.js

Testowanie tak samo jak aplikacja, może być bardzo skomplikowane, stąd też należy wykorzystać plik konfiguracyjny, gdzie zdefiniujemy jak ma działać narzędzie do uruchamiania testów end-to-end (Nightwatch.js).

Przedstawiam podstawową konfigurację, jaka powinna się znaleźć w pliku nightwatch.json - w katalogu głównym projektu. Nie będę opisywał pól, tylko zapraszam do dokumentacji.

{
    "src_folders": [
        "test/e2e/"
    ],

    "output_folder": "reports",

    "test_settings": {
        "default": {
            "silent": true,

            "desiredCapabilities": {
                "browserName": "chrome",
                "chromeOptions": {
                    "args": [
                        "--headless"
                    ],
                    "binary": "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"
                }
            }
        }
    }
}

Pod klucze binary znajduje się ścieżka do programu, który ma być uruchamiany na potrzeby weryfikacji scenariuszy. Na systemach Windows, należy wkleić ścieżkę zmieniając backslashe (domyślna forma rozdzielenia katalogów) na slashe.

Na uwagę zasługuje wykorzystanie argumentu "--headless", z którym będzie uruchamiana przeglądarka Google Chrome Canary.

Headless to nowy feature w tej przeglądarce, który pozwala na uruchomienie przeglądarki bez GUI. Zainteresowany jak działa ten feature? Przeczytaj tutaj.

Na stronie opisujące ten feature jest ostrzeżenie (w języku angielskim):

Caution: Headless mode is available on Mac and Linux in Chrome 59.
Windows support is coming in Chrome 60.
To check what version of Chrome you have, open chrome://version.

W skrócie, testy polegające na otwieraniu strony i analizowaniu jej treści mogą przebiegać bez otworzenia przeglądarki. Jaki jest tego plus? Ja widzę jeden podstawowy - wydajność, tj. skrócenie czasu potrzebnego na uruchomienie testów.

A co powiesz na temat PhantomJS?

Wykorzystanie Headless to nie jedyny sposób, aby uruchomić takie testy. Można wykorzystać narzędzie PhantomJS. Nie polecam jednak tego narzędzia z uwagi na to, że wykorzystuje ono stary silnik Chrome-a do renderowanie - Webkit, gdzie Headless korzysta z najnowszego - Blink.

6) Pierwszy test: Czy strona posiada tekst?

Testy musisz zdefiniować w pliku stworzonym w katalogu z definiowanym w konfiguracji pod kluczem src_folders.

I tak na przykład stwórz plik: test.example.js, który będzie wykorzystywał składnię CommonJS, aby wyeksportować obiekt jako moduł.

const TARGET_PAGE_URL = 'https://piecioshka.pl/blog/';

module.exports = {
    'Is header contains correct text?': (browser) => {
        browser.url(TARGET_PAGE_URL);
        browser.waitForElementVisible('body', 3000);
        browser.assert.containsText('h2', 'Piotr Kowalski');
        browser.end();
    }
};

Co tutaj się dzieje? Generalnie każda para klucz-wartość to pewien scenariusz. Jego nazwa zapisana jest w kluczu, a kroku w definicji funkcji.

Pełne API, czyli definicja akcji, które możesz zrobić na stronie dostępna jest tutaj.

Wskazówki, na temat jak pisać poprawnie testy end-to-end są opisane na stronie projektu. Link do przewodnika jest tutaj.

7) Drugi test: Czy strona zawiera odpowiednią ilość elementów?

// ...
module.exports = {
    // ...
    'Is main part of app contains proper number of elements?': (browser) => {
        browser.url(TARGET_PAGE_URL);
        browser.waitForElementVisible('body', 3000);
        browser.elements('css selector', '#menu li', (result) => {
            if (result.value.length !== 4) {
                browser.assert.fail('Number of elements is not correct');
            }
        });
        browser.end();
    }
}

8) Trzecia opcja: Zrzut ekranu

// ...
module.exports = {
    // ...
    'Capture screenshot to see manually that page looks correct': (browser) => {
        browser.url(TARGET_PAGE_URL);
        browser.waitForElementVisible('body', 1000);
        let filename = './screenshots/screenshot-' + new Date().toISOString() + '.png';
        browser.saveScreenshot(filename);
        browser.end();
    }
};

9) Uruchomienie testów end-to-end, które właśnie napisaliśmy

Teraz wystarczy, że otworzysz 2 okna terminala:

  • w jednym uruchomisz serwer Selenium, za pomocą polecenia npm run selenium:start
  • w drugim oknie uruchomisz Nightwatch.js, aby uruchomić napisane testy, za pomocą polecenia: npm run test:e2e

Java

Selenium wymaga zainstalowanego środowiska do uruchomiania programów napisanych w języku Java. Środowisko to nazywa się JRE - Java Runtime Environment.
Pobierz najnowszą wersję z http://java.com/

Poniżej przedstawiam Ci jak wygląda drugi terminal w którym uruchamiam testy:

Serwera nie ma co pokazywać. Tam się dzieje magia, na którą nie wolno patrzeć.

Pytania

Pozwolisz, że zadam Ci teraz kilka pytań. Swoje odpowiedzi umieść proszę w komentarzu:

  1. Jak Ci się podoba takie podejście do testowania?
  2. Czy jako tester pokazałabyś programiście kod, który testuje jego aplikację, czy jednak wolałbyś zostawić go dla siebie, aby developer nie miał wpływu na definicję scenariuszy?
  3. Czy przetestowałeś, jak Nightwatch.js oraz Chrome Headless sprawują się w projekcie, który jest wykorzystywany w Twojej pracy?
  4. Czy takie testy powinny być tworzone przez programistów, czy raczej przez testerów oprogramowania?

Będę wdzięczny za odpowiedzi.
Pamiętaj, że komentarze są po to, aby prowadzić w nich dyskusje.

PS Mateusz, mam nadzieję, że pomogłem. Piona!