コンテンツにスキップ
アカウントを作成
または
サインイン
Stripe ドキュメントのロゴ
/
AI に質問する
アカウントを作成
サインイン
始める
支払い
売上
プラットフォームおよびマーケットプレイス
資金管理
開発者向けのツール
概要
バージョン管理
変更ログ
API バージョンのアップグレード
SDK バージョンをアップグレードする
開発者向けのツール
SDK
API
テスト
ワークベンチ
イベントの送信先
ワークフロー
Stripe CLI
Stripe Shell
開発者ダッシュボード
エージェントツールキット
LLM を使用した構築Visual Studio Code をご利用の場合Stripe 健全性アラートファイルのアップロード
セキュリティとプライバシー
セキュリティ
プライバシー
Stripe を拡張する
Stripe Apps
    概要
    始める
    アプリを作成する
    Stripe アプリの仕組み
    サンプルアプリ
    アプリを構築する
    シークレットを保存
    API 認証方法
    認証フロー
    サーバー側のロジック
    イベントのリッスン
    さまざまな環境を処理
    サンドボックスのサポートを有効にする
    アプリの設定ページ
    UI を構築する
      UI Extensions の仕組み
      UI テスト
      開発者向けのツール
      アプリのデザイン
      アプリのスタイル設定
      Stripe の UI 拡張機能 SDK をアップグレード
    アカウント登録
    アプリを配布する
    配布オプション
    アプリをアップロード
    バージョンとリリース
    アプリをテストする
    アプリを公開する
    自分のアプリを宣伝する
    ディープリンクを追加する
    インストールリンクを作成
    UI 拡張機能で役割を割り当て
    インストール後のアクション
    アプリのアナリティクス
    アプリの埋め込みコンポーネント
    サードパーティーの Stripe アプリを埋め込む
    Stripe Apps に移行
    拡張機能を移行または構築
    Stripe Apps または Stripe Connect にプラグインを移行
    参照情報
    アプリマニフェスト
    CLI
    拡張 SDK
    権限
    ビューポート
    設計パターン
    コンポーネント
Stripe のコネクター
パートナー
Partner Ecosystem
パートナー認定
ホーム開発者向けのツールStripe AppsBuild a UI

UI テスト

一連のユーティリティーとヘルパーを使用して Stripe アプリ UI をテストします。

ページをコピー

Extension SDK には、アプリのユーザーインターフェイスのユニットテストを作成するための一連のツールが組み込まれています。Jest を使用してテストを実行することをお勧めします。また、アサーションを作成できるように、Jest カスタムマッチャーが組み込まれています。

概念の概要

Stripe アプリの UI をテストする場合、ドキュメントオブジェクトモデル (DOM) ツリーを直接テストするのではなく、アプリを表示するリモートエンジンをテストします。

セキュリティー上の理由から、Stripe アプリリポジトリーの React コードは、シリアライズされ、iframe を使用して拡張機能ローダーを介して送信され、Stripe ダッシュボード内で DOM ツリーに変換されます。Extension SDK で提供されているテストツールは、リモートレンダリングエンジンと連携します。

例

この例では、クリックしたときにテキストが変わるボタン UI コンポーネントをテストします。このテストでは、ボタンを表示して、ボタンの初期テキストが正しいことを確認し、ボタンをクリックして、ボタンのテキストが変わることを確認します。

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

コンポーネントの表示

render(element: React.ReactElement)

render メソッドは、React エレメントを受け入れ、以下のプロパティーが指定されたオブジェクトを返します。

  • wrapper: render に渡されたコンポーネントのルートエレメント。
  • update: JavaScript イベントスタックがクリアされた後で解決するプロミスを返す関数。これは、API の模擬実行、プロミスの処理、useEffect などの React フックの採用や、後続のテストケースを実行する前に非同期のレンダリングの完了を確認する場合に利用できます。
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... });

エレメントのプロパティーとメソッド

ラッパーまたはその中のエレメントを処理する際は、以下のプロパティーとメソッドを使用して、状態を評価し、アプリと対話します。

children: Element<unknown>[]

エレメントの直接の子の配列を返します。

descendants: Element<unknown>[]

ツリー内でエレメントの下位にあるすべてのエレメントの配列を返します。

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

エレメントのテキスト表記を返します。debug() 出力は、options パラメーターを使用して変更できます。

  • all は、デフォルトのプロパティーのフィルタリング動作を上書きして、出力にすべてのプロパティーを組み込みます。debug() では、デフォルトの場合、className、aria-*、および data-* の各プロパティーが省略されます。
  • depth は、出力される子の数を定義します。デフォルトでは、すべての子が出力されます。
  • verbosity は、非スカラープロパティーの拡張のレベルを定義します。デフォルト値の 1 は、オブジェクトを 1 レベルの深さで拡張します。

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

