Jaki wybrać framework do testów automatycznych aplikacji napisanych w Electronie i dlaczego powinien to być Spectron?

 

Jako początkujący tester, gdy słyszałam o testach automatycznych, miałam w głowie Selenium WebDriver oraz dwa naczelne języki programowania, które zwykle są stosowane dla tego frameworku, czyli Pythona oraz Javę. Jednakże, z czasem pojawiły się inne możliwości, te szybsze, mające obecnie większą rzeszę zwolenników niż przeciwników. Mowa tu np. o Cypressie. Bardzo podobnym frameworkiem, który jak Cypress wykorzystuje JavaScript, jest Spectron. To właśnie framework przeznaczony do aplikacji Electronowych, którego opiszę poniżej.

Ten artykuł podzielony jest na dwie części. W pierwszej objaśnię czym jest Electron i wytłumaczę jego dwa główne procesy, a w drugiej przejdę do Spectrona. Więc, jeśli macie już wiedzę na temat Electrona, możecie śmiało przejść od razu do części drugiej. 

Część 1. Electron

O Electronie słów kilka

Electron, nazywany również Electronem JS, jest to framework open source do budowania natywnych aplikacji z wykorzystaniem JS, HTML i CSS. Aplikacje zbudowane w Elektronie nie wymagają specjalnie pisanego osobnego backendu, ponieważ już sam framework używa Node.js. Pisząc w Electronie, mamy jeden kod który jest kompatybilny z Windowsem, Mac’iem oraz Linuxem.

Najpopularniejsze aplikacje które zostały zbudowane w Electronie to: Visual Studio Code, WhatsApp, Github Desktop, Slack, czy też inVision.

Procesy main i render

Po naświetleniu możliwości jakie daje Electron, opiszę jeszcze dwa procesy które są dostępne przy pisaniu electronowych aplikacji, a mianowicie proces główny (main process) i proces renderowania (rendering process). Już na wstępie trzeba zaznaczyć, że main i renderer process nie są procesami stricte electronowymi, a raczej tymi które są odziedziczone po Chromium i używane przez Chrome dla stabilności i wydajności procesów - więcej informacji możecie znaleźć tutaj. Każda instancja webContents działa w swoim własnym procesie (procesie renderującym). Główny proces (może być tylko jeden) zarządza między innymi instancjami webContents. Oba procesy posiadają dostęp do różnych API, dlatego gdy chcemy używać ich w różnych plikach możemy to zrobić za pomocą IPC lub modułu remote.

Na przykładzie BrowserWindow, czyli okna, które uruchamia nam się również przy testach, możemy powiedzieć że, główny proces tworzy stronę internetową poprzez tworzenie instancji BrowserWindow. Każda instancja BrowserWindow uruchamia stronę internetową we własnym procesie renderowania. Gdy instancja BrowserWindow zostanie usunięta, odpowiedni proces renderowania również zostanie zakończony.

browserwindow-proces-renderowania.png

Więcej o procesach i tworzeniu aplikacji w Electronie znajdziecie tutaj.

Dlaczego tyle piszę o tym w kontekście Spectrona i testów automatycznych? Otóż, przy pisaniu testów te dwa procesy są przez nas wykorzystywane np. przy wgrywaniu pliku do testu czy tworzeniu pliku w teście. Owszem, jeśli zanurkujmy w internecie możemy znaleźć taką bibliotekę jak spectron-fake-dialog, która posłuży nam do mockowania danych i nie musimy wtedy ingerować w kod źródłowy. Niestety, biblioteka ta nie wgra nam realnego pliku, a jedynie zamockuje jego istnienie. Dlatego też, jeśli potrzebujemy operować na plikach realnych (pobierać lub zapisywać na nich dane), możemy posłużyć się dwoma wymienionymi wcześniej procesami.

Część 2. Spectron

