Dies ist eine umfassende Anleitung zur Bereitstellung von Zuverlässigkeit in JavaScript und Node.js. Hier werden Dutzende der besten Beiträge, Bücher und Tools gesammelt.
Behandeln Sie zunächst allgemein anerkannte Testmethoden, die jeder Anwendung zugrunde liegen. Und dann können Sie sich mit dem Bereich befassen, der Sie interessiert: Frontend und Schnittstellen, Backend, CI oder alle oben genannten Bereiche.
Inhalt
Abschnitt 0. Goldene Regel
0. Goldene Regel: Halten Sie sich an Lean Testing
Was soll ich tun. Der Testcode unterscheidet sich von dem, was in Betrieb genommen wird. Machen Sie es so einfach wie möglich, kurz, frei von Abstraktionen, einzeln, wunderbar bei der Arbeit und sparsam. Eine andere Person sollte sich den Test ansehen und sofort verstehen, was sie tut.
Unsere Köpfe sind mit dem Produktionscode beschäftigt, sie haben keinen freien Speicherplatz für zusätzliche Komplexität. Wenn wir einen neuen Teil des komplexen Codes in unseren armen Verstand schieben, verlangsamt dies die Arbeit des gesamten Teams an der Aufgabe, für die wir testen. Aus diesem Grund meiden viele Teams Tests einfach.
Tests - dies ist eine Gelegenheit, einen freundlichen und lächelnden Assistenten zu finden, mit dem es sehr gut zu arbeiten ist und der eine enorme Rendite für kleine Investitionen bringt. Wissenschaftler glauben, dass es in unserem Gehirn zwei Systeme gibt: eines für Aktionen, die keine Anstrengung erfordern, wie das Fahren auf einer leeren Straße, und das zweite für komplexe Operationen, die Bewusstsein erfordern, wie das Lösen mathematischer Gleichungen. Erstellen Sie Ihre Tests für das erste System, damit Sie beim Betrachten des Codes ein Gefühl der Einfachheit erhalten, das mit dem Bearbeiten eines HTML-Dokuments vergleichbar ist, und nicht mit einer
2X(17 × 24)
Lösung
2X(17 × 24)
.
Dies kann durch sorgfältige Auswahl von Methoden, Werkzeugen und Testzielen erreicht werden, so dass diese wirtschaftlich sind und einen hohen ROI erzielen. Testen Sie nur so viel wie nötig, versuchen Sie flexibel zu sein. Manchmal lohnt es sich sogar, einige Tests zu verwerfen und die Zuverlässigkeit für Geschwindigkeit und Einfachheit zu opfern.

