Merk
Tilgang til denne siden krever autorisasjon. Du kan prøve å logge på eller endre kataloger.
Tilgang til denne siden krever autorisasjon. Du kan prøve å endre kataloger.
Gen UX apps are AI-generated Power Apps created through the natural-language experience in Power Apps. They use the same canvas runtime as hand-authored canvas apps, so the same iframe-scoping and data-control-name patterns apply. The GenUxPage class provides helpers tuned for the generated control structure.
How Gen UX apps differ from canvas apps
Gen UX apps share the canvas runtime and the iframe[name="fullscreen-app-host"] host frame. The main differences are:
- Control names are autogenerated (for example,
Button1,TextInput1) and might change when you regenerate the app. - The AI prompt drives the app layout, so structure varies between apps.
- The
GenUxPageclass exposes helpers that work against semantic roles and ARIA labels rather than control names, making tests more resilient to regeneration.
Launch a Gen UX app
Use the AppProvider class to launch a Gen UX app in play mode, passing a direct URL to skip the maker portal and connect straight to the canvas runtime.
import { test, expect } from '@playwright/test';
import {
AppProvider,
AppType,
AppLaunchMode,
buildCanvasAppUrlFromEnv,
} from 'power-platform-playwright-toolkit';
const GEN_UX_APP_URL = buildCanvasAppUrlFromEnv();
test.beforeEach(async ({ page, context }) => {
const app = new AppProvider(page, context);
await app.launch({
app: 'My AI App',
type: AppType.Canvas,
mode: AppLaunchMode.Play,
skipMakerPortal: true,
directUrl: GEN_UX_APP_URL,
});
});
Tip
Use skipMakerPortal: true with directUrl to bypass Power Apps and reduce startup time by 10–20 seconds.
Scope locators to the canvas frame
Scope all interactions to the canvas iframe:
const canvasFrame = page.frameLocator('iframe[name="fullscreen-app-host"]');
Wait for the app to load
Gen UX apps can take 30–60 seconds to load Dataverse data. Wait for a known element before interacting:
// Wait for a gallery or any visible UI element
await canvasFrame
.locator('[data-control-part="gallery-item"]')
.first()
.waitFor({ state: 'visible', timeout: 60000 });
Interact with controls by ARIA label
Gen UX apps generate controls with ARIA labels derived from your prompt. Use ARIA-label selectors for resilience:
Fill a text input
Target text inputs by their aria-label attribute, which matches the Dataverse column display name, and use Playwright's fill() method to enter values.
await canvasFrame.locator('input[aria-label="Name"]').fill('Contoso Ltd');
await canvasFrame.locator('input[aria-label="Phone"]').fill('555-9000');
Click a button
Locate buttons by combining the role="button" selector with the aria-label that the AI assigned based on your prompt.
await canvasFrame.locator('[role="button"][aria-label="Save"]').click();
await canvasFrame.locator('[role="button"][aria-label="New record"]').click();
Select from a dropdown
Click the dropdown to expand its option list, then select the desired option by matching its visible text.
const dropdown = canvasFrame.locator('[aria-label="Category"]');
await dropdown.click();
await canvasFrame.locator('[role="option"]:has-text("Enterprise")').click();
Work with galleries
Gen UX galleries use the same attributes as canvas app galleries:
const gallery = canvasFrame.locator('[data-control-part="gallery-item"]');
// Count items
const count = await gallery.count();
expect(count).toBeGreaterThan(0);
// Filter by text content
const item = gallery.filter({ hasText: 'Contoso Ltd' });
await item.waitFor({ state: 'visible', timeout: 30000 });
await item.click();
Full test example: create and find a record
The following end-to-end test launches a Gen UX app, creates a new record through the form, and verifies that it appears in the gallery.
import { test, expect } from '@playwright/test';
import { AppProvider, AppType, AppLaunchMode, buildCanvasAppUrlFromEnv } from 'power-platform-playwright-toolkit';
const GEN_UX_APP_URL = buildCanvasAppUrlFromEnv();
test('should create a new record and find it in the list', async ({ page, context }) => {
const app = new AppProvider(page, context);
await app.launch({
app: 'My AI App',
type: AppType.Canvas,
mode: AppLaunchMode.Play,
skipMakerPortal: true,
directUrl: GEN_UX_APP_URL,
});
const canvasFrame = page.frameLocator('iframe[name="fullscreen-app-host"]');
// Wait for the gallery to load
await canvasFrame
.locator('[data-control-part="gallery-item"]')
.first()
.waitFor({ state: 'visible', timeout: 60000 });
// Click New record
await canvasFrame.locator('[role="button"][aria-label="New record"]').click();
// Fill the form
const accountName = `AI Test ${Date.now()}`;
await canvasFrame.locator('input[aria-label="Name"]').fill(accountName);
await canvasFrame.locator('input[aria-label="Phone"]').fill('555-1234');
// Save
await canvasFrame.locator('[role="button"][aria-label="Save"]').click();
await page.waitForTimeout(3000); // allow Dataverse write
// Verify the new record appears in the gallery
const newItem = canvasFrame
.locator('[data-control-part="gallery-item"]')
.filter({ hasText: accountName });
await expect(newItem).toBeVisible({ timeout: 30000 });
});
Discover generated control names
Gen UX control names change when you regenerate the app. To find current control names:
- Open the app in play mode in a browser.
- Open browser DevTools (F12).
- Use the Inspector to hover over a control.
- Look for
data-control-namein the element's attributes.
Tip
Prefer aria-label and role-based selectors over data-control-name for Gen UX apps. ARIA labels come from your Dataverse column display names and don't change when you regenerate the app.
Authentication
Gen UX apps use the Power Apps domain. Use the standard storage state:
import { getStorageStatePath } from 'power-platform-playwright-toolkit';
test.use({
storageState: getStorageStatePath(process.env.MS_AUTH_EMAIL!),
});