React act() ブロックのコンテキストでアクションを実行します。通常は、(act() を内部的に使用する) update() を使用して非同期イベントを処理できます。ただし、コードでタイマー (setTimeout、setInterval、clearTimeout、clearInterval) を使用していて、模擬のタイマーを使用する場合などには、act() を直接呼び出す必要があります。模擬のタイマーを使用する場合、テスト間で模擬をリセットまたはクリーンアップする必要があります (Jest では、runOnlyPendingTimers() と useRealTimers() を呼び出します)。そうしないと、タイマーを使用するライブラリコードは適切に機能しません。

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

type が一致する子孫エレメントを検出します。type はコンポーネントです。一致するエレメントが検出されない場合は、null が返されます。一致が検出された場合、返されるエレメントには正しいプロパティーがタイプ付けされます。これは、React ツリーをナビゲートする際のタイプの安全性の保護に非常に優れています。

2 番目の props 引数が渡される場合、props が一致する type の最初のエレメントを検出します。

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

findX メソッドのいずれかを使用すると、保存されている結果はすぐに無効になり、コンポーネントに対する以降の更新は反映されないことに注意してください。以下に例を示します。

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

find と似ていますが、すべての一致を配列として返します。

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

渡された関数と一致する最初の子孫コンポーネントを検出します。関数は、一致が見つかるまで、descendants の各エレメントで呼び出されます。一致が見つからない場合は、null が返されます。

findWhere は、返されるエレメントのタイプの指定に使用できる TypeScript 引数 (省略可能) を受け入れます。汎用の引数を省略すると、返されるエレメントのプロパティーは不明です。このため、.props と .trigger を呼び出すと、タイプエラーが発生しますが、これはそれらの関数がエレメントで有効なプロパティーを認識できないためです。

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

findWhere と似ていますが、すべての一致を配列として返します。

is(type: Type): boolean

コンポーネントタイプが渡されたタイプと一致するかどうかを示すブール値を返します。この関数はタイプ保護としても機能するため、props などの値に対する後続の呼び出しは、渡されたコンポーネントのプロパティータイプとしてタイプ付けされます。

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]

渡されたプロパティー名の現在の値を返します。

props: Props

エレメントのすべてのプロパティー。

text: string

エレメントのテキストコンテンツ (textContent を呼び出すことで取得するストリング)。

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

コンポーネントで呼び出される関数プロパティーをシミュレートします。これは通常、効果的にテストするために重要です。コンポーネントをマウントした後、サブコンポーネントの変更をシミュレートし、生成されるツリーが予期した状態であることをアサートします。

オプションで、trigger に渡された追加の各引数が関数に渡されます。これは、コンポーネントを個別にテストする場合に役立ちます。

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

trigger() と似ていますが、ネストされたオブジェクトを参照するキーパスを指定できます。TypeScript の制限事項のため、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();

マッチャー

Extension SDK は、Jest カスタムマッチャーを提供します。これは、@stripe/ui-extension-sdk/testing のインポート時に自動的にインポートされます。

toContainComponent(type: RemoteComponentType, props?: object)

渡されたノードの子孫に、type が一致するコンポーネントが 1 つ以上存在することをアサートします。2 番目の props 引数が渡される場合は、渡されたオブジェクトとプロパティーが等しいコンポーネントで一致をさらにフィルタリングします。expect.objectContaining などの Jest の非対称マッチャーは完全にサポートされています。

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

.toContainComponent と同じですが、渡されたノード内の times が正確に一致していることをアサートします。

toHaveProps(props: object)

ノードに指定されたプロパティーがあるかどうかを検査します。

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

コンポーネントの表示用出力に、渡されたストリングがテキストコンテンツとして含まれていることを確認します (コンポーネントによって表示されるすべての DOM ノードで textContent を呼び出して取得する内容にテキストが含まれていること) 。

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

模擬のコンテキストプロパティー

アプリビューには Stripe ダッシュボードのコンテキストプロパティーが渡されます。getMockContextProps 関数を使用すると、テスト用として模擬のコンテキストプロパティーオブジェクトを生成できます。

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

デフォルトの場合、模擬のコンテキストプロパティーは、id: 'usr_1234' and email: 'user@example.com' のような標準のテスト値です。この値は、部分オブジェクトを渡すことで上書きできます。渡すオブジェクトはデフォルトオブジェクトと深くマージ (deepmerge) されるため、上書きする必要がある値を渡すだけで済みます。

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

参照情報

  • UI Extensions の仕組み
  • UI 拡張機能 SDK リファレンス
  • UI コンポーネント
このページはお役に立ちましたか。
はいいいえ
お困りのことがございましたら 、サポートにお問い合わせください。
早期アクセスプログラムにご参加ください。
変更ログをご覧ください。
ご不明な点がございましたら、お問い合わせください。
LLM ですか?llms.txt を読んでください。
Powered by Markdoc