Skip to main content

Migration from wdi5

Migrate your wdi5 test suite to Playwright-Praman with minimal friction. This guide maps every wdi5 API to its Praman equivalent and highlights features that are new in Praman.

Quick Comparison​

Aspectwdi5Praman
Test runnerWebdriverIOPlaywright
UI5 bridgebrowser.asControl()ui5.control()
Selector enginewdi5 selector objectUI5Selector object
Async modelWDIO auto-sync (deprecated) / asyncAlways async/await
Parallel executionLimited (WDIO workers)Native Playwright workers
Auth managementManual login scripts6 built-in strategies + setup projects
AI integrationNoneBuilt-in capabilities, recipes, agentic handler
OData helpersNoneModel-level + HTTP-level CRUD
FLP navigationManual hash navigation9 typed navigation methods

Core API Mapping​

Control Discovery​

// wdi5
const button = await browser.asControl({
selector: {
controlType: 'sap.m.Button',
properties: { text: 'Save' },
},
});

// Praman
import { test, expect } from 'playwright-praman';

test('find a button', async ({ ui5 }) => {
const button = await ui5.control({
controlType: 'sap.m.Button',
properties: { text: 'Save' },
});
});

Multiple Controls​

// wdi5
const buttons = await browser.allControls({
selector: { controlType: 'sap.m.Button' },
});

// Praman
const buttons = await ui5.controls({ controlType: 'sap.m.Button' });

Control Interaction​

// wdi5
const input = await browser.asControl({
selector: { id: 'nameInput' },
});
await input.enterText('John Doe');
const value = await input.getValue();

// Praman
const input = await ui5.control({ id: 'nameInput' });
await input.enterText('John Doe');
const value = await input.getValue();

// Or use the shorthand:
await ui5.fill({ id: 'nameInput' }, 'John Doe');

Selector Field Mapping​

The selector object structure is similar, with a few naming adjustments and additions.

wdi5 Selector FieldPraman UI5Selector FieldTypeNotes
controlTypecontrolTypestringIdentical. Fully qualified UI5 type.
ididstring | RegExpIdentical. Supports RegExp in Praman.
viewNameviewNamestringIdentical.
viewIdviewIdstringIdentical.
propertiespropertiesRecord<string, unknown>Identical. Key-value property matchers.
bindingPathbindingPathRecord<string, string>Identical. OData binding path matchers.
i18NTexti18NTextRecord<string, string>Identical. i18n translated value matchers.
ancestorancestorUI5SelectorIdentical. Recursive parent matching.
descendantdescendantUI5SelectorIdentical. Recursive child matching.
interactioninteractionUI5InteractionIdentical. idSuffix and domChildWith.
searchOpenDialogssearchOpenDialogsbooleanIdentical. Search inside open dialogs.
labelFor----Not available in Praman. See note below.
labelFor Selector

wdi5 supports a labelFor selector field that matches controls by their associated sap.m.Label. Praman does not currently support labelFor. Use one of these alternatives:

// Option 1: Match by properties directly
const input = await ui5.control({
controlType: 'sap.m.Input',
properties: { placeholder: 'Enter vendor name' },
});

// Option 2: Match by binding path
const input = await ui5.control({
controlType: 'sap.m.Input',
bindingPath: { value: '/Vendor/Name' },
});

// Option 3: Use ancestor to scope to a form group
const input = await ui5.control({
controlType: 'sap.m.Input',
ancestor: {
controlType: 'sap.ui.layout.form.FormElement',
descendant: {
controlType: 'sap.m.Label',
properties: { text: 'Vendor Name' },
},
},
});

Config Mapping​

wdi5 Config (wdio.conf.ts)​

// wdio.conf.ts
export const config = {
wdi5: {
waitForUI5Timeout: 30000,
logLevel: 'verbose',
url: 'https://sap-system.example.com',
skipInjectUI5OnStart: false,
},
specs: ['./test/specs/**/*.ts'],
baseUrl: 'https://sap-system.example.com',
};

Praman Config (praman.config.ts + playwright.config.ts)​

// praman.config.ts
import { defineConfig } from 'playwright-praman';

export default defineConfig({
logLevel: 'info', // wdi5 logLevel -> praman logLevel
ui5WaitTimeout: 30_000, // wdi5 waitForUI5Timeout -> praman ui5WaitTimeout
controlDiscoveryTimeout: 10_000,
interactionStrategy: 'ui5-native',
auth: {
strategy: 'basic',
baseUrl: process.env.SAP_BASE_URL!,
username: process.env.SAP_USER!,
password: process.env.SAP_PASS!,
},
});
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
testDir: './tests',
timeout: 120_000,
use: {
baseURL: process.env.SAP_BASE_URL,
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{ name: 'setup', testMatch: /auth-setup\.ts/, teardown: 'teardown' },
{ name: 'teardown', testMatch: /auth-teardown\.ts/ },
{
name: 'chromium',
dependencies: ['setup'],
use: { ...devices['Desktop Chrome'], storageState: '.auth/sap-session.json' },
},
],
});

