Probar aplicaciones de lienzo

Las aplicaciones de lienzo se ejecutan dentro de un iframe dentro del reproductor de Power Apps. En esta guía se explica cómo iniciar una aplicación canvas, definir el ámbito de los selectores al marco correcto e interactuar con los controles utilizando atributos de data-control-name.

Cómo funcionan las pruebas de aplicaciones canvas

Cuando una aplicación de lienzo se carga en modo de reproducción, el tiempo de ejecución hospeda la aplicación dentro de un iframe.

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

Todos los controles dentro de la aplicación tienen un atributo data-control-name que coincide con el nombre de control establecido en Power Apps Studio. Los elementos de la galería tienen data-control-part="gallery-item".

Antes de interactuar con los controles, limite todos los localizadores a este marco:

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

Lanzar una aplicación de lienzo

Use AppProvider para iniciar la aplicación y obtener el CanvasAppPage objeto :

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

Sugerencia

Al establecer skipMakerPortal: true y proporcionar una directUrl, se ahorran de 10 a 20 segundos por prueba al omitir la navegación de Power Apps.

Espere a que la aplicación se cargue.

Después del inicio, espere a que aparezca un control conocido antes de interactuar:

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

Nota:

Las aplicaciones de lienzo respaldadas por Dataverse pueden tardar entre 30 y 60 segundos en cargar datos en una galería. Use un tiempo de espera de 60 segundos para los selectores de galería.

Interacción con controles

En los ejemplos siguientes se muestra cómo interactuar con controles comunes de la aplicación de tipo canvas mediante localizadores con alcance de marco.

Haga clic en un botón

Busque un botón por su data-control-name atributo, espere a que esté visible y, a continuación, haga clic en él.

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

Rellenar una entrada de texto

Utiliza el fill() método para establecer el valor de una entrada de texto dirigiéndolo por su aria-label.

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

Filtre los elementos de la galería por su contenido de texto mostrado para buscar y hacer clic en un registro específico.

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

Use el count() método para comprobar que la galería contiene el número esperado de elementos.

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

Creación de un objeto de página para la aplicación de lienzo

Para mantener el mantenimiento, encapsula selectores y acciones en una clase Page Object:

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

Ejemplo completo de prueba CRUD para apps de canvas

En este ejemplo se combina el inicio de la aplicación, la comprobación de la galería y la interacción de formularios en un conjunto de pruebas completo.

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

Detección de nombres de control en aplicaciones de lienzo

Para buscar los data-control-name valores en la aplicación:

  1. Abra la aplicación en modo de reproducción en un explorador.
  2. Abra las herramientas de desarrollo del explorador (F12).
  3. Utiliza el Inspector para pasar el cursor por encima de los controles y para buscar atributos data-control-name.

Como alternativa, use el servidor MCP de Playwright para pedir a un asistente de IA que inspeccione el DOM y genere selectores automáticamente. Consulte Pruebas asistidas por IA.

Pasos siguientes

Consulte también