npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@axa-fr/cypress-component

v0.0.9

Published

This package aims to facilitate the reading and writing of Cypress tests. It improves the accessibility of DOM elements via a component-based approach, like current web frameworks. It also facilitates the management of routes whether in a plugged or unplu

Downloads

9

Readme

Cypress components

Twitter

Ce package a pour but de faciliter la lecture et l'écriture de tests Cypress. Il améliore l'accessibilité des éléments du DOM via une approche par composants, comme les frameworks web actuel. Il facilite également la gestion des routes que ce soit dans un environnement bouchonné ou non.

Install

npm i @axa-fr/cypress-component

Documentation

Browser

L'objet Browser vous permet d'éxécuter n'importe quel action sur le navigateur. Il encapsule les actions Cypress suivantes:

Exemple

import { Browser } from '@axa-fr/cypress-component';

describe('Test scenario', () => {
    beforeEach(() => {
        Browser.visit('https://example.com');
    });
    it('should...', () => {
        ...
    });
});

RouteHandler

Le RouteHandler est un object qui vous permet de facilement gérer vos routes. Les routes sont très importantes dans Cypress car elles vont vous permettre de pouvoir synchroniser l'exécution de votre test en attendant les requêtes HTTP envoyées dépuis votre application. Vous pouvez également mocker ces appels pour tester tous les comportements possible de votre application. Par exemple, simuler qu'un service tombe en erreur.

Il contient les méthode suivantes:

  • configure(routesDefinition: RoutesDefinition): vous permet de configurer l'ensemble de vos routes
  • register(routeAlias: string, route: Route): configure une seule route et l'associe à un alias
  • wait(...routesToWait: string[]): attend qu'une ou plusieurs requête(s) s'éxécutent
  • stub( routeAlias: string, stub: string | object, httpStatus?: number, responseDelay?: number, headers?: object, ): mock une route. Vous avez la possibilité de mocker le body, le statut HTTP, les headers et rajouter du délai de réponse.
  • stubDefault(): mock chaque route configurée via configure avec son mock par défaut (c.f. exemple ci-dessous)
  • stubRestore(routeAlias: string): permet d'envlever le mock d'une route pour qu'elle retrouve son comportement inital

Exemple

Pour décalrer l'ensemble de vos routes, je vous conseille de créer un fichier spécifique. Par exemples routes-definition.ts. Vous aller ensuite définir une constante pour identifier chacune de vos routes. Cette constante servira d'alias pour la route. Ensuite pour chaque route, vous allez lier la constante avec une definition de route. Cette définition de route est défine à travers différents paramètres:

  • httpMehod: le verbe HTTP de la requêtes
  • urlPattern: le pattern de l'url. vous pouvez remplacer les arguments par * ou tout un morceau d'url avec **
  • defaultStub: définit le mock par défaut de la route. Un mock se définit via un body, un statut HTTP, des headers et un éventuel délai de réponse
// routes-definition.ts

import { HttpMethod, RoutesDefinition } from '@axa-fr/cypress-component';

export const Routes = {
    loadContract: 'LOAD_CONTRACT_ROUTE',
    // ...
};

export const MyRoutesDefinition: RoutesDefinition = {
    [Routes.loadContract]: {
        httpMethod: HttpMethod.POST,
        urlPattern: '**/api/contract/*',
        defaultStub: {
            body: {
                // CONTRACT
            },
        },
    },
    // ...
};

Vous pouvez maintenant facilement gérer vos routes dans vos tests. Dans le cas ci-dessous, je configure mes routes (RouteHandler.configure(MyRoutesDefinition) RouteDefinition est l'objet qu'on a définit ci-dessus) et je souhaite que toutes les routes soient mockées (RouteHandler.stubDefault()). Je visite ensuite une url et j'attend que la requête qui charge mon contrat soit bien éxécutée avant de commencer l'éxécution de mon test.

import { Browser, RouteHandler } from '@axa-fr/cypress-component';
import { MyRoutesDefinition, Routes } from '../../routes-definition';

describe('Test scenario', () => {
    beforeEach(() => {
        RouteHandler.configure(MyRoutesDefinition);
        RouteHandler.stubDefault();

        Browser.visit('https://example.com');

        RouteHandler.wait(Routes.loadContract);
    });
    it('should...', () => {
        // Votre test ici
    });
});

Composants

Les composants sont le coeurs de ce package. Il vous permet de définir les composants dont vous avez besoin pour l'éxécution de vos tests dans un fichier externe pour les partager entre vos différents scénarios. Vous allez pouvoir typer ces composants pour ne pas pouvoir exécuter de commandes innapropriées. A l'heure actuel, il existe différents type de composants que vous pouvez utiliser:

  • HtmlElement: Le composant de base
  • Input(TextInput, Checkbox, Radio, Select, Button, Link): les inputs ont la possibilté de focus ou blur. Ils possèdent aussi une fonctione set qui permet de mettre une valeur dans l'input en éxécutant par examples les actions suivantes: focus > type|check|select|click > blur. Le contenu d'un input text est toujours remplacé.
  • FormField(TextField, SelectField, CheckboxField, RadioField): les champs de formulaire vont encapsuler les inputs associées. Et vont exposer les commandes de l'input pour facilement pouvoir gérer les champs de formulaire. Ils permettent aussi d'attendre une ou plusieurs routes après qu'un appel à set soit effectué.