Die meisten der folgenden Empfehlungen leiten sich aus diesem Prinzip ab.
Bist du bereitAbschnitt 1. Anatomie des Tests
1.1 Der Name jeder Prüfung sollte aus drei Teilen bestehen
Was soll ich tun. Aus dem Testbericht sollte hervorgehen, ob die aktuelle Version der Anwendung den Anforderungen derjenigen Personen entspricht, die mit dem Code nicht vertraut sind: Tester, die an der Bereitstellung von DevOps-Ingenieuren beteiligt sind, sowie Sie selbst in zwei Jahren. Es ist am besten, wenn die Tests Informationen in der Sprache der Anforderungen melden und ihre Namen aus drei Teilen bestehen:
- Was genau wird getestet? Zum Beispiel die
ProductsService.addNewProduct
Methode. - Unter welchen Bedingungen und Szenarien? Beispielsweise wird der Preis nicht an die Methode übergeben.
- Was ist das erwartete Ergebnis? Beispielsweise wird ein neues Produkt nicht genehmigt.
Sonst. Die Bereitstellung schlägt fehl, der Test mit dem Namen "Produkt hinzufügen" schlägt fehl. Verstehst du was genau falsch funktioniert?
Hinweis Jedes Kapitel enthält einen Beispielcode und manchmal eine Abbildung. Siehe Spoiler.
CodebeispieleWie man es richtig macht. Der Name des Tests besteht aus drei Teilen.
1.2 Strukturieren Sie die Tests nach dem AAA-Muster
Was soll ich tun. Jeder Test sollte aus drei klar getrennten Abschnitten bestehen: Anordnen (Vorbereitung), Handeln (Aktion) und Bestätigen (Ergebnis). Das Festhalten an einer solchen Struktur stellt sicher, dass der Leser Ihres Codes nicht den Gehirnprozessor verwenden muss, um den Testplan zu verstehen:
Anordnen: Der gesamte Code, der das System gemäß dem Testszenario in einen Zustand versetzt. Dies kann das Erstellen einer Instanz des Moduls im Testdesigner, das Hinzufügen von Datensätzen zur Datenbank, das Erstellen von Stubs anstelle von Objekten und anderen Code umfassen, der das System auf den Testlauf vorbereitet.
Act: Codeausführung als Teil eines Tests. Normalerweise nur eine Zeile.
Behauptung: Stellen Sie sicher, dass der erzielte Wert den Erwartungen entspricht. Normalerweise nur eine Zeile.
Sonst. Sie werden nicht nur viele Stunden mit dem Hauptcode arbeiten, sondern Ihr Gehirn wird auch von dem anschwellen, was ein einfacher Job sein sollte - vom Testen.
CodebeispieleWie man es richtig macht. Ein nach dem AAA-Muster strukturierter Test.
describe.skip('Customer classifier', () => { test('When customer spent more than 500$, should be classified as premium', () => {
Ein Beispiel für Antimuster. Keine Trennung in einem Stück ist schwieriger zu interpretieren.
test('Should be classified as premium', () => { const customerToClassify = {spent:505, joined: new Date(), id:1} const DBStub = sinon.stub(dataAccess, "getCustomer") .reply({id:1, classification: 'regular'}); const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); expect(receivedClassification).toMatch('premium'); });
1.3 Beschreiben Sie die Erwartungen in der Sprache des Produkts: Geben Sie im Stil von BDD an
Was soll ich tun. Das Programmieren von Tests in einem deklarativen Stil ermöglicht es dem Benutzer, die Essenz sofort zu verstehen, ohne einen einzelnen Gehirnprozessorzyklus zu verbringen. Wenn Sie imperativen Code schreiben, der in bedingte Logik gepackt ist, muss der Leser viel Aufwand betreiben. Unter diesem Gesichtspunkt müssen Sie Erwartungen in einer menschenähnlichen Sprache in einem deklarativen BDD-Stil beschreiben, indem Sie erwarten / sollten und keinen benutzerdefinierten Code verwenden. Wenn es in Chai und Jest keine notwendige Behauptung gibt, die oft wiederholt wird, können Sie
den Matcher Jest erweitern oder
Ihr eigenes Plugin für Chai schreiben.
Sonst. Das Team wird weniger Tests schreiben und nervige Tests
with .skip()
dekorieren.
CodebeispieleEin Beispiel mit Mokka .
Ein Beispiel für Antimuster. Um das Wesentliche des Tests zu verstehen, muss der Benutzer einen ziemlich langen imperativen Code durchlaufen.
it("When asking for an admin, ensure only ordered admins in results" , ()={
Wie man es richtig macht. Das Lesen dieses deklarativen Tests ist unkompliziert.
it("When asking for an admin, ensure only ordered admins in results" , ()={
1.4 Black-Box-Tests einhalten: Testen Sie nur öffentliche Methoden
Was soll ich tun. Das Testen der Innenseiten führt zu einem enormen Overhead und bringt fast nichts. Wenn Ihr Code oder Ihre API die richtigen Ergebnisse liefert, lohnt es sich, drei Stunden lang zu testen, wie es intern funktioniert, und dann auch diese fragilen Tests zu unterstützen? Wenn Sie das öffentliche Verhalten überprüfen, überprüfen Sie gleichzeitig implizit die Implementierung selbst. Ihre Tests schlagen nur fehl, wenn ein bestimmtes Problem vorliegt (z. B. falsche Ausgabe). Dieser Ansatz wird auch als Verhaltenstest bezeichnet. Wenn Sie dagegen die Interna testen (die „White-Box“ -Methode), konzentrieren Sie sich statt der Planung der Ausgabe der Komponenten auf kleine Details, und Ihre Tests können aufgrund kleiner Änderungen des Codes unterbrochen werden, auch wenn die Ergebnisse in Ordnung sind Eskorte wird viel mehr Ressourcen in Anspruch nehmen.
Sonst. Ihre Tests werden sich wie ein
Junge verhalten
, der "Wolf!" : Falsch positive Ergebnisse melden (z. B. schlägt der Test aufgrund einer Änderung des Namens einer privaten Variablen fehl). Es ist nicht verwunderlich, dass die Leute bald anfangen werden, CI-Benachrichtigungen zu ignorieren, und eines Tages werden sie einen echten Fehler verpassen ...
CodebeispieleEin Beispiel für Antimuster. Testen der Innenseiten ohne guten Grund.
Ein Beispiel mit Mokka .
class ProductService{
1.5 Wählen Sie die richtige simulierte Implementierung: Vermeiden Sie gefälschte Objekte zugunsten von Stubs und Spionen
Was soll ich tun. Simulierte Implementierungen (Test-Doubles) sind ein notwendiges Übel, da sie mit den Interna der Anwendung verknüpft sind und einige von großem Wert sind (
aktualisieren Sie den Speicher nachgeahmter Implementierungen: gefälschte Objekte (Mocks), Stubs (Stubs) und Spionageobjekte (Spione) ) Es sind jedoch nicht alle Techniken gleichwertig. Spione und Stummel wurden entwickelt, um Anforderungen zu testen, haben jedoch unvermeidliche Nebenwirkungen - sie wirken sich auch geringfügig auf das Innere aus. Und gefälschte Objekte dienen zum Testen der Innenseiten, was zu einem enormen Overhead führt, wie in Kapitel 1.4 beschrieben.
Stellen Sie sich vor der Verwendung simulierter Implementierungen die einfachste Frage: "Verwenden Sie diese Option, um die Funktionalität zu testen, die in der Dokumentation mit den Anforderungen angezeigt wurde oder möglicherweise angezeigt wird." Wenn nicht, riecht es nach White-Box-Tests.
Wenn Sie beispielsweise herausfinden möchten, ob sich die Anwendung ordnungsgemäß verhält, wenn der Zahlungsdienst nicht verfügbar ist, können Sie stattdessen einen Stub erstellen und "Keine Antwort" zurückgeben, um zu überprüfen, ob das zu testende Modul den richtigen Wert zurückgibt. So können Sie unter bestimmten Szenarien das Verhalten / die Reaktion / die Ausgabe der Anwendung überprüfen. Sie können auch mit Hilfe eines Spions bestätigen, dass der Brief gesendet wurde, wenn der Dienst nicht verfügbar war. Es handelt sich auch um Verhaltenstests, die sich besser in der Dokumentation mit den Anforderungen widerspiegeln ("Senden Sie einen Brief, wenn Zahlungsinformationen nicht gespeichert werden können"). Wenn Sie einen gefälschten Zahlungsdienst ausführen und sicherstellen, dass dieser mit den richtigen JS-Typen aufgerufen wird, richtet sich Ihr Test gleichzeitig an Interna, die nicht mit der Funktionalität der Anwendung zusammenhängen und sich wahrscheinlich häufig ändern.
Sonst. Bei jedem Code-Refactoring werden alle gefälschten Objekte im Code gefunden und aktualisiert. Tests von einem Assistenten werden zur Belastung.
CodebeispieleEin Beispiel für Antimuster. Gefälschte Objekte sind für Mut.
Beispiel mit Sinon .
it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => {
Wie man es richtig macht. Spione wurden entwickelt, um Anforderungen zu testen, aber es gibt einen Nebeneffekt - sie wirken sich unweigerlich auf das Innere aus.
it("When a valid product is about to be deleted, ensure an email is sent", async () => {
1.6 Verwenden Sie nicht "foo", sondern realistische Eingaben
Was soll ich tun. Oft treten Produktionsfehler mit sehr spezifischen und überraschenden Eingabedaten auf. Je realistischer die Daten während des Tests sind, desto wahrscheinlicher ist es, dass Fehler rechtzeitig erkannt werden. Verwenden Sie spezielle Bibliotheken, z. B.
Faker, um pseudoreale Daten zu generieren, die die Vielfalt und Art der Produktionsdaten simulieren. Solche Bibliotheken können realistische Telefonnummern, Benutzernamen, Bankkarten, Firmennamen und sogar den Text „lorem ipsum“ generieren. Sie können Tests erstellen (zusätzlich zu Unit-Tests und nicht stattdessen), die gefälschte Daten randomisieren, um das Modul in einen Test zu integrieren, oder sogar echte Daten aus einer Produktionsumgebung importieren. Willst du noch weiter gehen? Lesen Sie das nächste Kapitel (über eigenschaftsbasierte Tests).
Sonst. Ihre Entwicklungstests werden mit synthetischen Eingaben wie „Foo“ erfolgreich aussehen, und Produktionsdaten können fehlschlagen, wenn ein Hacker
@3e2ddsf . ##' 1 fdsfds . fds432 AAAA
knifflige Zeile wie
@3e2ddsf . ##' 1 fdsfds . fds432 AAAA
@3e2ddsf . ##' 1 fdsfds . fds432 AAAA
@3e2ddsf . ##' 1 fdsfds . fds432 AAAA
.
CodebeispieleEin Beispiel für Antimuster. Eine Testsuite, die aufgrund der Verwendung unrealistischer Daten erfolgreich ausgeführt wird.
Ein Beispiel mit Jest .
const addProduct = (name, price) =>{ const productNameRegexNoSpace = /^\S*$/;
Wie man es richtig macht. Zufällige realistische Eingabe.
it("Better: When adding new valid product, get successful confirmation", async () => { const addProductResult = addProduct(faker.commerce.productName(), faker.random.number());
1.7 Verwenden Sie eigenschaftsbasierte Tests, um mehrere Eingabekombinationen zu validieren
Was soll ich tun. Normalerweise wählen wir für jeden Test mehrere Stichproben von Eingabedaten aus. Auch wenn das Eingabeformat den realen Daten ähnlich ist (siehe Kapitel „Verwenden Sie nicht„ foo “)), werden nur einige Kombinationen von Eingabedaten behandelt (Methode
('', true, 1)
, Methode
("string" , false" , 0)
). Im Betrieb kann eine API, die mit fünf Parametern aufgerufen wird, mit Tausenden verschiedener Kombinationen aufgerufen werden, von denen eine zu einem Prozessabsturz (
Fuzzing ) führen kann. Was wäre, wenn Sie einen Test schreiben könnten, der automatisch 1000 Kombinationen von Eingabedaten und Daten sendet Festlegen, bei welchen Kombinationen der Code nicht die richtige Antwort zurückgibt? Dasselbe machen wir mit m todike Test basierte auf Eigenschaften: durch alle möglichen Kombinationen von Eingangsdaten in die Testeinheit zu senden wir die Chance auf eine Fehlererkennung erhöhen, zum Beispiel, haben wir eine Methode.
addNewProduct(id, name, isDiscount)
diese Methode seine Bibliothek Unterstützung mit einer Reihe von Kombinationen nennen.
(, , )
, z. B.
(1, "iPhone", false)
,
(2, "Galaxy", true)
usw. Sie können anhand der Eigenschaften mit Ihrem bevorzugten Testläufer (Mocha, Jest) testen etc.) und Bibliotheken wie
js-verify oder
testcheck (es hat eine viel bessere Dokumentation). Sie können auch
die Fast-Check-Bibliothek ausprobieren , die zusätzliche Funktionen bietet und vom Autor aktiv begleitet wird.
Sonst. Sie wählen gedankenlos Eingabedaten für den Test aus, die nur gut funktionierende Codeausführungspfade abdecken. Leider verringert dies die Effektivität des Testens als Mittel zum Erkennen von Fehlern.
CodebeispieleWie man es richtig macht. Testen Sie zahlreiche Kombinationen mit dem Mokka-Testcheck.
require('mocha-testcheck').install(); const {expect} = require('chai'); const faker = require('faker'); describe('Product service', () => { describe('Adding new', () => {
1.8 Verwenden Sie bei Bedarf nur kurze und Inline-Aufnahmen.
Was soll ich tun. Wenn Sie
basierend auf Snapshots testen müssen , verwenden Sie nur kurze Snapshots ohne zusätzliche Informationen (z. B. in 3-7 Zeilen), einschließlich dieser als Teil des Tests (
Inline-Snapshot ) und nicht als externe Dateien. Wenn Sie diese Empfehlung befolgen, bleiben Ihre Tests selbstverständlich und zuverlässiger.
Auf der anderen Seite veranlassen uns die „klassischen Snapshot“ -Handbücher und -Tools, große Dateien (z. B. Markup zum Rendern von Komponenten oder JSON-API-Ergebnisse) auf externen Medien zu speichern und die Ergebnisse bei jeder Testausführung mit der gespeicherten Version zu vergleichen. Es kann beispielsweise implizit unseren Test mit 1000 Zeilen mit 3000 Werten verknüpfen, die der Autor des Tests nie gesehen hat, von denen er nicht erwartet hatte. Warum ist das so schlimm? Weil es 1000 Gründe gibt, warum der Test fehlschlägt. Schon eine Zeile kann einen Schnappschuss ungültig machen, und dies kann häufig vorkommen. Wie viel Nach jedem Leerzeichen, Kommentar oder geringfügigen Änderungen in CSS oder HTML. Darüber hinaus gibt der Name des Tests keinen Aufschluss über den Fehler, da nur überprüft wird, ob sich 1000 Zeilen nicht geändert haben, und der Autor des Tests aufgefordert wird, ein langes Dokument, das er nicht analysieren und überprüfen konnte, so lange wie gewünscht zu nehmen. All dies sind Symptome eines obskuren und hastigen Tests, der keine klare Aufgabe hat und versucht, zu viel zu erreichen.
Es ist anzumerken, dass es mehrere Situationen gibt, in denen es akzeptabel ist, lange und externe Bilder zu verwenden, beispielsweise wenn das Schema bestätigt wird und nicht die Daten (Werte extrahieren und sich auf die Felder konzentrieren) oder wenn sich die empfangenen Dokumente selten ändern.
Sonst. UI-Tests schlagen fehl. Der Code sieht gut aus, ideale Pixel werden auf dem Bildschirm angezeigt. Was passiert also? Ihre Tests mit Schnappschüssen haben nur den Unterschied zwischen dem Originaldokument und dem gerade erhaltenen Dokument ergeben - ein Leerzeichen wurde dem Markup hinzugefügt ...
CodebeispieleEin Beispiel für Antimuster. Verknüpfen eines Tests mit unbekannten 2000 Codezeilen.
it('TestJavaScript.com is renderd correctly', () => {
Wie man es richtig macht. Erwartungen sind sichtbar und im Rampenlicht.
it('When visiting TestJavaScript.com home page, a menu is displayed', () => {
1.9 Vermeiden Sie globale Prüfstände und Anfangsdaten und fügen Sie jedem Test Daten separat hinzu
Was soll ich tun. Gemäß der goldenen Regel (Kapitel 0) sollte jeder Test einen eigenen Satz von Zeilen in der Datenbank hinzufügen und bearbeiten, um Bindungen zu vermeiden, und es war für Benutzer einfacher, den Test zu verstehen. In der Realität verstoßen Tester häufig gegen diese Regel, bevor sie Tests ausführen, bei denen die Datenbank mit Anfangsdaten (Seeds) (
auch als „Prüfstand“ bezeichnet ) gefüllt wird, um die Produktivität zu steigern. , (. « »), . . , , (, ).
. , , , ? , , , .
. - .
before(() => {
. , .
it("When updating site name, get successful confirmation", async () => {
1.10 ,
. , - , try-catch-finally , . ( ), .
Chai:
expect(method).to.throw
( Jest:
expect(method).toThrow()
). , , . , , .
. (, CI-) , .
. , try-catch .
/it("When no product name, it throws error 400", async() => { let errorWeExceptFor = null; try { const result = await addNewProduct({name:'nest'});} catch (error) { expect(error.code).to.equal('InvalidInput'); errorWeExceptFor = error; } expect(errorWeExceptFor).not.to.be.null;
. , , , QA .
it.only("When no product name, it throws error 400", async() => { expect(addNewProduct)).to.eventually.throw(AppError).with.property('code', "InvalidInput"); });
1.11
. :
- smoke-,
- IO-less,
- , , ,
- , pull request', .
, , , #cold #api #sanity. . , Mocha :
mocha — grep 'sanity'
.
. , , , , , , , .
. '#cold-test' (Cold=== , - , ).
1.12
. , Node.js . , Node.
TDD . , , , .
-- , - . , , . , . , , , , (, ..).
. , .
2:
️2.1 :
. 10 , . . , 10 (, , ), , ,
? ?
: 2019- , TDD , , , . , , ,
. IoT-, Kafka RabbitMQ, , - . , , ? (, , ), , - .
( ) , , (« API, , !» (consumer-driven contracts)). , : , , , .
: TDD - . TDD , . , .
. ROI, Fuzz, , 10 .
. Cindy Sridharan 'Testing Microservices — the sane way'

Ein Beispiel:
2.2
. , . , . , , ? — . : TDD-, .
«», API, , (, , in-memory ), , , . , , « », .
. , , 20 %.
. Express API ( ).

2.3 , API
. , ( ). - , ! — , , . «
-22 » : , , .
(consumer-driven contracts) PACT : , … ! PACT — «», . PACT- — . , API CI, .
. — .
.
2.4
. , Express-. . , , , JS- {req,res}. , (,
Sinon ) {req,res}, , .
node-mock-http {req,res} . , , HTTP-, res- (. ).
. Express- === .
2.5
. . CI- , . (, ), (, ), .
Sonarqube (2600+
)
Code Climate (1500+
). ::
Keith Holliday. , .
. CodeClimate, :

2.6 , Node
. , . ( ) . , - , ? ? , API 50 % ? , Netflix - (
Chaos Engineering ). : , . , Netflix,
chaos monkey , , , , - ( Kubernetes
kube-monkey , ). , . , , Node- , , v8 1,7 , UX , ?
node-chaos (-), , Node.
. , production .
. Node-chaos , Node.js, .

2.7 ,
. ( 0), , , . , (seeds) (
« » ) . , (. « »), , . . , , (, ).
. , , , ? , , , .
. - .
before(() => {
. , .
it("When updating site name, get successful confirmation", async () => {
3:
3.1. UI
. , , , . , , ( HTML CSS) . , (, , , ), , , .
. 10 , 500 (100 = 1 ) - - .
. .
test('When users-list is flagged to show only VIP, should display only VIP members', () => {
. UI . test('When flagging to show only VIP, should display only VIP members', () => {
3.2 HTML- ,
. HTML- , . , , CSS-. , 'test-id-submit-button'. . , , .
. , , . — , , Ajax . . , CSS 'thick-border' 'thin-border'
. , .
. CSS-.
<!-- the markup code (part of React component) --> <span id="metric" className="d-flex-column">{value}</span> <!-- what if the designer changes the classs? -->
3.3
. , , . , , . , — - , (.
« » ). (, ) , .
, : , . ( ) . , .
. , . ?
. .
class Calendar extends React.Component { static defaultProps = {showFilters: false} render() { return ( <div> A filters panel with a button to hide/show filters <FiltersPanel showFilter={showFilters} title='Choose Filters'/> </div> ) } } //Examples use React & Enzyme test('Realistic approach: When clicked to show filters, filters are displayed', () => { // Arrange const wrapper = mount(<Calendar showFilters={false} />) // Act wrapper.find('button').simulate('click'); // Assert expect(wrapper.text().includes('Choose Filter')); // This is how the user will approach this element: by text })
. .
test('Shallow/mocked approach: When clicked to show filters, filters are displayed', () => {
3.4 .
. (, ). (,
setTimeOut
) , . (,
Cypress cy.request('url') ), API,
wait(expect(element)) @testing-library/DOM . , API, , . , ,
hurry-up the clock . — , , ( ). , , - npm- , ,
wait-for-expect .
. , . , . .
. E2E API (Cypress).
. , DOM- (@testing-library/dom).
. .
test('movie title appears', async () => {
3.5.
. - , . , , . :
pingdom , AWS CloudWatch
gcp StackDriver , , SLA. , , (,
lighthouse ,
pagespeed ), . — , :
,
(TTI) . , , , , , DOM, SSL . , CI, 247 CDN.
. , , , , - CDN.
. Lighthouse .

3.6 API
. ( 2), , , ( ). API (,
Sinon ,
Test doubles ), API. . API , ( ). API, . , , API . , : .
. , API 100 , 20 .
3.7 ,
. E2E (end-to-end, ) UI (. 3.6). , , . , , - . , — (, ), . - , , UI-
Cypress Pupeteer . , : 50 , , . 10 . , , , — . , .
. UI , , ( , UI) .
3.8
. , API , , . (before-all), - . , : . , . - API- . , . (, ), , , . , : , API (. 3.6).
. , 200 , 100 , 20 .
. (before-all), (before-each) (, Cypress).
Cypress .
let authenticationToken;
3.9 smoke-,
. production- , , . , , , , . smoke- . production, , , . , smoke- , .
. , , production . /Payment.
. Smoke- .
it('When doing smoke testing over all page, should load them all successfully', () => {
3.10
. , . «» , , , , . , ( ) , , -, , , . « », .
. ,
Cucumber JavaScript .
StoryBook UI- , (, , , ..) , . , , .
. , .
. cucumber-js.
. Storybook , .

3.11
. , . , . , . , - . , . , , , . , - . UI « ». , (,
wraith , PhantomCSS), . (,
Applitools ,
Perci.io ) , , « » (, ), DOM/CSS, .
. , ( ) , ?
. : , .

. wraith UI.
# Add as many domains as necessary. Key will act as a label domains: english: "http://www.mysite.com" # Type screen widths below, here are a couple of examples screen_widths: - 600 - 768 - 1024 - 1280 # Type page URL paths below, here are a couple of examples paths: about: path: /about selector: '.about' subscribe: selector: '.subscribe' path: /subscribe
4:
4.1 (~80 %),
. — , . , . — (, ), . ? , 10-30 % . 100 % , . . , : Airbus, ; , 50 % . , , 80 % (
Fowler: «in the upper 80s or 90s» ), , , .
: (CI), (
Jest ) , . , . , ( ) — . , — , , . , .
. . , , . .
.
. ( Jest).

4.2 ,
. , . , , , , . , , - , .
PricingCalculator
, , , 10 000 … , , . , . 80- , . : , , , . , - .
. , , , .
. ? , QA . : , - . , - API .

4.3
. : 100 %, . Wie so? , , , . . - : , , , .
, . JavaScript-
Stryker :
- « ». ,
newOrder.price===0
newOrder.price!=0
. «» .
- , , : , . , , .
, , , .
. , 85- 85 % .
. 100 %, 0 %.
function addNewOrder(newOrder) { logger.log(`Adding new order ${newOrder}`); DB.save(newOrder); Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`); return {approved: true}; } it("Test addNewOrder, don't use such test names", () => { addNewOrder({asignee: "John@mailer.com",price: 120}); });
. Stryker reports, , ().

4.4 -
. ESLint. ,
eslint-plugin-mocha , (
describe()
),
, .
eslint-plugin-jest , ( ).
. 90- , , , . , .
. , , .
describe("Too short description", () => { const userToken = userService.getDefaultToken()
5: CI
5.1 ,
. — . , . , ( !). , . (
ESLint standard Airbnb ), . ,
eslint-plugin-chai-expect , .
Eslint-plugin-promise ( ).
Eslint-plugin-security , DOS-.
eslint-plugin-you-dont-need-lodash-underscore , , V8, ,
Lodash._map(…)
.
. , , . Was ist los? , , . . , , .
. , . , ESLint production-.

5.2
. CI , , ..? ,
. Warum? : (1) -> (2) -> (3) . , , .
, , , , - .
CI- ( ,
CircleCI local CLI ) . ,
wallaby , ( ) . npm- package.json, , (, , , ). (non-zero exit code)
concurrently . — ,
npm run quality
. githook (
husky ).
. , .
. Npm-, , , .
"scripts": { "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", "inspect:lint": "eslint .", "inspect:vulnerabilities": "npm audit", "inspect:license": "license-checker --failOn GPLv2", "inspect:complexity": "plato .", "inspect:all": "concurrently -c \"bgBlue.bold,bgMagenta.bold,yellow\" \"npm:inspect:quick-testing\" \"npm:inspect:lint\" \"npm:inspect:vulnerabilities\" \"npm:inspect:license\"" }, "husky": { "hooks": { "precommit": "npm run inspect:all", "prepush": "npm run inspect:all" } }
5.3 production-
. — CI-. . —
Docker-compose . (, ) production-.
AWS Local AWS-.
, serverless
AWS SAM Faas-.
Kubernetes CI-, . , « Kubernetes»
Minikube MicroK8s , , . « Kubernetes»: CI- (,
Codefresh ) Kubernetes-, CI- ; .
. .
: CI-, Kubernetes-
(Dynamic-environments Kubernetes )
deploy: stage: deploy image: registry.gitlab.com/gitlab-examples/kubernetes-deploy script: - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN - kubectl create ns $NAMESPACE - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL" - mkdir .generated - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF" - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml" - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml environment: name: test-for-ci
5.4
. , , . , 500 , , . , CI- (
Jest ,
AVA Mocha ) , . CI- (!), . , CLI , , .
. — , .
5.5
. , . 10 ? CI- npm-
license check plagiarism check ( ), , , Stackoveflow .
. , , .
.

5.6
. , Express, .
npm audit ,
snyk ( ). CI .
. . .
: NPM Audit

5.7
. package-lock.json Yarn npm ( ): .
npm install
npm update
, . , — . , package.json
ncu .
, . :
- CI , , npm outdated npm-check-updates (ncu). .
- , pull request' .
: ? , ( ,
eslint-scope ). « »:
latest , , (, 1.3.1, — 1.3.8).
. , .
5.8 CI-, Node
. , Node . , Node.
- . , Jenkins .
- Docker.
- , . . smoke-, (, , ) .
- , , , , , .
- , . , -. - ( ).
- . .
- , , .
- (, Docker-).
- , .
node_modules
.
. , .
5.9 : CI-, Node
. , , . Node, CI . , MySQL, Postgres. CI- «», MySQl, Postgres Node. , - (, ). CI, , .
. - ?
: Travis ( CI) Node.
language: node_js node_js: - "7" - "6" - "5" - "4" install: - npm install script: - npm run test