Bonjour, Habr!
Je m'appelle Vitaliy Kotov, je fais beaucoup de tests d'automatisation et j'aime ça. J'ai récemment participé à un projet de configuration de l'automatisation à partir de zéro sur la pile TypeScript + Protractor + Jasmine. Pour moi, cette pile était nouvelle et j'ai cherché les informations nécessaires sur Internet.
J'ai réussi à trouver les manuels les plus utiles et les plus sensés uniquement en anglais. J'ai décidé qu'en russe, je devais également le faire. Je vais seulement vous dire les bases: pourquoi une telle pile, ce que vous devez configurer et à quoi ressemble le test le plus simple.
Je dois dire tout de suite que je travaille rarement avec NodeJS, npm et avec JavaScript côté serveur en général (en particulier avec TypeScript). Si vous trouvez une erreur dans la terminologie quelque part ou si certaines de mes décisions peuvent être améliorées, je serai heureux de le savoir dans les commentaires de gars plus expérimentés.
Au fait, j'avais déjà un article similaire:
«Nous déployons l'automatisation en quelques heures: PHPUnit, Selenium, Composer» .

Défi
Tout d'abord, voyons quel problème nous résolvons. Nous avons une application web écrite en utilisant AngularJS. Il s'agit d'un framework JavaScript basé sur lequel les projets Web sont souvent écrits.
Dans cet article, nous ne considérerons pas les avantages et les inconvénients des projets AngularJS. Quelques mots sur les caractéristiques de ces projets en termes de rédaction de tests e2e pour eux.
Un aspect assez important du test de l'automatisation est de travailler avec des éléments de page, ce qui se produit à l'aide de localisateurs. Un localisateur est une ligne composée selon certaines règles et identifiant un élément d'interface utilisateur: un ou plusieurs.
Pour le Web, CSS et Xpath sont les plus couramment utilisés. Parfois, s'il y a un élément avec un ID unique sur la page, vous pouvez le rechercher. Cependant, il me semble que WebDriver transforme toujours cet ID en un localisateur CSS à la fin et travaille déjà avec lui.
Si nous regardons le code HTML d'un projet AngularJS, nous verrons que les éléments ont beaucoup d'attributs qui ne sont pas en HTML classique:

Le code est extrait de la page de
démonstration du
rapporteur .
Tous les attributs commençant par ng- * sont utilisés par AngularJS pour travailler avec l'interface utilisateur. Une situation assez typique est lorsque les éléments n'ont pas d'autres attributs que ces attributs de contrôle, ce qui complique quelque peu le processus de compilation des localisateurs de qualité.
Ceux qui ont fait beaucoup d'automatisation connaissent la valeur de telles interfaces utilisateur pour lesquelles les localisateurs peuvent être facilement construits. Après tout, cela est rare pour les grands projets. :)
En fait, pour un tel projet, nous devons également configurer l'automatisation des tests. C'est parti!
C'est quoi
Tout d'abord, découvrons pourquoi chaque composant de notre pile est nécessaire.
Protractor est un framework de test basé sur WebDriverJS. Ce sera lui qui lancera nos navigateurs, leur fera ouvrir les pages nécessaires et interagira avec les éléments nécessaires.
Ce cadre est spécialement conçu pour les projets AngularJS. Il fournit des moyens supplémentaires pour spécifier les localisateurs:
element(by.model('first')); element(by.binding('latest')); element(by.repeater('some'));
Une liste complète se trouve sur la page de
manuel .
Ces méthodes simplifient la création et la prise en charge de localisateurs sur un projet. Cependant, vous devez comprendre que "sous le capot" tout cela est en tout cas converti en css. Le fait est que le protocole W3C, sur la base duquel l'interaction dans WebDriver a lieu, ne peut fonctionner qu'avec un ensemble fini de localisateurs. Cette liste peut être consultée sur
w3.org .
TypeScript est un langage de programmation créé par Microsoft. TypeScript diffère de JavaScript par sa capacité à taper des variables, la prise en charge de l'utilisation de classes à part entière et la possibilité de connecter des modules.
Écrit en code TS pour fonctionner avec le moteur V8 est traduit en code JS, qui est déjà en cours d'exécution. Lors de cette transformation, la conformité du code est vérifiée. Par exemple, il ne «compile» pas si, au lieu de int, une chaîne est explicitement passée quelque part à la fonction.
Jasmine est un framework pour tester le code JavaScript. En fait, c'est grâce à lui que notre code JS se transforme en ce que nous appelions un test. Il gère ces tests.
Ci-dessous, nous examinons ses capacités.
Montage et configuration du projet
Eh bien, nous avons décidé d'un ensemble de cadres, maintenant, mettons tout cela ensemble.
Pour travailler avec le code, j'ai choisi
Visual Studio Code de Microsoft. Bien que beaucoup écrivent dans
WebStorm ou même
Intellij Idea de JetBrains.
J'ai déjà installé NodeJS (v11.6.0) et NPM (6.9.0). Si vous ne l'avez pas, ce n'est pas un problème, leur installation n'est pas difficile. Tout est décrit suffisamment en détail sur le
site officiel .
Le fil peut être utilisé à la place du NPM, bien que cela ne soit pas important pour un petit projet.
Dans notre IDE, nous créons un nouveau projet. Nous créons package.json à la racine du projet - c'est là que nous décrirons tous les packages dont nous avons besoin pour le projet.
Vous pouvez le créer à l'aide de la commande
npm init . Ou vous pouvez simplement copier le contenu dans un fichier.
Initialement,
package.json ressemble à ceci:
{ "name": "protractor", "dependencies": { "@types/node": "^10.5.2", "@types/jasmine": "^3.3.12", "protractor": "^5.4.2", "typescript": "^3.4.1" } }
Après cela, nous
exécutons la commande
npm install pour installer tous les modules nécessaires et leurs dépendances (enfin, vous vous souvenez de l'image même de quelque chose de plus lourd qu'un trou noir ...)
En conséquence, nous devrions avoir un répertoire node_modules. Si elle est apparue, alors tout se passe comme prévu. Sinon, il vaut la peine d'examiner le résultat de l'exécution de la commande, généralement tout y est décrit en détail.
TypeScript et sa configuration
Pour installer TypeScript, nous avons besoin de npm:
npm install -g typescript
Assurez-vous qu'il est installé:
$ tsc -v Version 3.4.1
Tout semble être en ordre.
Maintenant, nous devons créer une configuration pour travailler avec TS. Il doit également être à la racine du projet et s'appeler
tsconfig.jsonSon contenu sera comme ceci:
{ "compilerOptions": { "lib": ["es6"], "strict": true, "outDir" : "output_js", "types" : ["jasmine", "node"] }, "exclude": [ "node_modules/*" ] }
En bref, nous avons spécifié ce qui suit dans cette configuration:
- Dans quel répertoire placer le code JS final (dans notre cas, c'est output_js)
- Activer le mode strict
- Indiqué avec quels cadres nous travaillons
- Exclusion de node_modules de la compilation
TS a une grande variété de paramètres. C'est suffisant pour notre projet. Vous pouvez en savoir plus
sur typescriptlang.org .
Voyons maintenant comment fonctionne la commande
tsc , qui transformera notre code TS en code JS. Pour ce faire, créez un simple fichier check_tsc.ts avec le contenu suivant:
saySomething("Hello, world!"); function saySomething(message: string) { console.log(message); }
Ensuite, exécutez la commande
tsc (pour cela, vous devez être dans le répertoire du projet).
Nous verrons que nous avons le répertoire output_js et un fichier js similaire avec le contenu suivant est apparu à l'intérieur:
"use strict"; saySomething("Hello, world!"); function saySomething(message) { console.log(message); }
Ce fichier peut déjà être lancé à l'aide de la commande node:
$ node output_js/check_tsc.js Hello, world!
Nous avons donc écrit notre premier programme TypeScipt, félicitations. Écrivons des tests maintenant. :)
Configuration du rapporteur
Pour Protractor, nous avons également besoin d'une configuration. Mais ce ne sera plus sous forme de json, mais sous forme de fichier ts. Appelons-le config.ts et écrivons-y le code suivant:
import { Config } from "protractor"; export const config: Config = { seleniumAddress: "http://127.0.0.1:4444/wd/hub", SELENIUM_PROMISE_MANAGER: false, capabilities: { browserName: "chrome", }, specs: [ "Tests/*Test.js", ] };
Dans ce fichier, nous avons spécifié les éléments suivants:
Tout d'abord, le chemin d'accès au serveur Selenium en cours d'exécution. Il est assez simple à exécuter, il vous suffit de
télécharger le fichier jar du serveur autonome et les pilotes nécessaires (par exemple, le pilote chrome
pour le navigateur Chrome ). Ensuite, écrivez la commande suivante:
java -jar -Dwebdriver.chrome.driver=/path/to/chromedriver /path/to/selenium-server-standalone.jar
En conséquence, nous devrions voir la conclusion suivante:
23:52:41.691 INFO [GridLauncherV3.launch] - Selenium build info: version: '3.11.0', revision: 'e59cfb3' 23:52:41.693 INFO [GridLauncherV3$1.launch] - Launching a standalone Selenium Server on port 4444 2019-05-02 23:52:41.860:INFO::main: Logging initialized @555ms to org.seleniumhq.jetty9.util.log.StdErrLog 23:52:42.149 INFO [SeleniumServer.boot] - Welcome to Selenium for Workgroups.... 23:52:42.149 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 4444
Le port 4444 est par défaut. Il peut être défini à l'aide du paramètre -port ou via le paramètre de configuration "seleniumArgs" => "-port".
Si vous voulez plus simple et plus rapide: vous pouvez télécharger le package npm
webdriver-manager .
Ensuite, gérez le serveur à l'aide des commandes de démarrage, d'arrêt, etc. Il n'y a pas beaucoup de différence, c'est juste que je suis plus habitué à travailler avec un fichier jar. :)
Deuxièmement , nous avons indiqué que nous ne voulions pas utiliser le gestionnaire Promise. Plus d'informations à ce sujet plus tard.
Troisièmement , nous avons spécifié des capacités pour notre navigateur. J'ai commenté une partie, par exemple, que nous pouvons assez facilement lancer le navigateur en mode sans tête. C'est une fonctionnalité intéressante, mais elle ne vous permettra pas d'observer visuellement nos tests. En attendant, nous apprenons juste - je voudrais. :)
Quatrièmement , nous avons spécifié un masque pour les spécifications (tests). Tout ce qui se trouve dans le dossier Tests et se termine par Test.js. Pourquoi sur js, pas ts? En effet, en fin de compte, Node fonctionnera spécifiquement avec les fichiers JS et non avec les fichiers TS. Il est important de ne pas se confondre, surtout au début du travail.
Créez maintenant le dossier Tests et écrivez le premier test. Il fera ce qui suit:
- Désactive la vérification qu'il s'agit d'une page angulaire. Sans cela, nous obtenons ce message d'erreur: Erreur lors de l'exécution de testForAngular. Bien sûr, pour les pages angulaires, cette vérification n'est pas nécessaire pour désactiver.
- Accède à la page Google.
- Vérifiez qu'il existe un champ de saisie de texte.
- Entrez le texte «rapporteur».
- Cliquez sur le bouton soumettre (il a un localisateur assez compliqué, car il y a deux boutons et le premier est invisible).
- On s'attendra à ce que l'URL contienne le mot «rapporteur» - cela signifie que nous avons tout fait correctement et que la recherche a commencé.
Voici le code que j'ai obtenu:
import { browser, by, element, protractor } from "protractor"; describe('Search', () => { it('Open google and find a text', async () => {
Dans le code, nous voyons que tout commence par la fonction describe (). Elle nous est venue du framework Jasmine. Ceci est un wrapper pour notre script. À l'intérieur, il peut y avoir des fonctions beforeAll () et beforeEach () pour effectuer des manipulations avant tous les tests et avant chaque test. Autant de fonctions qu'il () sont, en fait, nos tests. En fin de compte, s'ils sont définis, afterAll () et afterEach () seront exécutés pour les manipulations après chaque test et tous les tests.
Je ne parlerai pas de toutes les fonctionnalités de Jasmine, vous pouvez les lire sur le site
jasmine.imtqy.comPour exécuter notre test, vous devez d'abord transformer le code TS en code JS, puis l'exécuter:
$ tsc $ protractor output_js/config.js
Notre test a commencé - nous sommes super. :)

Si le test n'a pas commencé, il convient de vérifier:
- Que le code est écrit correctement. En général, s'il y a des erreurs critiques dans le code, nous les rattraperons lors de la commande tsc.
- Ce serveur Selenium est en cours d'exécution. Pour ce faire, vous pouvez ouvrir l'URL http: //127.0.0.1-00-00444/wd/hub - il devrait y avoir une interface pour les sessions Selenium.
- Que Chrome démarre normalement avec la version téléchargée de chrome-driver. Pour ce faire, sur la page wd / hub /, cliquez sur Créer une session et sélectionnez Chrome. S'il ne démarre pas, vous devez soit mettre à jour Chrome, soit télécharger une autre version de chrome-driver.
- Si tout cela échoue, vous pouvez vérifier que la commande npm install s'est terminée avec succès.
- Si tout est écrit correctement, mais que rien ne démarre toujours - essayez de rechercher l'erreur sur google. Cela aide le plus souvent. :)
Scripts NPM
Pour vous simplifier la vie, vous pouvez créer une partie des commandes npm alias. Par exemple, je voudrais supprimer le répertoire avec les fichiers JS précédents et le recréer avec de nouveaux avant chaque test.
Pour ce faire, ajoutez l'élément de scripts à package.json:
{ "name": "protractor", "scripts": { "test": "rm -rf output_js/; tsc; protractor output_js/config.js" }, "dependencies": { "@types/node": "^10.5.2", "@types/jasmine": "^3.3.12", "protractor": "^5.4.2", "typescript": "^3.4.1" } }
Maintenant, en entrant la commande de
test npm, les événements suivants se produiront: le répertoire output_js avec l'ancien code sera supprimé, il sera recréé et un nouveau code JS y sera écrit. Après quoi, les tests commenceront immédiatement.
Au lieu de cet ensemble de commandes, vous pouvez spécifier toute autre dont vous avez personnellement besoin pour travailler. Par exemple, vous pouvez démarrer et éteindre un serveur au sélénium entre les tests. Bien que cela, bien sûr, est plus facile à contrôler à l'intérieur du code de test lui-même.
Un peu sur Promise
Au final, je vais parler un peu de Promise, async / wait et en quoi l’écriture des tests dans NodeJS diffère du même Java ou Python.
JavaScript est un langage asynchrone. Cela signifie que le code n'est pas toujours exécuté dans l'ordre dans lequel il est écrit. Cela inclut les requêtes HTTP, et nous nous souvenons que le code communique avec Selenium Server via HTTP.
Promise (généralement appelé «promesses») fournit un moyen pratique d'organiser le code asynchrone. Vous pouvez en savoir plus à leur sujet sur
learn.javascript.ru .
En fait, ce sont des objets qui rendent un code dépendant de l'exécution d'un autre, garantissant ainsi un certain ordre. Le rapporteur travaille très activement avec ces objets.
Regardons un exemple. Supposons que nous exécutons le code suivant:
driver.findElement().getText();
En Java, nous nous attendons à ce que nous renvoyions un objet de type String. Dans Protractor, ce n'est pas tout à fait le cas, nous retournerons un objet Promise. Et juste comme ça, l'imprimer avec un objectif de débogage ne fonctionnera pas.
Habituellement, nous n'avons pas besoin d'imprimer la valeur résultante. Nous devons le passer à une autre méthode qui fonctionnera déjà avec cette valeur. Par exemple, il vérifiera la conformité du texte avec l'attendu.
Des méthodes similaires dans Protractor acceptent également les objets Promise en entrée, il n'y a donc aucun problème. Mais, si vous voulez toujours voir la valeur, () vous sera utile.
C'est ainsi que nous pouvons imprimer le texte du bouton sur une page Google (notez que puisqu'il s'agit d'un bouton, le texte est à l'intérieur de l'attribut value):
En ce qui concerne les mots clés asynchrones / attendent, il s'agit d'une approche légèrement plus récente pour travailler avec du code asynchrone. Il vous permet d'éviter l'enfer des promesses, qui était auparavant formé dans le code en raison du grand nombre d'imbrication. Néanmoins, vous ne pourrez pas vous débarrasser complètement de Promise et vous devez pouvoir travailler avec eux. Ceci est compréhensible et détaillé peut être trouvé dans l'article
Conception asynchrone / attendre en JavaScript: forces, pièges et caractéristiques d'utilisation .
Devoirs
En guise de devoirs, je suggère d'écrire des tests pour une page écrite en AngularJS:
protractor-demo .
N'oubliez pas de supprimer la ligne du code concernant la désactivation de la vérification des pages sur AngularJS. Et assurez-vous de travailler avec des localisateurs spécialement conçus pour AngularJS. Il n'y a pas de magie particulière à cela, mais c'est assez pratique.
Résumé
Faisons le point. Nous avons réussi à écrire des tests qui fonctionnent sur un tas de TypeScript + Protractor + Jasmine. Nous avons appris à construire un tel projet, à créer les configurations nécessaires et à écrire le premier test.
En cours de route, nous avons discuté un peu de l'utilisation des tests automatiques JavaScript. Cela semble bon pour quelques heures. :)
Que lire, où chercher
Protractor a un très bon manuel avec des exemples JavaScript:
https://www.protractortest.org/#/tutorialJasmine a un manuel:
https://jasmine.imtqy.com/pages/docs_home.htmlTypeScipt a un bon début:
https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.htmlSur le support, il y a un bon article en anglais sur TypeScript + Protractor + Cucumber:
https://medium.com/@igniteram/e2e-testing-with-protractor-cucumber-using-typescript-564575814e4aEt dans mon référentiel, j'ai publié le code final de ce dont nous avons discuté dans cet article:
https://github.com/KotovVitaliy/HarbProtractorJasmineJasmine .
Sur Internet, vous pouvez trouver des exemples de projets plus complexes et plus importants sur cette pile.
Merci de votre attention! :)