Accéder directement au contenu
Créez un compte
ou
connecter-vous
Logo de la documentation Stripe
/
Demander à l'assistant IA
Créez un compte
Connectez-vous
Démarrer
Paiements
Revenus
Plateformes et places de marché
Gestion de fonds
Outils de développement
Aperçu
Gestion des versions
Journal des modifications
Mettre à niveau votre version de l'API
Actualiser votre version du SDK
Outils de développement
SDK
API
Tests
Workbench
Destinations d'événements
Workflows
CLI Stripe
Shell Stripe
Dashboard des développeurs
Boîte à outils des agents
Intégrer des LLMStripe pour Visual Studio CodeAlertes d'intégrité de StripeChargements de fichiers
Sécurité et confidentialité
Sécurité
Confidentialité
Extensions Stripe
Stripe Apps
    Présentation
    Démarrer
    Créer une application
    Fonctionnement de Stripe Apps
    Exemples d'application
    Créer une application
    Enregistrer des clés secrètes
    Méthodes d'authentification de l'API
    Flux d'autorisation
    Logique côté serveur
    Écouter les événements
    Gérer différents modes
    Activer la prise en charge de l'environnement de test
    Page des paramètres d'application
    Concevoir une interface utilisateur
      Fonctionnement des extensions d'interface utilisateur
      Test de l'interface utilisateur
      Outils de développement
      Concevoir votre application
      Styliser votre application
      Effectuer la mise à niveau du SDK d'extension de l'interface utilisateur de Stripe
    Inscription des utilisateurs
    Distribuer votre application
    Options de distribution
    Charger votre application
    Versions
    Tester votre application
    Publier votre application
    Faire la promotion de votre application
    Ajouter des liens profonds
    Créer des liens d'installation
    Assigner des rôles dans les extensions d'interface utilisateur
    Actions post-installation
    Analyses de l'application
    Composants intégrés pour les applications
    Intégrer des applications tierces conçues pour Stripe
    Migrer vers Stripe Apps
    Migrer ou développer une extension
    Migrer un plugin vers Stripe Apps ou Stripe Connect
    Référence
    Manifeste de l'application
    Interface de ligne de commande
    SDK d'extension
    Autorisations
    Fenêtres d'affichage
    Modèles de conception
    Composants
Connecteurs Stripe
Partenaires
Partner ecosystem
Certification des partenaires
AccueilOutils de développementStripe AppsBuild a UI

Test de l'interface utilisateur

Testez l'interface utilisateur de votre application avec un ensemble d'utilitaires et d'outils d'aide.

Copier la page

Le SDK Extension inclut un ensemble d’outils pour écrire des tests unitaires pour l’interface utilisateur de votre application. Nous recommandons d’exécuter les tests avec Jest et d’inclure les comparateurs Jest personnalisés pour faciliter l’écriture des assertions.

Présentation du concept

Lorsque vous testez l’interface utilisateur de votre application Stripe, pour le rendu, vous utilisez un moteur distant et non pas directement l’arbre Document Object Model (DOM).

Pour des questions de sécurité, le code React qui se trouve dans le dépôt de votre application Stripe est sérialisé, envoyé via un chargeur d’extension à l’aide d’un iframe et traduit en un arbre DOM dans le Dashboard Stripe. Les outils de test fournis par le SDK fonctionnent avec le moteur de rendu distant.

Exemple

Cet exemple teste un composant d’interface utilisateur de type bouton dont le texte change après un clic. Pour le test, nous affichons le bouton, vérifions que son texte initial est correct, cliquons dessus et vérifions que son texte a changé.

// App.tsx import {useState} from 'react'; import {ContextView, Button} from '@stripe/ui-extension-sdk/ui'; const App = () => { const [isPressed, setIsPressed] = useState(false); return ( <ContextView title="Hello world"> <Button onPress={() => setIsPressed(true)}> {isPressed ? 'You pressed me!' : 'Press me'} </Button> </ContextView> ); }; export default App; // App.test.tsx import {render} from '@stripe/ui-extension-sdk/testing'; import {Button} from '@stripe/ui-extension-sdk/ui'; import App from './App'; describe('App', () => { it('changes button text when pressed', async () => { const {wrapper, update} = render(<App />); // Expect that the initial text is correct expect(wrapper.find(Button)).toContainText('Press me'); // Press the button wrapper.find(Button)!.trigger('onPress'); // This is needed if the "onPress" handler involves something asyncronous // like a promise or a React useEffect hook await update(); // Expect that the text changed expect(wrapper.find(Button)).toContainText('You pressed me!'); }); });