Spectron to, jak już wspominałam wcześniej, open source’owy framework przeznaczony do testów aplikacji electronowych. Z jego pomocą mamy dostęp do pełnego API Electrona. Jest zbudowany na ChromeDriver oraz WebDriverIO, co daje nam dostęp do API WebDriverIO, a to już duży plus dla osób znających ten framework. Łączy również asynchroniczność oraz asercje używając standardowych Promise. Jest kompatybilny z Mocha, Jasmine, AVA, oraz Chai. Testy mogą być poddane ciągłej integracji np w Travisie.

Instalacja i pierwszy test

Do współpracy z Spectronem najczęściej wybieranym frameworkiem jest Mocha lub Jest. W tym przykładzie posłużymy się Mocha. 

Żeby zainstalować Spectrona wystarczy wpisać komendę za pomocą npm w konsoli:

npm install --save-dev spectron

oraz zainstalować Moche:

npm i mocha -D

Następnie tworzymy katalog test a w nim plik spec.js. W pliku wykorzystujemy oczywiście Spectrona, ale też path, assert oraz electron:

const assert = require('assert');
const path = require('path');
const electronPath = require('electron');
const { Application } = require('spectron');

Następnie, dodajemy path, czyli wskazujemy ścieżkę do naszej aplikacji:

const app = new Application({
       path: electronPath,
       args: [path.join(__dirname, '..')]
});

Teraz przejdźmy do pierwszego testu. Można go zamknąć w zestawie testów (test suite), a następnie tworzyć testy pojedynczo. Od razu możemy wyeksportować to, co jest powtarzalne, jak np. start i stop aplikacji w beforeEach() i afterEach(). Dodajemy również timeout i wtedy podstawowa konfiguracja będzie wyglądać tak:

describe('First Test Suite: ', function () {
    this.timeout(500000);
      beforeEach(() => app.start());
   	afterEach(() => app.stop());
});

Async/Await

Jak już wspomniałam wcześniej Spectron wykorzystuje Promise, którego składnia może nie zachęcać. Za to, z powodzeniem możemy wykorzystać Async/Await. Dla tych, którzy nie są z nim zaznajomieni, pokrótce wyjaśnię, czym jest. Jest to specjalny syntax który współgra z Promise. Przed funkcją używamy słówka async(), które powoduje, że funkcja zwraca nam Promise. Słówko await sprawia że JS czeka, aż Promise się spełni i zwróci nam wynik. Więcej informacji na ten temat możecie znaleźć tutaj, a teraz zobaczmy to na przykładzie testu:

it('Check text from button', async () => { 
const selector = '[data-spectron="button-example"]';
const getTextFromButton = await app.client.getText(selector);
assert.equal(
        getTextFromButton, 
       'Example Text', 
       'Text from button is not the same as expected');
   });

Właściwości

W Spectronie wykorzystujemy dwie główne właściwości, a mianowicie ‘client’ i ‘electron’. W trzeciej linijce kodu możecie zauważyć właściwość ‘client’, która jest interfejsem API WebDriverIO, dzięki czemu mamy dostęp do komend takich jak: click, getValue, isEnabled, waitForExist, czy też wyżej wymienione getText. Pełną listę znajdziecie tutaj.

Druga właściwość to ‘electron’. Jest to nasza furtka do API Electrona, które to jest dużym plusem przy używaniu Spectrona. Mamy tutaj dostęp np. do clipboard, gdzie możemy zapisywać, czytać czy też znajdować dane w schowku. Wszystkie komendy zwracają Promise dlatego przed używamy await.

Selektory

Jak już wprawne oko zdążyło zauważyć, w selektorze używam ‘data-spectron’, nie ‘id’ czy też selektora CSS. Jeśli zaznajomieni jesteście z Cypressem i jego dobrymi praktykami to znajdziecie tam informację, że używanie atrybutu ‘data-*’ pozwala wyizolować selektor od zmian w kodzie JS czy zmian w CSS.  W Cypress, użylibyśmy atrybutu ‘data-cy’ lub ‘data-cypress’, a w Spectronie możemy użyć ‘data-spectron’, ważne, żeby był to atrybut wyizolowany. Oczywiście, jest to do ustalenia z zespołem testerskim oraz programistami ponieważ zmian, wymaga wtedy też kod źródłowy. Więcej na ten temat możecie znaleźć tu.

