Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Power Apps Test Engine uses YAML-based test definitions that run against a specialized test host. Power Platform Playwright samples use TypeScript and the standard Playwright test runner, giving you access to the full Playwright API, ecosystem tooling, and CI/CD integrations.
This guide maps Test Engine concepts to their Playwright equivalents and walks through a concrete migration example.
Concept mapping
The following table shows how Test Engine concepts map to their Playwright equivalents.
| Test Engine concept | Playwright equivalent |
|---|---|
| YAML test file | TypeScript test file (*.test.ts) |
testSuite.testCases |
test.describe() blocks |
testStep |
test() function |
appLogicalName |
directUrl in AppProvider.launch() |
onTestCaseStart |
test.beforeEach() |
Assert |
expect() from @playwright/test |
Select (control interaction) |
canvasFrame.locator('[data-control-name="..."]').click() |
SetProperty |
canvasFrame.locator('input[...]').fill() |
Screenshot |
page.screenshot() or toHaveScreenshot() |
environmentVariables |
.env file variables |
| Power Fx formulas in YAML | TypeScript expressions |
Before you begin
Complete these prerequisites before starting the migration.
Clone the repository and install dependencies:
git clone https://github.com/microsoft/power-platform-playwright-samples.git cd power-platform-playwright-samples node common/scripts/install-run-rush.js installCopy your app URL from the Test Engine YAML
appLogicalNameor the Power Apps make portal.Set up authentication - see Authentication guide.
Step 1: Identify your app type
Test Engine supports canvas apps. If you're migrating:
- Canvas app tests → Follow Test canvas apps.
- Custom page tests → Follow Test custom pages.
- Model-driven app tests → Follow Test model-driven apps.
Step 2: Map your test structure
Test Engine YAML
A typical Test Engine test definition looks like this.
testSuite:
testSuiteName: OrdersTests
testCases:
- testCaseName: CreateOrder
testSteps: |
Select(AddButton);
SetProperty(OrderNumberInput, "ORD-TEST");
Select(SaveButton);
Assert(Label1.Text = "Saved");
Playwright TypeScript equivalent
Here's the same test rewritten by using Playwright and the Power Platform toolkit.
import { test, expect } from '@playwright/test';
import { AppProvider, AppType, AppLaunchMode, buildCanvasAppUrlFromEnv } from 'power-platform-playwright-toolkit';
test.describe('OrdersTests', () => {
test('CreateOrder', async ({ page, context }) => {
const app = new AppProvider(page, context);
await app.launch({
app: 'Orders App',
type: AppType.Canvas,
mode: AppLaunchMode.Play,
skipMakerPortal: true,
directUrl: buildCanvasAppUrlFromEnv(),
});
const canvasFrame = page.frameLocator('iframe[name="fullscreen-app-host"]');
// Wait for app to load
await canvasFrame
.locator('[data-control-part="gallery-item"]')
.first()
.waitFor({ state: 'visible', timeout: 60000 });
// Select(AddButton)
await canvasFrame.locator('[data-control-name="AddButton"] [role="button"]').click();
// SetProperty(OrderNumberInput, "ORD-TEST")
await canvasFrame.locator('input[aria-label="Order Number"]').fill('ORD-TEST');
// Select(SaveButton)
await canvasFrame.locator('[data-control-name="SaveButton"] [role="button"]').click();
// Assert(Label1.Text = "Saved")
await expect(canvasFrame.locator('[data-control-name="Label1"]')).toHaveText('Saved');
});
});
Step 3: Map control selectors
Test Engine uses control names from Power Apps Studio directly in YAML. In Playwright, use data-control-name attributes with the same values:
| Test Engine | Playwright |
|---|---|
Select(MyButton) |
canvasFrame.locator('[data-control-name="MyButton"] [role="button"]').click() |
SetProperty(MyInput, "text") |
canvasFrame.locator('input[aria-label="My Label"]').fill("text") |
Assert(MyLabel.Text = "x") |
expect(canvasFrame.locator('[data-control-name="MyLabel"]')).toHaveText("x") |
Select(GalleryItem) |
canvasFrame.locator('[data-control-part="gallery-item"]').filter({ hasText: 'x' }).click() |
Tip
To find the data-control-name value for a control, open the app in play mode, open DevTools (F12), and inspect the element. The value matches the control name you set in Power Apps Studio.
Step 4: Map environment variables
Test Engine uses an environmentVariables section in YAML. Move these values to your .env file:
# Test Engine YAML
environmentVariables:
- name: appUrl
value: https://apps.powerapps.com/play/...
# packages/e2e-tests/.env
CANVAS_APP_URL=https://apps.powerapps.com/play/...
Step 5: Map setup and teardown
Convert Test Engine lifecycle hooks to Playwright's built-in beforeEach and afterEach functions.
# Test Engine
testSuite:
onTestCaseStart: |
Navigate(HomeScreen);
// Playwright
test.beforeEach(async ({ page, context }) => {
// Re-launch the app for each test (equivalent to onTestCaseStart navigation)
const app = new AppProvider(page, context);
await app.launch({ ... });
});
Step 6: Replace Power Fx assertions
Test Engine uses Power Fx expressions in Assert(). Replace with Playwright expect() assertions:
| Power Fx | Playwright |
|---|---|
Assert(Label1.Text = "Done") |
expect(frame.locator('[data-control-name="Label1"]')).toHaveText('Done') |
Assert(CountRows(Gallery1.AllItems) > 0) |
expect(await frame.locator('[data-control-part="gallery-item"]').count()).toBeGreaterThan(0) |
Assert(IsVisible(ErrorLabel)) |
expect(frame.locator('[data-control-name="ErrorLabel"]')).toBeVisible() |
Assert(!IsVisible(Spinner)) |
expect(frame.locator('[data-control-name="Spinner"]')).not.toBeVisible() |
Key differences to be aware of
Keep these behavioral differences in mind as you migrate your tests.
| Area | Test Engine | Playwright |
|---|---|---|
| Waits | Automatic (Test Engine handles timing) | Explicit waitFor() required |
| Gallery timeouts | Handled internally | Use 60-second timeout for Dataverse galleries |
| Test isolation | Each test resets app state | Use beforeEach to re-launch or navigate home |
| Screenshots | Built-in Screenshot step |
page.screenshot() or toHaveScreenshot() |
| Error reporting | YAML-level | Playwright HTML report + trace viewer |
Run your migrated tests
After migrating your tests, authenticate and run them by using these commands.
cd packages/e2e-tests
npm run auth:headful # authenticate
npx playwright test # run all tests
npx playwright test --ui # run with interactive UI
Troubleshoot migration issues
Refer to the following table for common migration problems and their solutions.
| Symptom | Resolution |
|---|---|
| Gallery doesn't load | Add waitFor({ timeout: 60000 }) before interacting |
| Control not found | Verify data-control-name in DevTools - it might differ from Power Fx name |
| Selector matches multiple elements | Use .filter() or .nth(0) to narrow selection |
| Tests run but assertion fails immediately | Add explicit waitFor or toBeVisible before asserting |