Weiter zum Inhalt
Konto erstellen
oder
anmelden
Das Logo der Stripe-Dokumentation
/
KI fragen
Konto erstellen
Anmelden
Jetzt starten
Zahlungen
Umsatz
Plattformen und Marktplätze
Geldmanagement
Entwickler-Tools
Übersicht
Versionierung
Änderungsprotokoll
Aktualisieren Sie Ihre API-Version
Ihre SDK-Version aktualisieren
Entwickler-Tools
SDKs
API
Tests
Workbench
Ereignisziele
Arbeitsabläufe
Stripe-CLI
Stripe Shell
Entwickler-Dashboard
Agent-Toolkit
Mit LLMs entwickelnStripe für Visual Studio CodeStripe-StatuswarnungenHochgeladene Dateien
Sicherheit und Datenschutz
Sicherheit
Datenschutz
Extend Stripe
Stripe-Apps
    Übersicht
    Jetzt starten
    Eine App erstellen
    Funktionsweise von Stripe-Apps
    Beispiel-Apps
    App erstellen
    Shop-Geheimnisse
    API-Authentifizierungsmethoden
    Autorisierungsabläufe
    Serverseitige Logik
    Ereignisse überwachen
    Umgang mit verschiedenen Modi
    Sandbox-Unterstützung aktivieren
    App-Einstellungsseite
    Erstellen Sie eine Nutzeroberfläche
      Funktionsweise der Erweiterungen der Nutzeroberfläche
      Benutzeroberflächen-Tests
      Entwickler-Tools
      Richten Sie Ihre App ein
      Gestalten Sie Ihre App
      Upgrade des Erweiterungs-SDK der Nutzeroberfläche von Stripe
    Onboarding
    Ihre App verbreiten
    Vertriebsmöglichkeiten
    App hochladen
    Versionen und Releases
    Ihre App testen
    Ihre App veröffentlichen
    Ihre App bewerben
    Deep-Links hinzufügen
    Installationslinks erstellen
    Rollen in Erweiterungen der Nutzeroberfläche zuweisen
    Aktionen nach der Installation
    App-Analytik
    Eingebettete Komponenten für Apps
    Stripe-Apps von Drittanbietern einbetten
    Umstellung auf Stripe Apps
    Migrieren oder Erweiterung erstellen
    Ein Plugin zu Stripe Apps oder Stripe Connect migrieren
    Verwendungszweck
    App-Manifest
    CLI
    Erweiterungs-SDK
    Berechtigungen
    Darstellungsfelder
    Entwurfsmuster
    Komponenten
Stripe Connectors
Partner
Partner-Ecosystem
Partner-Zertifizierung
StartseiteEntwickler-ToolsStripe AppsBuild a UI

Benutzeroberflächen-Tests

Testen Sie die Nutzeroberfläche Ihrer Stripe-App mit einer Reihe von Werkzeugen und Hilfsmitteln.

Seite kopieren

Das Extension SDK enthält eine Reihe von Tools zum Schreiben von Komponententests für die Nutzeroberfläche Ihrer App. Wir empfehlen die Ausführung von Tests mit Jest und binden Jest Custom Matchers ein, um das Schreiben von Assertions zu erleichtern.

Konzeptionelle Übersicht

Beim Testen der Nutzeroberfläche Ihrer Stripe-App testen Sie eine externe Engine, die Ihre App rendert, und nicht den DOM-Baum direkt.

Aus Sicherheitsgründen wird der React-Code im Repository Ihrer Stripe-App serialisiert, mithilfe eines iFrame über einen sogenannten Extension Loader übermittelt und in einen DOM-Baum innerhalb des Stripe-Dashboards übersetzt. Die vom Extension SDK bereitgestellten Test-Tools sind mit der externen Rendering-Engine kompatibel.

Beispiel

In diesem Beispiel wird eine Schaltflächen-Komponente der Nutzeroberfläche getestet, die beim Anklicken den Text ändert. Im Test wird die Schaltfläche gerendert, der ursprüngliche Text der Schaltfläche überprüft, auf die Schaltfläche geklickt und bestätigt, dass sich der Text der Schaltfläche geändert hat.