Pour délcarer un composant, vous avez différentes possibilités:

  • Via un CSS selector:
export const HomePage = {
    footer: HtmlElement('#footer'),
    // ...
};
  • Via un contains:
export const HomePage = {
    footer: HtmlElement({ contains: 'Pied de page' }),
    // ...
};
  • Via un CSS selector et un contains (et même un index):
export const HomePage = {
    footer: HtmlElement({ selector: '.container', contains: 'Pied de page', index: 0 }),
    // ...
};
  • Via un enchainement de ces proriétés:
export const HomePage = {
    footer: HtmlElement([
        { selector: 'html' },
        { selector: 'body' },
        { selector: '.container', contains: 'Pied de page', index: 0 },
    ]),
    // ...
};

Pour les champs de formulaires, vous quelques exemples:

  • TextField avec un CSS selector contenant un texte donné.
import { Button, TextField } from '@axa-fr/cypress-component';

export const LoginPage = {
    username: TextField({ selector: '.form-field', contains: 'Username' }),
    password: TextField({ selector: '.form-field', contains: 'Password' }),
    loginButton: Button({ selector: '.submit', contains: 'Login' }),
    successMessage: HtmlElement('.success'),
    // ...
};
import { Browser, RouteHandler } from '@axa-fr/cypress-component';
import { MyRoutesDefinition, Routes } from '../../routes-definition';
import { HomePage } from '../../components';

describe('Test scenario', () => {
    beforeEach(() => {
        RouteHandler.configure(RouteDefinitions);

        Browser.visit('https://example.com');
    });
    it('should show success message when logged in', () => {
        LoginPage.username.set('my-username');
        LoginPage.password.set('********');
        LoginPage.loginButton.click();

        RouteHandler.wait(Routes.login);

        LoginPage.successMessage.should((successMessage) => {
            expect(successMessage).to.be.visible;
            expect(successMessage).to.contain('Vous êtes connecté');
        });
    });
});
  • RadioField avec un type de valeur passé comme type générique

Cela fontionne de la même manière pour les SelectField et les CheckboxField

import { Button, TextField } from '@axa-fr/cypress-component';

export enum CountriesEnum = {
    France,
    Other
}

export type CountriesType = "France" | "Other";

export const SettingsPage = {
    // Here we use an enum
    country: RadioField<CountriesEnum>({ selector: '.form-field', contains: 'Country' }),
    // But you can also use a type
    country2: RadioField<CountriesType>({ selector: '.form-field', contains: 'Country' }),
    CGU: Checkbox({ selector: '#CGU-checkbox' }),
    updateButton: Button({ selector: '.submit', contains: 'Update' }),
    // ...
};
import { Browser, RouteHandler } from '@axa-fr/cypress-component';
import { MyRoutesDefinition, Routes } from '../../routes-definition';
import { Countries, SettingsPage } from '../../components';

describe('Test scenario', () => {
    beforeEach(() => {
        RouteHandler.configure(RouteDefinitions);

        Browser.visit('https://example.com/settings');
    });
    it('should update settings', () => {
        RouteHandler.wait(Routes.GETsettings);

        SettingsPage.country.set(Countries.France);
        SettingsPage.country2.set('France');

        SettingsPage.CGU.check();
        SettingsPage.updateButton.click();

        RouteHandler.wait(Routes.PUTsettings);
    });
});
  • bindComponents: pour créer une hierarchie au seins de vos composants

bindComponents est un fonctione qui vous permet de lier un composant parent avec des enfants.

import { Button, TextField } from '@axa-fr/cypress-component';

export const SettingsPage = bindComponents(HtmlElement('#settings', {
    country: RadioField<"France" | "Other">({ selector: '.form-field', contains: 'Country' }),
    CGU: Checkbox({ selector: '#CGU-checkbox' }),
    updateButton: Button({ selector: '.submit', contains: 'Update' }),
    // ...
});
import { Browser, RouteHandler } from '@axa-fr/cypress-component';
import { MyRoutesDefinition, Routes } from '../../routes-definition';
import { Countries, SettingsPage } from '../../components';

describe('Test scenario', () => {
    beforeEach(() => {
        RouteHandler.configure(RouteDefinitions);

        Browser.visit('https://example.com/settings');
    });
    it('should update settings', () => {
        RouteHandler.wait(Routes.GETsettings);

        SettingsPage.should((page) => expect(page).to.be.visible);

        SettingsPage.CGU.check();
        SettingsPage.updateButton.click();

        RouteHandler.wait(Routes.PUTsettings);
    });
});