OPA5 Journey to test.step()​

wdi5 test files often follow the OPA5 journey pattern. In Praman, use test.step() for structured multi-step tests.

wdi5 + OPA5 Journey​

// wdi5 test
describe('Purchase Order', () => {
it('should navigate to the app', async () => {
await browser.url('#/PurchaseOrder-manage');
await browser.asControl({ selector: { id: 'poTable' } });
});

it('should create a new PO', async () => {
const createBtn = await browser.asControl({
selector: { controlType: 'sap.m.Button', properties: { text: 'Create' } },
});
await createBtn.press();
});

it('should fill vendor field', async () => {
const vendorInput = await browser.asControl({
selector: { id: 'vendorInput' },
});
await vendorInput.enterText('100001');
});
});

Praman + test.step()​

import { test, expect } from 'playwright-praman';

test('create a purchase order', async ({ ui5, ui5Navigation }) => {
await test.step('Navigate to PO app', async () => {
await ui5Navigation.navigateToApp('PurchaseOrder-manage');
});

await test.step('Click Create', async () => {
await ui5.click({
controlType: 'sap.m.Button',
properties: { text: 'Create' },
});
});

await test.step('Fill vendor field', async () => {
await ui5.fill({ id: 'vendorInput' }, '100001');
});
});

New in Praman vs wdi5​

Praman includes features that wdi5 does not offer. If you are migrating, these are worth adopting early.

6 Built-In Auth Strategies​

No more custom login scripts. Praman supports Basic, BTP SAML, Office 365, Custom, API, and Certificate authentication out of the box.

// Auth is handled by setup projects — no login code in tests
test('after auth', async ({ ui5Navigation }) => {
await ui5Navigation.navigateToApp('PurchaseOrder-manage');
});

9 FLP Navigation Methods​

test('navigation', async ({ ui5Navigation }) => {
await ui5Navigation.navigateToApp('PurchaseOrder-manage');
await ui5Navigation.navigateToTile('Create Purchase Order');
await ui5Navigation.navigateToIntent('PurchaseOrder', 'create', { plant: '1000' });
await ui5Navigation.navigateToHome();
await ui5Navigation.navigateBack();
});

Fiori Elements Helpers​

Dedicated APIs for List Report and Object Page patterns.

test('FE list report', async ({ fe }) => {
await fe.listReport.setFilter('Status', 'Active');
await fe.listReport.search();
await fe.listReport.navigateToItem(0);
await fe.objectPage.clickEdit();
await fe.objectPage.clickSave();
});

AI-Powered Test Generation​

test('AI discovery', async ({ pramanAI }) => {
const context = await pramanAI.discoverPage({ interactiveOnly: true });
const result = await pramanAI.agentic.generateTest(
'Create a purchase order for vendor 100001',
page,
);
});

Custom UI5 Matchers​

10 UI5-specific Playwright matchers for expressive assertions.

const button = await ui5.control({ id: 'saveBtn' });
await expect(button).toBeUI5Enabled();
await expect(button).toHaveUI5Text('Save');
await expect(button).toBeUI5Visible();

OData Model + HTTP Operations​

test('OData', async ({ ui5 }) => {
// Model-level (reads from the in-browser UI5 OData model)
const data = await ui5.odata.getModelData('/PurchaseOrders');

// HTTP-level CRUD is also available with automatic CSRF handling
});

SM12 Lock Management​

test('locks', async ({ flpLocks }) => {
const count = await flpLocks.getNumberOfLockEntries('TESTUSER');
await flpLocks.deleteAllLockEntries('TESTUSER');
// Auto-cleanup on teardown
});

Structured Error Codes​

Every Praman error includes a machine-readable code, retryable flag, and suggestions[] array for self-healing tests. wdi5 errors are unstructured strings.

Step-by-Step Migration Checklist​

  1. Install dependencies: npm install playwright-praman @playwright/test
  2. Create config files: praman.config.ts and playwright.config.ts
  3. Set up auth: Create tests/auth-setup.ts using one of the 6 strategies
  4. Convert selectors: Replace browser.asControl({ selector: {...} }) with ui5.control({...})
  5. Convert assertions: Replace WDIO expect with Playwright expect + UI5 matchers
  6. Structure tests: Convert OPA5 journey describe/it blocks to test + test.step()
  7. Adopt navigation: Replace browser.url('#/hash') with ui5Navigation methods
  8. Run and verify: npx playwright test