w Praktyce
7 godz. 1 min · Angular · Full-stack i Programowanie
Mateusz KuleszaSenior Software Developer, Konsultant, TrenerPodstawą produktywnej pracy z angularem jest możliwość zagwarantowania że wszystko działa bez potrzeby wielokrotnego “przeklikiwania” poszczególnych ekranów. W pierwszej części kursu omawiam więc temat testów automatycznych.Już po obejrzeniu pierwszych lekcji zobaczysz dlaczego warto testować kod i jak dzięki narzędziom dostarczonym z angularem jest to proste. Zobaczysz jak testowanie automatyczne pozwoli zaoszczędzić Ci wiele godzin spędzonych na szukaniu błędów.
Za jakość aplikacji odpowiada nie tylko to czy działa ona poprawnie, ale w dużej mierze decyduje o tym dobry interfejs użytkownika oraz UX, czyli user experience. Dwie kolejne sekcje kursu poświęcone są właśnie dobremu UI oraz UX. Omawiam typowe problemy w oparciu o zasady i wskazówki specyfikacji Google Material Design - jednej z najbardziej szczegółowych specyfikacji UX. Wszystkie przykłady UI zarówno w wariantach desktopowych jak i mobilnych omówione są na przykładzie Angulara oraz obszernej biblioteki komponentów Angular Material. Zobaczysz nie tylko jak korzystając z gotowych komponentów błyskawicznie budować nowe funkcjonalności, ale przy okazji omówimy wiele praktycznych wskazówek oraz dobrych praktyk UX które warto wykorzystać w Twoich aplikacjach.
W ramach budowania interfejsów skupimy się na najmniejszych szczegółach takich jak prawidłowe zachowanie linków, przycisków oraz wskaźników przechodząc stopniowo do coraz większych elementów aplikacji takich jak nawigacja, układ strony, paski nawigacyjne czy okna dialogowe. Przy każdym etapie czeka Cię masa wskazówek, przykładów i rozwiązań typowych problemów user experience.
Jednak UX to nie tylko wygląd i zachowanie pojedynczych elementów. W ostatnich sekcjach kursu dowiesz się jak projektować bardziej złożone interakcje z użytkownikiem. Zobaczysz wieloetapowe formularze kreatora oraz dowiesz się jak zarządzać stanem aplikacji oraz różnymi źródłami danych. Pokaże Ci jak zbudować samodzielnie sortowane, filtrowane i stronicowane źródła danych oraz połączyć je z różnymi komponentami UI takimi jak listy czy datagrid.
Na koniec kursu zobaczysz jak możemy różne gotowe elementy UI połączyć w przepływ ekranów budując ścieżkę użytkownika. Zobaczysz jak prawidłowo zaprojektowane komponenty wraz z dobrze zaplanowanym UX pozwalają być niesamowicie produktywnym jednocześnie nie poświęcając jakości czy dobrej architektury aplikacji.
Jest to kurs dla osób które już pracowały z angularem i chciałyby wyjść poza pojedyncze techniki oraz poznać proces projektowania aplikacji w praktyce z uwzględnieniem najlepszych praktyk programistycznych oraz user experience. Zarówno w wariancie webowym jak i projektując pod urządzenia mobilne.
Angular 6, 7, 8+
W poprzedniej lekcji udało nam się utworzyć tutaj proste pole formularza i
przetestować zarówno przypisywanie tych wartości do formularza jak i
obsługę zdarzeń na tym formularzu gdy na przykład użytkownik wprowadzić jakieś zmiany wprowadzi
jakiś tekst jak jednak wiesz w aplikacjach bardziej rozbudowanych nie
przypisujemy wartości pojedynczo tak nie obsługujemy osobno
przypisania wartości w jedną stronę i obsługi zdarzenia w drugą tylko
skorzystamy z bardziej rozbudowanego mechanizmu do formularzy tak jak na przykład
ng model czyli jeśli tu values ją spróbuję użyć sobie ng model
i zamiast input zrobimy sobie ng model change
czyli zdarzenie które publikuje ng model i spróbuję zapisać takie coś pojawi się kilka
problemów pierwsza rzecz tutaj jak widzisz cannot read property debug
a jeszcze wcześniej tutaj cannot bind ng model ponieważ
nie jest to rozpoznana właściwości input jeśli korzystałeś wcześniej z angulara
no to wiesz dokładnie że to oznacza że mamy nie zaimportowany ng model i teraz
ng model ja bym mógł tutaj dodać do modułu app module do app module
aczkolwiek to by nazwę aplikacji w testach jak
pamiętasz mamy nasz tu specjalny model tutaj moduł testowy i jeśli
chcesz używać jakiś dyrektyw jakichś pluginów wtyczek czegoś spoza
naszego komponentu no to trzeba zadeklarować albo zaimportować tutaj czyli
żeby pierwszy błąd tu się go pozbyć tutaj tego błędu tu zrobimy sobie import forms
module i forms module zaimportujemy sobie
oczywiście z angular forms okej zapiszę
i zobaczmy teraz i powinno
być wszystko dobrze ale testy na to nie działają tutaj uruchomiło się całe
jakby nasz komponent komponenty się nam wyrenderował
aczkolwiek w wartość nie została zmieniona czyli tutaj nasza
wartość tutaj w tym polu input ona nie odpowiada tej wartości którą
ustawiliśmy w teście czyli ty wyszło który to jest test test task
list item should update task when input value change
czyli ten test się nie udał a zobaczmy troszkę wcześniej
mamy jakiegoś console loga i jak zobaczymy tutaj task
should show task name inside input także
się nie udał czyli oba te tutaj testy które zajmują się
inputem w momencie gdy przełączymy się na ng model powinien po prostu działać ale jednak
oba tutaj nie działają tutaj wartość nie jest w ogóle nawet przypisana i teraz
wynika to ze specjalnej funkcjonalności jaką ng model ng
model aktualizuje pola asynchronicznie czyli jeśli my przypisujemy wartość
do naszego model naszego komponentu w pierwszej fazie ng model
zaczytuje tą wartość weryfikuje waliduje tą wartość czy ona jest poprawna
dopiero jakby w drugiej fazie renderowania on tą wartość przypisuje do naszego inputa
i teraz musimy odpowiednio przerobić test żeby taką sytuację obsłużyć czyli
jeśli mamy tutaj nasz task name input nim
pobierzemy sobie wartość i sprawdzimy czy ona się zgadza to
musimy tutaj upewnić się że angular zakończył renderowanie
czyli fixture i tutaj jak pamiętasz były takie funkcje when
stable i when rendering done i tutaj when
stable jest o tyle ważne że widzisz musimy poczekać na zakończenie
się wszelkich asynchronicznych aktywności czyli za każdym razem
gdy na coś czekamy wykonujemy jakieś eventy wszystko dzieje
się asynchronicznie wszystko co nie dzieje się natychmiast tylko wymaga no
właśnie kolejnej kolejnego kroku asynchronicznego musimy
to wykonać poprzez when stable i when stable jak widzisz to jest funkcja która zwraca
nam promise czyli robimy sobibe then i dopiero
tutaj w tym then sprawdzimy czy oczekiwana wartość się zgadza
jak widzisz teraz jeden test się nie udał ja tutaj zrobię
f oznacza focus czyli sfocusuje się to jest na tym jednym teście czyli
jak widzisz nas też ten jeden test na pewno działa jeśli pominę pozostałe to tutaj wszystko jest
teraz spróbujmy to samo zrobić w drugim teście brakuje jednej
rzeczy żeby jak masz promisy pamiętaj żeby ten promise zawsze z testu zwrócić
żeby upewnić się że na pewno test o właśnie czy na
pewno test tutaj dokończył się czy test na
pewno poczekał na ten promise nim przejdzie dalej okej teraz
mamy renderowanie w inpucie musimy pamiętać zawsze żeby poczekać
aż ng model zaktualizuje input w drugą stronę to nie jest konieczne
a tylko że tutaj mamy na trigger event czyli samo wywołanie zdarzenia wywołuje
od razu przypisanie i tu tylko musimy się upewnić że przy ng modelu
nie przypisujemy tutaj event target value tylko tutaj po prostu eventem
jest już value czyli jak zrobię tutaj control s to drugi test
automatycznie tutaj działa bez zmian i w zasadzie mogę ng model skrócić i całą tą drugą część
po prostu tu elegancko zwinąć i jako
zapis tutaj jako dwustronne wiązanie ng model okej
w ten sposób zobaczymy i testy działają
czyli już w ten sposób możesz elegancko tutaj testować nawet
z ng model musisz pamiętać żeby wszędzie modelu poczekać ng model po
pierwsze się tej podepnie i dopiero w drugiej fazie przy drugim tutaj
sprawdzeniu zmian wprowadzi tutaj te zmiany jest jeszcze bardzo
fajna rzecz bo jeśli mamy tutaj ng model to tak naprawdę nie
musimy wyszukiwać tego po css można to zrobić trochę inaczej
mogę to zrobićby directive i
użyć po prostu ng model jako punktu
zaczepienia dla naszego tutaj inputa podobnie
zrobimy też na dole czyli wyszukam
go nie po css tylko po samym po samej klasie ng
model mogę znać to po klasie css tutaj lub po klasie
po typie komponentu on też tutaj je znajduje i
tutaj mogę dać też bardzo ciekawą rzecz że jeśli element
który tutaj znajdziemy jako debug element i jest komponentem lub
posiada przypiętą gdzieś jakąś dyrektywę to możemy też
dostać się do tej samej dyrektywy lub do komponentu który tutaj
mam w tym debug elemencie czyli tu mamy ng model to ja mogę nasz
input element żebym miał do tego kolejny test powiedzmy
że chciałbym sprawdzić tutaj z tamtego ng modelu powiedzmy
chciałbym zobaczyć czy jest on poprawny
czyli zrobimy sobie tutaj it should show
error message when task
name is empty na przykład czyli
chcemy wyświetlić komunikat błędu sprawdzić czy jest błąd i wyświetlić
komunikat błędu czyli powiedzmy że nasz tutaj ng model będzie required i
chciałem sprawdzić to teraz może to zrobić tak że w podobny sposób pobiorę sobie te
referencje do naszego input elementu i z tego input elementu
możemy wyciągnąć nasz ng model i
w ten sposób że tutaj jak sobie jak sobie poszukamy po tych wszystkich opcjach mamy jak widzisz injector
czyli mamy injector i mogę z nim zrobić get i wyciągnąć dowolny
token dependency injection czyli na przykład znaleźć sobie tutaj nasz ng model
który znajduje się na injectorze tego naszego elementu czyli
jeśli podejrzymy sobie tutaj zawartość tej zmiennej model to jak
zobaczysz mamy wszystkie właściwości tutaj tego naszego ng modelu możemy
zobaczyć czy jest touch untouched możemy pobrać sobie wartość na przykład
możemy pobrać też informacje na przykład czy jest on poprawny
i ja te dwie rzeczy może na początek wyświetlę czyli console log
wyświetlimy sobie wartość i wyświetlimy sobie stan czy jest on poprawny będziemy
chcieli sprawdzać czy jak zmienię właśnie jego wartość to czy jego stan będzie poprawny
i czy wyświetlił się error więc na chwilkę tutaj console log sobie sprawdzimy co tam się
dzieje wartość jest null i oczywiście jest
valid false czy jest niepoprawny czyli nasz required tutaj
spojrzę na model errors no
to zobaczymy jeszcze tutaj o właśnie required true czyli nam walidacja elegancko
zadziałała okej jednak test
tutaj wymaga żebyśmy sprawdzili czy istnieje komunikat błędu jeśli
właśnie taki błąd tutaj task is empty wystąpił czyli
tutaj utworzymy sobie zaraz komunikat błędu ale najpierw zaczniemy od testów czy sprawdźmy czy on
istnieje czyli const error
to będzie fixture ponownie debug element i
szukamy tym razem znowu po css dla
uproszczenia czyli css i poszukamy
sobie obiektu diva z klasy powiedzmy error na razie i
teraz expect i sprawdźmy czy on tutaj istnieje czyli expect error
i tu nie możemy zrobić to be defined dlatego że jeśli on nie znajdziesz
null tutaj będzie zdefiniowany więc zrobimy po prostu czy jest prawdziwy
to be truthy ewentualnie można by
spróbować not to be null
w ten sposób zobaczymy mamy
błąd że expected null not to be null okej
tu możemy sobie zrobić jeszcze message
element
not found zobaczmy teraz komunikat błędu error
message not found ok spróbujmy teraz czy yda nam się ten błąd tutaj naprawić
czyli dodamy sobie jakiegoś div'a powiedzmy field
cannot be empty i
dodamy jakiś ng if który to sprawdzi czyli jeśli
mamy tutaj exception to chcemy wyświetlić ten błąd który
tak samo jak mamy tutaj task name mamy referencje do tego elementu to
ja mogę przypisać do niego tutaj na przykład ng model i tutaj
wyciągnę sobie informację task name i sprawdzić
czy jest valid albo jeszcze lepiej dokładnie stwierdzić get error albo has
error i konkretny
błąd pobrać na przykład błąd tutaj required okej zobaczmy
teraz i oczywiście tego nie znajdzie bo szukam tej klasy
error a tu zapomniałem dodać klasy error oczywiście więc
nigdy nam by tego nie znalazł tutaj łatwo właśnie o tego typu błędy że szukamy
czegoś po prostu z literówką na przykład o mamy sukces czyli teraz mogę
pochować te console logi niepotrzebnie i zobaczmy
sukces udało się czyli jeśli powiedzmy ja bym tutaj wprowadził jakąś
wartość żeby był ng model set value set
wartość i powiedzmy
tutaj zrobiłbym detect changes czyli fixture detect
changes to pojawi nam się tutaj
elegancko że tu nie znalazł bo ng model sprawdził
tą wartość stwierdził że mamy tutaj poprawną wartość więc ukryje nam
ten komunikat tak czyli jak widzisz możemy sobie też dostać się do
różnych dyrektyw przypiętych w różnych miejscach manipulować ich zawartością
i sobie testować jak zmiana stanu tych dyrektyw jak komunikacja
z tymi dyrektywami wpływa nam na to co renderujemy na
nasz widok tutaj dodatkowo muszę jeszcze sprawdzić faktycznie expect
mogłem sprawdzić czy model faktycznie zawiera
ten stan czyli możemy też sprawdzić czy model powiedzmy
valid to be no
właśnie falsy jest
okej także sprawdzamy czy już na pewno coś znajdowało i sprawdzamy czy faktycznie w
wyniku tej walidacji pojawi nam się element jeszcze warto się zmienia my chcemy coś innego
wyrenderować pamiętaj też żeby ten fixture detect changes no i oczywiście pamiętaj
żeby te tutaj właśnie klasy żeby te nazwy się zgadzały żebyśmy na próżno
nie szukali czegoś tylko dlatego że po prostu gdzieś tam jest literówka na przykład i
nie możemy tego znaleźć okej to tyle jeśli chodzi właśnie
o takie testowanie widoku renderowania o testowanie danych
które pokazujemy na ekranie eventu które pobieramy i nieco
bardziej skomplikowane rzeczy na przykład interakcja z dyrektywami z jakimś asynchronicznym
kodem w kolejnych lekcjach zajmiemy się testowaniem już warstwy
logiki aplikacji powiemy sobie o usługach strumienia i tak dalej no ale tu
właśnie już w kolejnych lekcjach tak więc do zobaczenia