Freigeben über


Canvas-Apps testen

Canvas-Apps werden innerhalb eines iframe innerhalb des Power Apps Players ausgeführt. In diesem Leitfaden wird erläutert, wie Sie eine Canvas-App starten, Ihre Selektoren auf den richtigen Frame beschränken und mithilfe von Attributen mit data-control-name Steuerelementen interagieren.

Funktionsweise von Canvas-App-Tests

Wenn eine Canvas-App im Wiedergabemodus geladen wird, stellt die Laufzeit die App in einer iframe bereit.

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

Alle Steuerelemente in der App verfügen über ein data-control-name-Attribut, das dem steuerelementnamen entspricht, den Sie in Power Apps Studio festgelegt haben. Galerieelemente verfügen über data-control-part="gallery-item".

Sie können alle Locators auf diesen Frame beschränken, bevor Sie mit Steuerelementen interagieren:

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

Starten einer Canvas-App

Verwenden Sie AppProvider, um die App zu starten und das CanvasAppPage Objekt zu erhalten.

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,
  });
});

Tipp

Das Festlegen von skipMakerPortal: true und Bereitstellen eines directUrl spart 10 bis 20 Sekunden pro Test, indem die Navigation in Power Apps umgangen wird.

Warten, bis die App geladen wird

Warten Sie nach dem Start, bis ein bekanntes Steuerelement angezeigt wird, bevor Sie interagieren:

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

Hinweis

Canvas-Apps, die von Dataverse unterstützt werden, können 30 bis 60 Sekunden dauern, um Daten in einen Katalog zu laden. Verwenden Sie ein 60-Sekunden-Timeout für Galerie-Auswähler.

Interagieren mit Steuerelementen

Die folgenden Beispiele zeigen, wie mit Steuerelementen von Canvas-Apps mithilfe von Rahmenbereich-Lokatoren interagiert wird.

Klicken Sie auf eine Schaltfläche

Suchen Sie eine Schaltfläche anhand ihres data-control-name Attributs, warten Sie, bis sie sichtbar ist, und klicken Sie dann darauf.

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

Ausfüllen einer Texteingabe

Verwenden Sie die fill() Methode, um den Wert einer Texteingabe festzulegen, indem Sie sie über deren aria-label ansprechen.

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

Filtern Sie Katalogelemente nach ihren angezeigten Textinhalten, um nach einem bestimmten Datensatz zu suchen und darauf zu klicken.

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

Verwenden Sie die count() Methode, um zu überprüfen, ob der Katalog die erwartete Anzahl von Elementen enthält.

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

Erstellen eines Seitenobjekts für Ihre Canvas-App

Um die Wartung zu gewährleisten, kapseln Sie Selektoren und Aktionen in einer Page Object-Klasse:

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

Vollständiges CRUD-Testbeispiel für Canvas-Apps

In diesem Beispiel werden app-Start, Katalogüberprüfung und Formularinteraktion in einer vollständigen Testsuite kombiniert.

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

Ermitteln von Steuerelementnamen in Canvas-Apps

So suchen Sie die data-control-name Werte in Ihrer App:

  1. Öffnen Sie die App im Wiedergabemodus in einem Browser.
  2. Öffnen Sie Browserentwicklertools (F12).
  3. Verwenden Sie den Inspektor , um mit dem Mauszeiger auf Steuerelemente zu zeigen und nach data-control-name Attributen zu suchen.

Alternativ können Sie den Playwright MCP-Server verwenden, um einen KI-Assistenten zu bitten, das DOM zu prüfen und Selektoren für Sie zu generieren. Siehe KI-unterstützte Tests.

Nächste Schritte

Siehe auch