次の方法で共有


キャンバス アプリをテストする

キャンバス アプリは、Power Apps プレーヤー内の iframe 内で実行されます。 このガイドでは、キャンバス アプリを起動し、セレクターのスコープを適切なフレームに設定し、 data-control-name 属性を使用してコントロールを操作する方法について説明します。

キャンバス アプリのテストのしくみ

キャンバス アプリが再生モードで読み込まれると、ランタイムは iframe内でアプリをホストします。

iframe[name="fullscreen-app-host"]

アプリ内のすべてのコントロールには、Power Apps Studio で設定したコントロール名と一致する data-control-name 属性があります。 ギャラリーアイテムには data-control-part="gallery-item"があります。

コントロールを操作する前に、すべてのロケーターのスコープをこのフレームに設定します。

const canvasFrame = page.frameLocator('iframe[name="fullscreen-app-host"]');

キャンバス アプリを起動する

AppProviderを使用してアプリを起動し、CanvasAppPage オブジェクトを取得します。

import { test, expect } from '@playwright/test';
import {
  AppProvider,
  AppType,
  AppLaunchMode,
  buildCanvasAppUrlFromEnv,
} from 'power-platform-playwright-toolkit';

const CANVAS_APP_URL = buildCanvasAppUrlFromEnv();

test.beforeEach(async ({ page, context }) => {
  const app = new AppProvider(page, context);

  await app.launch({
    app: 'Northwind Orders',
    type: AppType.Canvas,
    mode: AppLaunchMode.Play,
    skipMakerPortal: true,   // bypasses Power Apps navigation
    directUrl: CANVAS_APP_URL,
  });
});

ヒント

skipMakerPortal: trueを設定し、directUrlを指定すると、Power Appsナビゲーションをバイパスすることで、テストごとに 10 秒から 20 秒を節約できます。

アプリが読み込まれるのを待つ

起動後、次の操作を行う前に、既知のコントロールが表示されるのを待ちます。

const canvasFrame = page.frameLocator('iframe[name="fullscreen-app-host"]');

// Wait for gallery to confirm the app is loaded and data is present
await canvasFrame
  .locator('[data-control-name="Gallery1"] [data-control-part="gallery-item"]')
  .first()
  .waitFor({ state: 'visible', timeout: 60000 });

Dataverse によってサポートされるキャンバス アプリは、ギャラリーにデータを読み込むのに 30 ~ 60 秒かかる場合があります。 ギャラリー セレクターには 60 秒のタイムアウトを使用します。

コントロールを操作する

次の例では、フレーム スコープ ロケーターを使用して、一般的なキャンバス アプリ コントロールを操作する方法を示します。

ボタンをクリックする

data-control-name属性でボタンを探し、ボタンが表示されるまで待ってからクリックします。

const addButton = canvasFrame.locator('[data-control-name="icon3"]');
await addButton.waitFor({ state: 'visible', timeout: 10000 });
await addButton.click();

テキスト入力欄に入力する

fill() メソッドを使用して、テキスト入力の値を設定し、そのaria-labelをターゲットにします。

const orderNumberInput = canvasFrame.locator('input[aria-label="Order Number"]');
await orderNumberInput.fill('ORD-12345');

表示されたテキスト コンテンツでギャラリー 項目をフィルター処理し、特定のレコードを検索してクリックします。

const galleryItem = canvasFrame
  .locator('[data-control-part="gallery-item"]')
  .filter({ has: canvasFrame.locator('[data-control-name="Title1"]').getByText('Order 001') });

await galleryItem.waitFor({ state: 'visible' });
await galleryItem.click();

count() メソッドを使用して、ギャラリーに予想される項目数が含まれていることを確認します。

const galleryItems = canvasFrame.locator('[data-control-name="Gallery1"] [data-control-part="gallery-item"]');
const count = await galleryItems.count();
expect(count).toBeGreaterThan(0);

キャンバス アプリのページ オブジェクトを作成する

保守性を確保するために、Page オブジェクト クラスにセレクターとアクションをカプセル化します。

// pages/my-app/MyCanvasAppPage.ts
import { Page, FrameLocator } from '@playwright/test';

export class MyCanvasAppPage {
  private readonly frame: FrameLocator;

  constructor(private readonly page: Page) {
    this.frame = page.frameLocator('iframe[name="fullscreen-app-host"]');
  }

  get addButton() {
    return this.frame.locator('[data-control-name="AddButton"]');
  }

  get gallery() {
    return this.frame.locator('[data-control-name="Gallery1"]');
  }

  async waitForLoad(): Promise<void> {
    await this.gallery
      .locator('[data-control-part="gallery-item"]')
      .first()
      .waitFor({ state: 'visible', timeout: 60000 });
  }

  async clickAdd(): Promise<void> {
    await this.addButton.click();
  }

  async getItemCount(): Promise<number> {
    return this.gallery.locator('[data-control-part="gallery-item"]').count();
  }
}

キャンバス アプリの完全な CRUD テストの例

この例では、アプリの起動、ギャラリーの検証、フォームの操作を完全なテスト スイートに組み合わせます。

import { test, expect, FrameLocator } from '@playwright/test';
import { AppProvider, AppType, AppLaunchMode, buildCanvasAppUrlFromEnv } from 'power-platform-playwright-toolkit';

const CANVAS_APP_URL = buildCanvasAppUrlFromEnv();

test.describe('Canvas App - Orders', () => {
  let canvasFrame: FrameLocator;

  test.beforeEach(async ({ page, context }) => {
    const app = new AppProvider(page, context);
    await app.launch({
      app: 'Orders App',
      type: AppType.Canvas,
      mode: AppLaunchMode.Play,
      skipMakerPortal: true,
      directUrl: CANVAS_APP_URL,
    });

    canvasFrame = page.frameLocator('iframe[name="fullscreen-app-host"]');
    await canvasFrame
      .locator('[data-control-part="gallery-item"]')
      .first()
      .waitFor({ state: 'visible', timeout: 60000 });
  });

  test('should display orders in gallery', async () => {
    const count = await canvasFrame
      .locator('[data-control-part="gallery-item"]')
      .count();
    expect(count).toBeGreaterThan(0);
  });

  test('should click Add and show form', async ({ page }) => {
    await canvasFrame.locator('[data-control-name="icon3"]').click();
    await page.waitForTimeout(2000);

    const input = canvasFrame.locator('input[type="text"]').first();
    await expect(input).toBeVisible();
  });
});

キャンバス アプリでコントロール名を検出する

アプリで data-control-name 値を検索するには:

  1. ブラウザーで再生モードでアプリを開きます。
  2. ブラウザー開発者ツールを開きます (F12)。
  3. インスペクターを使用してコントロールにカーソルを合わせ、data-control-name属性を探します。

または、Playwright MCP サーバーを使用して、AI アシスタントに DOM の検査とセレクターの生成を依頼します。 AI 支援テストを参照してください。

次のステップ

こちらも参照ください