Jak odpalić test

To już ostatnia prosta. Wystarczy że dodamy do naszego pliku package.json:

"scripts": {
  "test": "mocha"
}

I teraz już możemy odpalić test z konsoli za pomocą npm:

npm test

Więcej informacji na temat API, instalacji oraz użytkowania możecie znaleźć tutaj.

Spectron: hit czy kit?

Spectron jest pokazany jako framework do testów aplikacji electronowych, dlatego też gdy myślimy o testach e2e, to jest on pierwszy w kolejce do rozważenia. Mimo to, co jeśli chcielibyśmy użyć czegoś innego? 

Zapewne od razu pierwsze co przychodzi do głowy to Cypress, który zyskał na popularności jeśli chodzi o testy e2e. Niestety, po próbach wsparcia przez Cypress aplikacji pisanych w Electron.js, wycofał się z tego ponad rok temu i na ten moment nie zamierza go więcej wspierać. A co z Selenium WebDriver i Javą lub Pythonem? Można, w końcu Spectron również bazuje na ChromeDriver, konfiguracja jest dłuższa ale możliwa. To co przemawia za Spectronem w tej rywalizacji to krótszy, bardziej przejrzysty kod testowy, oraz używanie Async/Await, które pomagają zapewnić czystość kodu. To co jeszcze ma Spectron, to dostęp do API Electrona, które może nam się przydać np. do kopiowania i wyjmowania treści ze schowka. 

Zatem czy Spectron to narzędzie idealne? Myślę, że nie ma narzędzi idealnych ;)  Na pewno przemawia za nim to, że jest swego rodzaju monopolistą na rynku testów w Electronie. Z kolei to co działa na niekorzyść Spectrona to dostęp do informacji. O tym frameworku poza dokumentacją na stronie i paroma wzmiankami w artykułach nie dowiecie się za wiele. Niestety, gdy natraficie na jakiś problem, jest on zwykle już zgłoszony i jeszcze nie rozwiązany lecz jest to narzędzie ciągle rozwijające się, więc powiedziałabym że jest tu duży potencjał.

Czy muszę znać JavaScript do pisania testów w Spectronie?

Myślę, że już częściowo znacie odpowiedź na te pytanie. Można natknąć się na wiele dyskusji czy do pisania testów automatycznych trzeba znać język programowania. Samo zrozumienie syntaxu, konstrukcji, mapowania czy znajomość metod są bardzo przydatne lecz nie jest to wiedza z poziomu zaawansowanego seniora i podstawy jak najbardziej nam wystarczą. W końcu, w testach nie chodzi o to, żeby wrzucać tam jak najwięcej logiki, a żeby testy były zrozumiałe i czytelne nawet dla osób mniej technicznych. Trzeba również pamiętać, że sam JavaScript nie występuje praktycznie nigdy. W parze z nim najczęściej spotkamy React, ale również i TypeScript. Jeśli w waszym dedykowanym projekcie występuje React, Vue czy też może Angular, to przy pisaniu testów jego podstawy są również mile widziane. 

Podsumowanie

Spectron pomoże Wam lub Waszym zespołom wdrożyć testy automatyczne w krótkim czasie oraz posiąść informację zwrotną na temat jakości kodu. Narzędzie to jest cały czas rozwijane, ale już teraz wystarcza by napisać w nim wartościowe testy.

Mam nadzieję że powyższy artykuł przybliżył plusy oraz minusy używania Spectrona oraz pomoże Wam w pierwszych krokach testowania aplikacji electronowych. Powodzenia!