Rendu d’un composant

render(element: React.ReactElement)

La méthode render accepte un élément React et renvoie un objet avec les propriétés suivantes :

  • wrapper : l’élément racine du composant transmis à render.
  • update : fonction qui renvoie une promesse résolue une fois que la suite d’événements JavaScript est exécutée. Elle est utile pour la simulation d’API, pour le traitement de promesses, pour l’utilisation de hooks React tels que useEffect, ou encore pour s’assurer que l’affichage asynchrone soit terminé avant d’exécuter les cas de test ultérieurs.
import {render} from '@stripe/ui-extension-sdk/testing'; import App from './App'; it('contains a Button', async () => { const {wrapper, update} = render(<App />); await update(); // Continue testing... });

Propriétés et méthodes d’élément

Lorsque vous travaillez avec le wrapper ou n’importe quel élément inclus dans celui-ci, utilisez les propriétés et méthodes suivantes pour déterminer l’état et interagir avec votre application :

children: Element<unknown>[]

Renvoie un tableau contenant les enfants directs de l’élément.

descendants: Element<unknown>[]

Renvoie un tableau contenant tous les éléments se trouvant sous l’élément dans l’arbre.

debug(options?: {all?: boolean, depth?: number, verbosity?: number}): string

Renvoie une représentation textuelle de l’élément. Vous pouvez modifier le résultat de debug() à l’aide du paramètre options.

  • all remplace le comportement de filtrage des propriétés par défaut et inclut à la place toutes les propriétés dans le résultat. Par défaut, les propriétés className, aria-* et data-* sont omises par debug().
  • depth définit le nombre d’enfants affichés. Par défaut, tous les enfants sont affichés.
  • verbosity définit le niveau d’expansion des propriétés non-scalaires. La valeur par défaut de 1 étend les objets à une profondeur d’un niveau.

act<T>(action: () => T): T

Effectue une action dans le contexte d’un bloc act() React. En règle générale, vous pouvez utiliser update() (qui utilise act() en interne) pour gérer les événements asynchrones. Toutefois, il peut arriver que vous deviez appeler directement act(). Cela peut être le cas lorsque votre code utilise un système de décompte (setTimeout, setInterval, clearTimeout, clearInterval) et que vous souhaitez le tester à l’aide de chronomètres fictifs. Lorsque vous utilisez ces chronomètres, vous devez les réinitialiser ou les nettoyer entre chaque test (dans jest, cela consiste à appeler runOnlyPendingTimers() et useRealTimers()), faute de quoi le code de la bibliothèque qui utilise des chronomètres ne pourra pas fonctionner correctement.

find(type: Type, props?: Partial<PropsForComponent<Type>>): Element<PropsForComponent<Type>> | null

Trouve un élément descendant qui correspond à type, où type est un composant. Si aucun élément correspondant n’est trouvé, null est renvoyé. Si une correspondance est trouvée, l’élément renvoyé prend le typage de propriété correct, ce qui est un excellent moyen de garantir la sûreté du typage lors de la navigation dans l’arbre React.

Si le deuxième argument props est transmis, il trouve le premier élément type avec les props correspondantes.

// App.tsx import {Button, ContextView} from '@stripe/ui-extension-sdk/ui'; const App = () => ( <ContextView title="Hello world"> <Button href="http://bad.example.com">Do not press me</Button> <Button href="http://example.com">Press me</Button> </ContextView> ); export default App; // App.test.tsx import {render} from '@stripe/ui-extension-sdk/testing'; import {Button} from '@stripe/ui-extension-sdk/ui'; import App from './App'; it('contains a Button with text', () => { const {wrapper} = render(<App />); const button = wrapper.find(Button, {href: 'http://example.com'}); expect(button).toContainText('Press me'); });

N’oubliez pas que lorsque vous utilisez l’une des méthodes findX les résultats enregistrés sont immédiatement obsolètes, et les mises à jour ultérieures du composant ne sont pas prises en compte. Par exemple :

// Bad - this will not work const button = wrapper.find(Button); expect(button).toContainText('Press me'); button!.trigger('onPress'); expect(button).toContainText('You pressed me!'); // button still contains 'Press me' // Good - this will work expect(wrapper.find(Button)).toContainText('Press me'); wrapper.find(Button)!.trigger('onPress'); expect(wrapper.find(Button)).toContainText('You pressed me!');

findAll(type: Type, props?: Partial<PropsForComponent<Type>>): Element<PropsForComponent<Type>>[]

Comme find, mais renvoie toutes les correspondances dans un tableau.

findWhere<Type = unknown>(predicate: (element: Element<unknown>) => boolean): Element<PropsForComponent<Type>> | null

Trouve le premier composant descendant correspondant à la fonction transmise. La fonction est appelée avec chaque élément depuis descendants jusqu’à ce qu’une correspondance soit trouvée. Si aucune correspondance n’est trouvée, null est renvoyé.

findWhere accepte un argument TypeScript facultatif que vous pouvez utiliser pour spécifier le type de l’élément renvoyé. Si vous omettez l’argument générique, l’élément renvoyé a des propriétés inconnues. Par conséquent, appeler .props et .trigger sur cet élément génère des erreurs de type, puisque ces fonctions ne savent pas quelles propriétés sont valides sur votre élément :

// App.tsx import {Button, ContextView} from '@stripe/ui-extension-sdk/ui'; const App = () => ( <ContextView title="Hello world"> <Button href="http://example.com">Press me</Button> </ContextView> ); export default App; // App.test.tsx import {render} from '@stripe/ui-extension-sdk/testing'; import {Button} from '@stripe/ui-extension-sdk/ui'; import App from './App'; it('contains a Button with a href', () => { const {wrapper} = render(<App />); const button = wrapper.findWhere<typeof Button>( (node) => node.is(Button) && node.prop('href').startsWith('http://example'), ); expect(button).toContainText('Press me'); });

findAllWhere<Type = unknown>(predicate: (element: Element<unknown>) => boolean): Element<PropsForComponent<Type>>[]

Comme findWhere, mais renvoie toutes les correspondances dans un tableau.

is(type: Type): boolean

Renvoie un booléen indiquant si le type du composant correspond au type transmis. Cette fonction sert également de garde de type afin que les appels suivants à des valeurs telles que props soient du même type que la propriété du composant transmis.

import {Button} from '@stripe/ui-extension-sdk/ui'; // If we omit element.is here, we would not know whether 'href' was a valid prop and Typescript // would throw an error. if (element.is(Button) && element.prop('href') === 'http://example.com') { // ... }

prop<K extends keyof Props>(key: K): Props[K]

Renvoie la valeur actuelle du nom de propriété transmis.

props: Props

Toutes les propriétés de l’élément.

text: string

Le contenu textuel de l’élément (c’est-à-dire la chaîne que vous obtiendriez en appelant textContent).

trigger<K extends FunctionKeys<Props>>(prop: K, …args: Arguments<Props<K>>): ReturnType<Props<K>>

Simule une propriété de fonction appelée sur votre composant. Généralement, c’est la clé d’un test efficace. Une fois que vous avez monté votre composant, vous simulez une modification dans un sous-composant et assertez que l’arbre qui en résulte est à l’état attendu.

De manière facultative, chaque argument supplémentaire transmis à trigger est transmis à la fonction. Utile pour tester des composants isolés.

// App.tsx import {useState} from 'react'; import {ContextView, Button} from '@stripe/ui-extension-sdk/ui'; const App = () => { const [buttonText, setButtonText] = useState<string>('Press me'); return ( <ContextView title="Hello world"> <Button onPress={() => setButtonText('You pressed me!')}> {buttonText} </Button> </ContextView> ); }; export default App; // App.test.tsx import {render} from '@stripe/ui-extension-sdk/testing'; import {Button} from '@stripe/ui-extension-sdk/ui'; import App from './App'; describe('App', () => { it('changes button text when pressed', () => { const {wrapper} = render(<App />); expect(wrapper.find(Button)).toContainText('Press me'); // Press the button wrapper.find(Button)!.trigger('onPress', 'You pressed me!'); // Expect that the text changed expect(wrapper.find(Button)).toContainText('You pressed me!'); }); });

triggerKeypath<T>(keypath: string, …args: any[]): T

Semblable à trigger(), mais vous permet de fournir un keypath référençant des objets imbriqués. Sachez qu’en raison de limitations propres à TypeScript, il n’est pas possible d’obtenir une sûreté de typage du même ordre que celle garantie par trigger.

const App = ({action}: {action: {onAction(): void; label: string}}) => ( <Button type="button" onPress={action.onAction}> {action.label} </Button> ); const spy = jest.fn(); const app = mount( <App action={{label: 'Hi', onAction: spy}} />, ); app.triggerKeypath('action.onAction'); expect(spy).toHaveBeenCalled();

Comparateurs

Le SDK Extension fournit des comparateurs Jest personnalisés. Ils sont automatiquement importés lorsque vous importez @stripe/ui-extension-sdk/testing.

toContainComponent(type: RemoteComponentType, props?: object)

Asserte qu’au moins un composant correspondant à type figure dans les descendants du nœud transmis. Si le deuxième argument props est transmis, filtre également les correspondances en fonction des composants dont les propriétés sont égales à l’objet transmis. Les comparateurs Jest asymétriques tels que expect.objectContaining sont entièrement pris en charge.

// App.tsx import {Button, ContextView} from '@stripe/ui-extension-sdk/ui'; const App = () => ( <ContextView title="Hello world"> <Button onPress={() => console.log('You pressed me!')}>Press me</Button> </ContextView> ); export default App; // App.test.tsx import {render} from '@stripe/ui-extension-sdk/testing'; import {Button} from '@stripe/ui-extension-sdk/ui'; import App from './App'; it('contains a Button', () => { const {wrapper} = render(<App />); expect(wrapper).toContainComponent(Button, { onPress: expect.any(Function), }); });

toContainComponentTimes(type: RemoteComponentType, times: number, props?: object)

Identique à .toContainComponent, mais asserte qu’il y a exactement times correspondance dans le nœud transmis.

toHaveProps(props: object)

Vérifie si le nœud contient les propriétés spécifiées.

// App.tsx import {Button, ContextView} from '@stripe/ui-extension-sdk/ui'; const App = () => ( <ContextView title="Hello world"> <Button onPress={() => console.log('You pressed me!')}>Press me</Button> </ContextView> ); export default App; // App.test.tsx import {render} from '@stripe/ui-extension-sdk/testing'; import {Button} from '@stripe/ui-extension-sdk/ui'; import App from './App'; it('contains a Button with an onPress function', () => { const {wrapper} = render(<App />); expect(wrapper.find(Button)).toHaveProps({ onPress: expect.any(Function), }); });

toContainText(text: string)

Vérifie que le résultat affiché du composant contient la chaîne transmise en tant que contenu textuel (autrement dit que le texte est inclus dans le résultat que vous obtiendriez en appelant textContent sur tous les nœuds DOM affichés par le composant).

// App.tsx import {Button, ContextView} from '@stripe/ui-extension-sdk/ui'; const App = () => ( <ContextView title="Hello world"> <Button>Press me</Button> </ContextView> ); export default App; // App.test.tsx import {render} from '@stripe/ui-extension-sdk/testing'; import {Button} from '@stripe/ui-extension-sdk/ui'; import App from './App'; it('contains a Button with an onPress function', () => { const {wrapper} = render(<App />); expect(wrapper.find(Button)).toContainText('Press me'); });

Propriétés de contexte fictives

Les vues de l’application sont transmises en tant que propriétés de contexte dans le Dashboard Stripe. Vous pouvez générer un objet de propriétés de contexte fictif pour vos tests avec la fonction getMockContextProps.

import {getMockContextProps} from '@stripe/ui-extension-sdk/testing'; const context = getMockContextProps(); const {wrapper} = render(<App {...context} />);

Par défaut, les propriétés de contexte fictives sont des valeurs de test standard comme id: 'usr_1234' et email: 'user@example.com'. Vous pouvez remplacer ces valeurs en transmettant un objet partiel. L’objet que vous transmettez est fusionné avec l’objet par défaut (en fusion profonde). Ainsi, vous avez seulement besoin de transmettre les valeurs que vous souhaitez remplacer.

import {getMockContextProps} from '@stripe/ui-extension-sdk/testing'; const context = getMockContextProps({ environment: { objectContext: { id: 'inv_1234', object: 'invoice', }, }, }); const {wrapper} = render(<App {...context} />);

Voir aussi

  • Fonctionnement des extensions d’interface utilisateur
  • Documentation relative au SDK de l’extension d’interface utilisateur
  • Composants d’interface utilisateur
Cette page vous a-t-elle été utile ?
OuiNon
Besoin d'aide ? Contactez le service Support.
Rejoignez notre programme d'accès anticipé.
Consultez notre log des modifications.
Des questions ? Contactez l'équipe commerciale.
LLM ? Lire llms.txt.
Propulsé par Markdoc