// 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!'); }); });

Eine Komponente rendern

render(element: React.ReactElement)

Die Methode render akzeptiert ein React-Element und gibt ein Objekt mit den folgenden Eigenschaften zurück:

  • wrapper: Das Wurzelelement der an render übergebenen Komponente.
  • update: Eine Funktion, die ein Promise zurückgibt, das aufgelöst wird, nachdem der JavaScript-Ereignis-Stack gelöscht wurde. Dies ist nützlich, wenn Sie APIs simulieren, mit Promises umgehen, React-Hooks wie useEffect verwenden oder sicherstellen, dass das asynchrone Rendering abgeschlossen ist, bevor nachfolgende Testfälle ausgeführt werden.
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... });

Eigenschaften und Methoden von Elementen

Verwenden Sie beim Arbeiten mit dem Wrapper oder einem darin enthaltenen Element die folgenden Eigenschaften und Methoden, um den Status zu bewerten und mit der App zu interagieren:

children: Element<unknown>[]

Gibt ein Array mit den direkten untergeordneten Elementen des Elements zurück.

descendants: Element<unknown>[]

Gibt ein Array mit allen Elementen unter dem Element in der Baumstruktur zurück.

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

Gibt eine Textdarstellung des Elements zurück. Mit dem Parameter options kann man die Ausgabe von debug() ändern.

  • all überschreibt das Standard-Eigenschaften-Filterverhalten und schließt stattdessen alle Eigenschaften in die Ausgabe ein. debug() lässt die Eigenschaften className, aria-* und data-* standardmäßig weg.
  • depth definiert die Anzahl der gedruckten untergeordneten Elemente. Alle untergeordneten Elemente werden standardmäßig gedruckt.
  • verbosity definiert die Expansionsebene für nicht skalare Eigenschaften. Der Standardwert 1 erweitert Objekte um eine Ebene tiefer.

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

Führt eine Aktion im Kontext eines React act() block aus. Normalerweise können Sie update() verwenden (wobei act() intern verwendet wird), um asynchrone Ereignisse zu verarbeiten. In einigen Fällen müssen Sie jedoch möglicherweise act() direkt aufrufen, z. B. wenn Ihr Code Timer verwendet (setTimeout, setInterval, clearTimeout, clearInterval) und Sie einen Test mit Timer-Modellen durchführen möchten. Bei Verwendung von Timer-Modellen müssen Sie die Modelle zwischen den Tests zurücksetzen oder bereinigen (d. h. runOnlyPendingTimers() und useRealTimers() aufrufen), andernfalls funktioniert Bibliothekscode, der Timer nutzt, nicht ordnungsgemäß.

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

Findet ein nachfolgendes Element, das mit type übereinstimmt, wobei type eine Komponente ist. Wird kein übereinstimmendes Element gefunden, wird null zurückgegeben. Wird indes eine Übereinstimmung gefunden, hat das zurückgegebene Element den richtigen Eigenschaftstyp, sodass beim Navigieren durch den React-Baum eine optimale Typsicherheit gewährleistet ist.

Wird das zweite props-Argument übergeben, findet es das erste Element von type mit den entsprechenden props.

// 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'); });

Dabei ist zu beachten, dass gespeicherte Ergebnisse bei Verwendung einer beliebigen findX-Methode bereits veraltet sind und zukünftige Änderungen der Komponente nicht berücksichtigt werden. Ein Beispiel:

// 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>>[]

Wie find, gibt aber alle passenden Einträge als Array zurück.

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

Findet die erste abhängige Komponente, die zur weitergegebenen Funktion passt. Die Funktion wird mit jedem Element von descendants aufgerufen, bis ein passender Eintrag gefunden wird. Wird kein passender Eintrag gefunden, wird null zurückgegeben.

findWhere akzeptiert ein optionales TypeScript-Argument, mit dem der Typ des zurückgegebenen Elements angegeben werden kann. Wird das generische Argument ausgelassen, hat das zurückgegebene Element unbekannte Eigenschaften und ein Aufruf der jeweiligen .props und .trigger verursachen Typ-Fehler, da die Funktionen nicht wissen, welche Eigenschaften für Ihr Element gültig sind:

