Dezvoltarea prin test este o practică de programare care a fost propovăduită și promovată de fiecare comunitate de dezvoltatori de pe planetă. Și totuși este o rutină care este în mare parte neglijată de un dezvoltator în timp ce învață un nou cadru. Scrierea testelor de unitate din prima zi vă va ajuta să scrieți mai bine coduri, să identificați bug-uri cu ușurință și să mențineți un flux de lucru mai bun.
Angular, fiind o platformă completă de dezvoltare front-end, are un set propriu de instrumente pentru testare. Vom folosi următoarele instrumente în acest tutorial:
('ar trebui să aibă o componentă definită', () => expect (component) .toBeDefined (););
brazerul
și ComponentFixtures
și funcții auxiliare, cum ar fi async
și fakeAsync
fac parte din @ Unghiular / core / testare
pachet. Familiarizarea cu aceste utilitare este necesară dacă doriți să scrieți teste care arată modul în care componentele dvs. interacționează cu propriul șablon, servicii și alte componente.Nu vom acoperi testele funcționale folosind Protractor în acest tutorial. Protractorul este un cadru popular de testare end-to-end care interacționează cu interfața aplicației folosind un browser real.
În acest tutorial, suntem mai preocupați de testarea componentelor și a logicii componentei. Cu toate acestea, vom scrie câteva teste care demonstrează interacțiunea de bază UI utilizând cadrul Jasmine.
Scopul acestui tutorial este de a crea front-end pentru o aplicație Pastebin într-un mediu de dezvoltare bazat pe test. În acest tutorial, vom urmări mantra populară TDD, care este "roșu / verde / refactor". Vom scrie teste care nu reușesc inițial (roșu) și apoi să lucreze la codul nostru de aplicare pentru a le face să treacă (verde). Ne vom refactoriza codul cand va incepe sa pacaleasca, ceea ce inseamna ca acesta devine umflat si urat.
Vom scrie teste pentru componente, șabloane, servicii și clasa Pastebin. Imaginea de mai jos ilustrează structura aplicației noastre Pastebin. Elementele care sunt goale vor fi discutate în a doua parte a tutorialului.
În prima parte a seriei, ne vom concentra doar pe stabilirea mediului de testare și scrierea testelor de bază pentru componente. Angular este un cadru bazat pe componente; prin urmare, este o idee bună să petreceți ceva timp familiarizându-vă cu testele de scris pentru componente. În a doua parte a seriei, vom scrie teste mai complexe pentru componente, componente cu intrări, componente rulate și servicii. Până la sfârșitul seriei, vom avea o aplicație Pastebin pe deplin funcțională care arată astfel.
Vizualizarea componentei PastebinVizualizarea componentei AddPasteÎn acest tutorial, veți învăța cum să:
Întregul cod al tutorialului este disponibil pe Github.
https://github.com/blizzerand/pastebin-angular
Clonați repo și nu ezitați să verificați codul dacă sunteți îndoieli în orice stadiu al acestui tutorial. Să începem!
Dezvoltatorii de la Angular ne-au facilitat configurarea mediului nostru de testare. Pentru a începe, trebuie să instalați mai întâi Angular. Prefer sa folosesc CLI-ul Angular. Este o soluție all-in-one care se ocupă de crearea, generarea, construirea și testarea proiectului dvs. Angular.
noului Pastebin
Aici este structura directorului creată de Angular-CLI.
Întrucât interesele noastre sunt mai înclinate spre aspectele de testare din Angular, trebuie să ne uităm la două tipuri de fișiere.
karma.conf.js este fișierul de configurație pentru testul de testare Karma și singurul fișier de configurare pe care îl vom avea nevoie pentru scrierea testelor de unitate în Angular. În mod implicit, Chrome este lansatorul implicit de browser folosit de Karma pentru a capta teste. Vom crea un lansator personalizat pentru rularea Chrome fără cap și adăugați-l la browsere
mulțime.
/*karma.conf.js*/ browsere: ['Chrome', 'ChromeNoSandboxHeadless'], customLaunchers: ChromeNoSandboxHeadless: base: 'Chrome', steaguri: ['--no-sandbox', // Vezi https: / /chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md '--headless', '--disable-gpu', // Fără un port de depanare la distanță, Google Chrome iese imediat. '--remote-debugging-port = 9222',],,,
Celălalt tip de fișier la care trebuie să ne uităm este tot ce se termină .spec.ts
. Prin convenție, testele scrise în Jasmine sunt numite specificații. Toate specificațiile de test ar trebui să fie localizate în interiorul aplicației src / app /
directorul pentru că acolo unde Karma caută specificațiile de testare. Dacă creați o componentă nouă sau un serviciu, este important să plasați specificațiile de test în interiorul aceluiași director pe care se află codul pentru componentă sau serviciu.
ng nou
comandă a creat un app.component.spec.ts
fișier pentru noi app.component.ts
. Simțiți-vă liber să o deschideți și să aruncați o privire la testele Jasmine din Angular. Chiar dacă codul nu are sens, este bine. Vom păstra AppComponent așa cum este pentru moment și îl vom folosi pentru a găzdui rutele la un moment dat mai târziu în tutorial.
Avem nevoie de o clasă Pastebin pentru a modela Pastebin în interiorul componentelor și testelor. Puteți crea unul folosind CLI-ul Angular.
ng genera clasa Pastebin
Adăugați următoarea logică în Pastebin.ts:
clasa de export Pastebin id: number; titlu: șir; limbă: șir; pastă: șir; constructor (valori: Object = ) Object.assign (aceasta, valori); export const Limbi = ["Ruby", "Java", "JavaScript", "C", "Cpp"];
Am definit o clasă Pastebin și fiecare instanță din această clasă va avea următoarele proprietăți:
id
titlu
limba
pastă
Creați un alt fișier numit pastebin.spec.ts
pentru suita de testare.
/ * pastebin.spec.ts * / // importați importul de clasă Pastebin Pastebin din "./pastebin"; descrie ('Pastebin', () => it ('ar trebui să creeze o instanță a lui Pastebin', () => așteptați (new Pastebin ()) toBeTruthy;
Suita de testare începe cu a descrie
bloc, care este o funcție globală Jasmine care acceptă doi parametri. Primul parametru este titlul suitei de testare, iar al doilea este implementarea reală. Specificațiile se definesc folosind un aceasta
funcția care are doi parametri, similară cu cea a lui descrie
bloc.
Specificații multiple (aceasta
blocuri) pot fi imbricate într-o suită de testare (descrie
bloc). Cu toate acestea, asigurați-vă că titlurile suitelor de testare sunt denumite astfel încât acestea să fie lipsite de ambiguitate și mai ușor de citit, deoarece acestea sunt menite să servească drept documentație pentru cititor.
Așteptări, implementate utilizând aştepta
funcția, sunt utilizate de Jasmine pentru a determina dacă o spec. ar trebui să treacă sau să nu reușească. aştepta
funcția are un parametru care este cunoscut ca valoarea reală. Acesta este apoi legat cu o altă funcție care ia valoarea așteptată. Aceste funcții sunt numite funcții matcher, iar noi vom folosi funcțiile de matcher cum ar fi toBeTruthy ()
, să fie definit()
, a fi()
, și a conține()
o mulțime în acest tutorial.
așteptați (noul Pastebin ()) toBeTruthy ();
Cu acest cod, am creat o nouă instanță a clasei Pastebin și așteptăm ca aceasta să fie adevărată. Să adăugăm încă o spec. Pentru a confirma că modelul Pastebin funcționează conform destinației.
el ("ar trebui să accepte valori", () => let pastebin = new Pastebin (); pastebin = id: 111, title: "Hello world" așteptați (pastebin.id) .toEqual (111); așteptați (pastebin.language) .toEqual ("Ruby"); așteptați (pastebin.paste) .toEqual ("print" Hello "');
Am instanțiat clasa Pastebin și am adăugat câteva așteptări spec. Alerga ng test
pentru a verifica dacă toate testele sunt verde.
Generați un serviciu utilizând comanda de mai jos.
ng genera servicii pastebin
PastebinService
va găzdui logica pentru trimiterea cererilor HTTP către server; cu toate acestea, nu avem un server API pentru aplicația pe care o construim. Prin urmare, vom simula comunicarea server folosind un modul cunoscut ca InMemoryWebApiModule.
Instalare unghiular-in-memory-web-api
prin npm:
npm instalați unghiul în memorie-web-api - salvați
Actualizați AppModule cu această versiune.
/ * app.module.ts * / import BrowserModule din '@ unghiular / platform-browser'; import NgModule de la '@ angular / core'; // Importul componentelor AppComponent din "./app.component"; // Serviciul pentru importul Pastebin PastebinService de la "./pastebin.service"; // Modulele utilizate în acest tutorial import HttpModule de la '@ angular / http'; // În memoria Web api pentru a simula un import de server http (InMemoryWebApiModule) din 'angular-in-memory-web-api'; import InMemoryDataService de la "./in-memory-data.service"; @NgModule (declarații: [AppComponent,], importă: [BrowserModule, HttpModule, InMemoryWebApiModule.forRoot (InMemoryDataService)], furnizori: [PastebinService], bootstrap: [AppComponent]
Creaza un InMemoryDataService
care implementează InMemoryDbService
.
/*in-memory-data.service.ts*/ import InMemoryDbService din "angular-in-memory-web-api"; import Pastebin din "./pastebin"; clasa de export InMemoryDataService implementează InMemoryDbService createDb () const pastebin: Pastebin [] = [id: 0, title: "Hello world Ruby", limbă: "Ruby" : 1, titlu: "Hello world C", limbă: "C", paste: "printf (" Hello world "); id: 2, title:" Hello world CPP "; pastă: "cout<<"Hello world";', id: 3, title: "Hello world Javascript", language: "JavaScript", paste: 'console.log("Hello world")' ]; return pastebin;
Aici, pastebin
este o serie de paste de probă care vor fi returnate sau actualizate când vom efectua o acțiune HTTP cum ar fi http.get
sau http.post
.
/*pastebin.service.ts * / import Injectable de la '@ angular / core'; import Pastebin din "./pastebin"; import Http, Headers de la '@ angular / http'; importați "rxjs / add / operator / toPromise"; @ Injectable () clasa de export PastebinService // Proiectul folosește InMemoryWebApi pentru a gestiona serverul API. // Aici "api / pastebin" simulează un server API url private pastebinUrl = "api / pastebin"; anteturi private = titluri noi ('Content-Type': "application / json"); constructor (private http: Http) // getPastebin () efectuează http.get () și returnează un promisiune publică getPastebin (): Promisereturn this.http.get (this.pastebinUrl) .toPromise () .then (răspuns => răspuns.json (). data) .catch (this.handleError); handleError privat (eroare: orice): Promise console.error ('A apărut o eroare', eroare); returnați Promise.reject (error.message || error);
getPastebin ()
metoda face o cerere HTTP.get și returnează o promisiune care rezolvă o matrice de obiecte Pastebin returnate de server.
Dacă primești a Niciun furnizor pentru HTTP eroare în timp ce executați o spec., trebuie să importați HTTPModule în fișierul spec.
Componentele reprezintă cel mai elementar element de construcție al unui interfață utilizator într-o aplicație Angulară. O aplicație unghiulară este un arbore al componentelor unghiulare.
- Documentație unghiulară
Așa cum am subliniat mai devreme în secțiunea Prezentare generală, vom lucra la două componente în acest tutorial: PastebinComponent
și AddPasteComponent
. Componenta Pastebin constă într-o structură de tabelă care listează toată pasta preluată de la server. Componenta AddPaste deține logica pentru crearea de noi paste.
Continuați și generați componentele utilizând funcția Angular-CLI.
ng component g --spec = fals Pastebin
--spec = false
opțiune spune CLI-ului Angular să nu creeze un fișier spec. Acest lucru se datorează faptului că vrem să scriem teste unitare pentru componente de la zero. Creeaza o pastebin.component.spec.ts
fișier în interiorul pastebin-component pliant.
Iată codul pentru pastebin.component.spec.ts
.
import TestBed, ComponentFixture, async de la '@ angular / core / testing'; importați DebugElement de la '@ angular / core'; import PastebinComponent din "./pastebin.component"; import By din '@ unghiular / platform-browser'; import Pastebin, Limbi de la "... / pastebin"; // Module utilizate pentru testarea importului HttpModule de la '@ angular / http'; descrie ('PastebinComponent', () => // Declarații tipescript. permite comp: PastebinComponent;; permiteți: DebugElement; să element: HTMLElement; lăsați mockPaste: Pastebin []; // beforeEach este chemat o dată înainte de fiecare blocare într-un test. // Folosiți acest lucru pentru a configura componenta, pentru a injecta servicii etc. înainteEach () => TestBed.configureTestingModule (declarații: [PastebinComponent], // declarați importul componentelor de test: [HttpModule],; fixture = TestBed .createComponent (PastebinComponent); comp = fixture.componentInstance; de = fixture.debugElement.query (By.css ("pastebin"); element = de.nativeElement;); )
Se întâmplă multe aici. Să ne despărțim și să luăm o singură bucată odată. În cadrul descrie
bloc, am declarat câteva variabile și apoi am folosit a beforeEach
funcţie. beforeEach ()
este o funcție globală furnizată de Jasmine și, așa cum sugerează și numele, este invocată o singură dată înainte de fiecare spec descrie
bloc în care este numit.
TestBed.configureTestingModule (declarații: [PastebinComponent], // declarați importurile componentelor testului: [HttpModule],);
brazerul
clasa este o parte din utilitarele de testare Angular, și creează un modul de testare similar cu cel al @NgModule
clasă. Mai mult, puteți configura brazerul
folosind configureTestingModule
metodă. De exemplu, puteți crea un mediu de testare pentru proiectul dvs. care emulează aplicația Angulară reală și puteți trage apoi o componentă din modulul dvs. de aplicație și o puteți atașa din nou la acest modul de testare.
fișier = TestBed.createComponent (PastebinComponent); comp = fixture.componentInstance; de = fixture.debugElement.query (By.css ("div")); element = de.nativeElement;
Din documentația Angular:
createComponent
metoda returnează aComponentFixture
, un mâner pe mediul de testare care înconjoară componenta creată. Elementul de fixare oferă acces la instanța componentă în sine și laDebugElement
, care este un mâner pe elementul DOM al componentei.
Așa cum am menționat mai sus, am creat un dispozitiv de PastebinComponent
și apoi a folosit acel dispozitiv pentru a crea o instanță a componentei. Acum putem accesa proprietățile și metodele componentei în cadrul testelor noastre, sunând comp.property_name
. Deoarece dispozitivul de fixare oferă, de asemenea, acces la debugElement
, acum putem interoga elementele DOM și selectorii.
Există o problemă cu codul nostru, despre care nu ne-am gândit încă. Componenta noastră are un șablon extern și un fișier CSS. Preluarea și citirea acestora din sistemul de fișiere este o activitate asincronă, spre deosebire de restul codului, care este tot sincron.
Angular vă oferă o funcție numită async ()
care are grijă de toate lucrurile asincrone. Ce asincronă este să țineți evidența tuturor sarcinilor asincrone din interiorul acestuia, ascunzând complexitatea executării asincrone de la noi. Așa că acum vom avea două funcții înainte de fiecare, o asincronă beforeEach ()
și un sincron beforeEach ()
.
/ * pastebin.component.spec.ts * / // beforeEach este numit o dată înaintea fiecărui bloc "într-un test". / / // async înainte este folosit pentru compilarea de șabloane externe care este orice activitate de asincronizare TestBed.configureTestingModule (declarations: [PastebinComponent], / / declararea importurilor componentelor de testare: [HttpModule],) .compileComponents (); // compilați șablon și css)); beforeEach (() => // Și aici este setarea funcției sincrone async = TestBed.createComponent (PastebinComponent); fi = fixture.debugElement.query (By.css ('. pastebin')); element = de.nativeElement;);
Nu am scris încă niciun test. Cu toate acestea, este o idee bună să creați în prealabil o schiță a specificațiilor. Imaginea de mai jos descrie un design dur al componentei Pastebin.
Trebuie să scriem teste cu următoarele așteptări.
pastebinService
este injectat în componentă, iar metodele sale sunt accesibile.onInit ()
se numește.Primele trei teste sunt ușor de implementat.
el ('ar trebui să aibă o componentă', () => expect (comp) .toBeTruthy ();); ("ar trebui să aibă un titlu", () => comp.title = 'Aplicație Pastebin'; fixture.detectChanges (); așteptați (element.textContent) .toContain (comp.title); un tabel pentru afișarea pastelor ', () => așteptați (element.innerHTML) .toContain ("thead"); așteptați (element.innerHTML) .toContain ("tbody");)
Într-un mediu de testare, Angular nu leagă automat proprietățile componentei cu elementele șablonului. Trebuie să sunați în mod explicit fixture.detectChanges ()
de fiecare dată când doriți să legați o proprietate a componentei cu șablonul. Executarea testului ar trebui să vă ofere o eroare deoarece nu am declarat încă proprietatea titlului în componenta noastră.
titlu: string = "Aplicație Pastebin";
Nu uitați să actualizați șablonul cu o structură de tabelă de bază.
titlu
id Titlu Limba Cod
În ceea ce privește restul cazurilor, trebuie să injectăm Pastebinservice
și de a scrie teste care se ocupă de interacțiunea component-serviciu. Un serviciu real ar putea efectua apeluri către un server de la distanță și injectarea acestuia în formă brută va fi o sarcină laborioasă și provocatoare.
În schimb, ar trebui să scriem teste care se concentrează asupra faptului dacă componenta interacționează cu serviciul conform așteptărilor. Vom adăuga specificații care spionează pe pastebinService
si este getPastebin ()
metodă.
Mai întâi, importă PastebinService
în suita noastră de testare.
import PastebinService de la "... /pastebin.service";
Apoi, adăugați-l la furnizorii de
array inside TestBed.configureTestingModule ()
.
TestBed.configureTestingModule (declarații: [CreateSnippetComponent], furnizori: [PastebinService],);
Codul de mai jos creează un spion Jasmine care este proiectat pentru a urmări toate apelurile către getPastebin ()
și a reveni la o promisiune pe care o rezolvă imediat mockPaste
.
// PastebinService real este injectat în componentă let pastebinService = fixture.debugElement.injector.get (PastebinService); mockPaste = [id: 1, titlu: "Hello world", limba: "Ruby", pastă: "pune" Hello ""; spy = spyOn (pastebinService, 'getPastebin') și.returnValue (Promise.resolve (mockPaste));
Spionul nu este preocupat de detaliile de implementare ale serviciului real, ci în schimb, ocolește orice apel la real getPastebin ()
metodă. În plus, toate apelurile la distanță îngropate înăuntru getPastebin ()
sunt ignorate de testele noastre. Vom scrie unități de testare izolate pentru serviciile unghiulare în a doua parte a tutorialului.
Adăugați următoarele teste la pastebin.component.spec.ts
.
("nu ar trebui să arate pastebin înainte de OnInit", () => this.tbody = element.querySelector ("tbody"); // Încercați acest lucru fără metoda "replace (\ s \ / + g,") și a vedea ce se întâmplă să se aștepte (this.tbody.innerText.replace (/ \ s \ s + / g, ")) toBe (" ", tbody trebuie să fie gol"); toBe (false, "Spionul nu ar trebui să fie încă numit");); ("nu ar trebui să afișeze în continuare pastebin după inițializarea componentei", () => fixture.detectChanges (); // serviciul getPastebin este async, dar testul nu este așteptați (this.tbody.innerText.replace (/ \ s \ to + e (), toBe ("", tbody ar trebui să fie în continuare gol)), așteptați (spy.calls.any ()). ("ar trebui să arate pastebin după ce promisiunea getPastebin rezolvă", async () => fixture.detectChanges (); fixture.whenStable (), apoi (() => fixture.detectChanges (); toEqual (iasmine.objectContaining (mockPaste)); așteptați (element.innerText.replace (/ \ s \ s + / g, ")) toContain (mockPaste [0] .title;
Primele două teste sunt teste sincrone. Prima spec. Verifică dacă innerText
din div
element rămâne gol, atâta timp cât componenta nu este inițializată. Al doilea argument pentru funcția Matcher a lui Jasmine este opțional și este afișat atunci când testul eșuează. Acest lucru este util atunci când aveți mai multe declarații de așteptare în interiorul unui spec.
În cea de-a doua spec., Componenta este inițializată (deoarece fixture.detectChanges ()
este numit), iar spionul este, de asemenea, de așteptat să fie invocat, dar șablonul nu ar trebui să fie actualizat. Chiar dacă spionul întoarce o promisiune rezolvată, mockPaste
nu este încă disponibil. Acesta nu ar trebui să fie disponibil decât dacă testul este un test asincron.
Cel de-al treilea test folosește o async ()
funcția discutată mai devreme pentru a executa testul într-o zonă de testare asincronă. async ()
este folosit pentru a face un test sincron asincron. fixture.whenStable ()
este numit atunci când toate activitățile asincrone în așteptare sunt completate, și apoi oa doua rundă de fixture.detectChanges ()
este chemat să actualizeze DOM cu noile valori. Așteptările în testul final asigură că DOM-ul nostru este actualizat cu mockPaste
valorile.
Pentru ca încercările să treacă, trebuie să ne actualizăm pastebin.component.ts
cu următorul cod.
/*pastebin.component.ts*/ import Component, OnInit din '@ angular / core'; import Pastebin de la "... / pastebin"; import PastebinService de la "... /pastebin.service"; @Component (selector: 'app-pastebin', templateUrl: './pastebin.component.html', styleUrls: ['./pastebin.component.css']) clasa de export PastebinComponent implementează OnInit title: Aplicație Pastebin "; pastebin: orice = []; constructor (public pastebinServ: PastebinService) // loadPastebin () este apelat pe init ngOnInit () this.loadPastebin (); public loadPastebin () // invocă metoda getPastebin () a serviciului pastebin și stochează răspunsul în proprietatea "pastebin" this.pastebinServ.getPastebin (), apoi (pastebin => this.pastebin = pastebin);
Șablonul trebuie, de asemenea, să fie actualizat.
titlu
id Titlu Limba Cod Paste.id Paste.title Paste.language Vizualizați codul
Generați o componentă AddPaste utilizând funcția Angular-CLI. Imaginea de mai jos descrie designul componentei AddPaste.
Logica componentei ar trebui să treacă următoarele specificații.
showModal
proprietate la Adevărat
. (showModal
este o proprietate booleană care devine adevărată atunci când modalitatea este afișată și falsă când modalul este închis.)addPaste ()
metodă.showModal
proprietate la fals
.Am elaborat primele trei teste pentru tine. Vedeți dacă puteți efectua testele pe cont propriu.
descrie ('AddPasteComponent', () => lăsați componenta: AddPasteComponent; fixați-o: ComponentFixture; permiteți: DebugElement; să element: HTMLElement; lăsați spion: jasmine.Spy; lasati pastebinService: PastebinService; înainte de orice (async (() => TestBed.configureTestingModule (declarations: [AddPasteComponent], importă: [HttpModule, FormsModule], furnizori: [PastebinService],) .compileComponents (); înainteEach () => initialization fixture = TestBed.createComponent (AddPasteComponent); pastebinService = fixture.debugElement.injector.get (PastebinService); component = fixture.componentInstance; de = fixture.debugElement.query (By.css ( 'add-paste'); element = de.nativeElement; spy = spyOn (pastebinService, 'addPaste') și.callThrough (); // solicitați fixarea pentru a detecta modificările fixture.detectChanges ();); it ('ar trebui să fie creat', () => expect (component) .toBeTruthy ();); ("ar trebui să afișeze butonul" crea Paste "', () => // ar trebui să apară un buton de creare în șablon (element.innerText) .toContain (" create Paste ");); ("nu ar trebui să afișeze modalul decât dacă butonul este apăsat", () => // modelul-sursă este un id pentru modal. Nu ar trebui să apară decât dacă faceți clic pe butonul de creare (element.innerHTML). nu "tocontain (" source-modal ");) (" ar trebui să afișeze modal atunci când se face clic pe "create paste" )); // triggerEventHandler simulează un eveniment clic pe butonul obiect createPasteButton.triggerEventHandler ("click", null); fixture.detectChanges (); așteptați (element.innerHTML) .toContain ("source-modal" .showModal) .toBeTruthy ("showModal ar trebui să fie adevărat");))
DebugElement.triggerEventHandler ()
este singurul lucru nou aici. Acesta este folosit pentru a declanșa un eveniment clic pe elementul buton pe care este apelat. Al doilea parametru este obiectul evenimentului și l-am lăsat gol din componența acestuia clic()
nu se așteaptă pe cineva.
Asta e pentru a doua zi. În acest prim articol am învățat:
În tutorialul următor, vom crea noi componente, vom scrie mai multe componente de teste cu intrări și ieșiri, servicii și rute. Rămâneți acordat pentru a doua parte a seriei. Împărtășiți-vă gândurile prin comentariile.