// 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>>[]

Wie findWhere, gibt aber alle passenden Einträge als Array zurück.

is(type: Type): boolesch

Gibt einen booleschen Wert zurück, der angibt, ob der Komponententyp zum weitergegebenen Typ passt. Diese Funktion dient auch der Typsicherheit, sodass nachfolgende Aufrufe von Werten wie props als Eigenschaftstyp der weitergegebenen Komponente typisiert werden.

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]

Gibt den aktuellen Wert des weitergegebenen Eigenschaftsnamens zurück.

props: Props

Alle Eigenschaften des Elements.

text: Zeichenfolge

Der Textinhalt des Elements (also der String, der durch den Aufruf von textContent aufgerufen würde).

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

Simuliert den Aufruf einer Funktionseigenschaft für Ihre Komponente. Dadurch wird zumeist eine effiziente Testung gewährleistet. Nachdem Sie Ihre Komponente eingebunden haben, simulieren Sie eine Änderung in einer Subkomponente und überprüfen, dass der resultierende Baum sich im erwarteten Zustand befindet.

Optional wird jedes an trigger weitergegebene zusätzliche Argument der Funktion übergeben. Dies ist für die Testung von isolierten Komponenten hilfreich.

// 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

Wie trigger(), ermöglicht aber die Angabe eines Schlüsselpfads unter Angabe verschachtelter Objekte. Dabei ist zu beachten, dass die Beschränkungen in TypeScript nicht dieselbe Typsicherheit wie trigger bieten.

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();

Matchers

Der Extension SDK bietet Jest Custom-Matcher. Diese werden beim Import von @stripe/ui-extension-sdk/testing automatisch mit importiert.

toContainComponent(type: RemoteComponentType, props?: object)

Stellt sicher, dass mindestens eine zum type passende Komponente sich in den abhängigen Objekten der weitergegebenen Node befindet. Wird das zweite props-Argument weitergegeben, filtert es die passenden Einträge weiter nach Komponenten, deren Eigenschaften dem weitergegebenen Objekt entsprechen. Die asymmetrischen Matcher von Jest , wie expect.objectContaining, werden voll unterstützt.

// 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)

Identisch zu .toContainComponent, stellt aber sicher, dass sich genau times mal so viele passende Einträge in der weitergegebenen Node befinden.

toHaveProps(props: Objekt)

Prüft, ob die Node die angegebenen Eigenschaften hat.

// 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: Zeichenfolge)

Überprüft, dass der zurückgegebene Output der Komponente den weitergegebenen String als Textinhalt enthält (also dass der Text in allen durch die Komponente erzeugten DOM-Nodes enthalten ist, der durch einen Aufruf von textContent abgerufen würde).

// 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'); });

Simulierte Kontexteigenschaften

App-Ansichten sind im Stripe-Dashboard übergebene Kontexteigenschaften. Sie können eine simulierte Kontexteigenschaft zu Testzwecken mit der Funkion getMockContextProps generieren.

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

Standardmäßig sind die Eigenschaften des simulierten Kontexts Standardtestwerte wie id: 'usr_1234' und email: 'user@example.com'. Sie können diese Werte überschreiben, indem Sie ein Teilobjekt übergeben. Das von Ihnen übergebene Objekt wird mit dem Standardobjekt zusammengeführt. Sie müssen also nur die Werte übergeben, die Sie überschreiben möchten.

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

Siehe auch

  • Funktionsweise von Nutzeroberflächen-Erweiterungen
  • Dokumentation zu Erweiterungs-SDK für die Nutzeroberfläche
  • Komponenten der Nutzeroberfläche
War diese Seite hilfreich?
JaNein
Benötigen Sie Hilfe? Kontaktieren Sie den Kundensupport.
Nehmen Sie an unserem Programm für frühzeitigen Zugriff teil.
Schauen Sie sich unser Änderungsprotokoll an.
Fragen? Sales-Team kontaktieren.
LLM? Lesen Sie llms.txt.
Unterstützt von Markdoc