Skip to main content
Version: 1.x

Intent API

The playwright-praman/intents sub-path provides high-level, business-oriented test operations for SAP S/4HANA modules. Instead of interacting with individual UI5 controls, intent APIs express test steps in business terms.

Overview​

import {
fillField,
clickButton,
selectOption,
assertField,
navigateAndSearch,
} from 'playwright-praman/intents';

import { procurement } from 'playwright-praman/intents';

The intent layer is built on two foundations:

  1. Core wrappers -- low-level building blocks that accept a UI5Handler slice and optional vocabulary lookup.
  2. Domain namespaces -- 9 SAP module-specific APIs that compose the core wrappers into business flows.

Core Wrappers​

Core wrappers are the shared building blocks used by all domain intent functions. They accept a minimal UI5HandlerSlice interface, making them easy to unit test with mocks:

interface UI5HandlerSlice {
control(selector: UI5Selector, options?: { timeout?: number }): Promise<unknown>;
click(selector: UI5Selector): Promise<void>;
fill(selector: UI5Selector, value: string): Promise<void>;
select(selector: UI5Selector, key: string): Promise<void>;
getText(selector: UI5Selector): Promise<string>;
waitForUI5(timeout?: number): Promise<void>;
}

Available Core Wrappers​

WrapperPurpose
fillFieldFill a UI5 input control, with optional vocabulary term resolution
clickButtonClick a button by text label or selector
selectOptionSelect an option in a dropdown/ComboBox
assertFieldAssert the value of a field matches expected text
navigateAndSearchNavigate to an app via FLP and execute a search
confirmAndWaitClick a confirmation button and wait for UI5 stability
waitForSaveWait for a save operation to complete (message toast)

Vocabulary Integration​

Core wrappers accept an optional VocabLookup to resolve business terms to UI5 selectors:

interface VocabLookup {
getFieldSelector(term: string, domain?: string): Promise<UI5Selector | undefined>;
}

// With vocabulary: "Vendor" resolves to { id: 'vendorInput' }
await fillField(ui5, vocab, 'Vendor', '100001', { domain: 'procurement' });

// Without vocabulary: pass a selector directly
await fillField(ui5, undefined, { id: 'vendorInput' }, '100001');

When a vocabulary term cannot be resolved, the wrapper returns an IntentResult with status: 'error' and helpful suggestions.

IntentResult Envelope​

All intent functions return a typed IntentResult<T>:

interface IntentResult<T = void> {
readonly status: 'success' | 'error' | 'partial';
readonly data?: T;
readonly error?: { readonly code: string; readonly message: string };
readonly metadata: {
readonly duration: number;
readonly retryable: boolean;
readonly suggestions: string[];
readonly intentName: string;
readonly sapModule: string;
readonly stepsExecuted: string[];
};
}

Example usage:

const result = await procurement.createPurchaseOrder(ui5, vocab, {
vendor: '100001',
material: 'RAW-0001',
quantity: 100,
plant: '1000',
});

if (result.status === 'success') {
console.log(`PO created: ${result.data}`);
console.log(`Steps: ${result.metadata.stepsExecuted.join(' -> ')}`);
// Steps: navigate -> fillVendor -> fillMaterial -> fillQuantity -> save
}

IntentOptions​

All domain functions accept optional IntentOptions:

interface IntentOptions {
skipNavigation?: boolean; // Skip FLP navigation (app already open)
timeout?: number; // Override default timeout (ms)
validateViaOData?: boolean; // Validate result via OData GET after save
overrides?: IntentOverrides; // Environment-specific customization
}

interface IntentOverrides {
appId?: string; // Custom FLP semantic object hash
saveButtonText?: string; // Localized save button label
fields?: Record<string, string>; // Localized field label mappings
}

// Skip navigation when already on the correct page
const result = await procurement.createPurchaseOrder(ui5, vocab, poData, {
skipNavigation: true,
timeout: 60_000,
});

IntentOverrides​

Use overrides to make tests portable across SAP system landscapes with different configurations or languages:

// German-language SAP system
await procurement.createPurchaseOrder(ui5, ui5Nav, vocab, poData, {
overrides: {
appId: 'ZMM_PO-create',
saveButtonText: 'Sichern',
fields: { Vendor: 'Lieferant', Plant: 'Werk' },
},
});

All 9 intent domains support overrides. The override values take precedence over vocabulary-resolved defaults.

Domain Namespaces​

Procurement (MM -- Materials Management)​

import { procurement } from 'playwright-praman/intents';

// Create a purchase order
await procurement.createPurchaseOrder(ui5, vocab, {
vendor: '100001',
material: 'RAW-0001',
quantity: 100,
plant: '1000',
});

// Search purchase orders
await procurement.searchPurchaseOrders(ui5, vocab, { vendor: '100001' });

// Display purchase order details
await procurement.displayPurchaseOrder(ui5, vocab, '4500012345');

Sales (SD -- Sales and Distribution)​

import { sales } from 'playwright-praman/intents';

// Create a sales order
await sales.createSalesOrder(ui5, vocab, {
customer: '200001',
material: 'FG-1000',
quantity: 50,
salesOrganization: '1000',
});

// Search sales orders
await sales.searchSalesOrders(ui5, vocab, { customer: '200001' });

Finance (FI -- Financial Accounting)​

import { finance } from 'playwright-praman/intents';

// Post a journal entry
await finance.postJournalEntry(ui5, vocab, {
documentDate: '2026-02-20',
postingDate: '2026-02-20',
lineItems: [
{ glAccount: '400000', debitCredit: 'S', amount: 1000 },
{ glAccount: '110000', debitCredit: 'H', amount: 1000 },
],
});

// Post a vendor invoice
await finance.postVendorInvoice(ui5, vocab, {
vendor: '100001',
invoiceDate: '2026-02-20',
amount: 5000,
currency: 'EUR',
});

// Process a vendor payment
await finance.processPayment(ui5, vocab, {
vendor: '100001',
amount: 5000,
paymentDate: '2026-02-28',
});

Manufacturing (PP -- Production Planning)​

import { manufacturing } from 'playwright-praman/intents';

// Create a production order
await manufacturing.createProductionOrder(ui5, vocab, {
material: 'FG-1000',
plant: '1000',
quantity: 50,
});

// Confirm a production order
await manufacturing.confirmProductionOrder(ui5, vocab, {
orderNumber: '1000012',
quantity: 50,
});

Master Data (MD -- Cross-Module)​

import { masterData } from 'playwright-praman/intents';

// Create a vendor master
await masterData.createVendor(ui5, vocab, {
name: 'Acme GmbH',
country: 'DE',
taxId: 'DE123456789',
});

// Create a customer master
await masterData.createCustomer(ui5, vocab, {
name: 'Globex Corp',
country: 'US',
salesOrganization: '1000',
});

// Create a material master
await masterData.createMaterial(ui5, vocab, {
materialNumber: 'RAW-0001',
description: 'Raw material A',
materialType: 'ROH',
baseUnit: 'KG',
});

Quality Management (QM -- Quality Management)​

import { quality } from 'playwright-praman/intents';

// Create an inspection lot
await quality.createInspectionLot(ui5, ui5Nav, vocab, {
material: 'RAW-0001',
plant: '1000',
inspectionType: '01',
});

// Record inspection results
await quality.recordResults(ui5, ui5Nav, vocab, {
inspectionLot: '000012345678',
result: '10.5',
});

// Create a quality notification
await quality.createQualityNotification(ui5, ui5Nav, vocab, {
notificationType: 'Q1',
description: 'Surface defect on batch 2026-03',
});

Warehouse Management (WM -- Warehouse Management)​

import { warehouse } from 'playwright-praman/intents';

// Create a goods movement
await warehouse.createGoodsMovement(ui5, ui5Nav, vocab, {
movementType: '101',
material: 'RAW-0001',
plant: '1000',
quantity: '500',
});

// Create a transfer order
await warehouse.createTransferOrder(ui5, ui5Nav, vocab, {
warehouseNumber: '001',
material: 'RAW-0001',
quantity: '100',
});

Asset Management (AM -- Fixed Assets)​

import { assetManagement } from 'playwright-praman/intents';

// Acquire a fixed asset
await assetManagement.acquireAsset(ui5, ui5Nav, vocab, {
assetClass: '1000',
description: 'CNC Machine Model X',
companyCode: '1000',
});

// Retire an asset
await assetManagement.retireAsset(ui5, ui5Nav, vocab, {
assetNumber: '000000001000',
retirementDate: '2026-12-31',
});

// Transfer an asset between cost centers
await assetManagement.transferAsset(ui5, ui5Nav, vocab, {
assetNumber: '000000001000',
targetCostCenter: '2000',
});

Human Resources (HR -- Personnel Administration)​

import { hr } from 'playwright-praman/intents';

// Create an employee record
await hr.createEmployee(ui5, ui5Nav, vocab, {
firstName: 'Max',
lastName: 'Mustermann',
personnelArea: '1000',
});

// Record working time
await hr.recordTime(ui5, ui5Nav, vocab, {
personnelNumber: '00000001',
date: '2026-10-04',
hours: '8.0',
});

// Request absence/leave
await hr.requestAbsence(ui5, ui5Nav, vocab, {
absenceType: 'Vacation',
startDate: '2026-11-01',
endDate: '2026-11-05',
});

Data Shapes​

Each domain defines typed data interfaces:

TypeDomainPurpose
JournalEntryDataFIGeneral-ledger journal entry posting
VendorInvoiceDataFIAccounts-payable vendor invoice
PaymentDataFIOutgoing payment processing
ProductionOrderDataPPShop-floor order creation
ProductionConfirmationDataPPProduction order confirmation
VendorMasterDataMDVendor master data creation
CustomerMasterDataMDCustomer master data creation
MaterialMasterDataMDMaterial master data creation
InspectionLotDataQMQuality inspection lot creation
ResultsRecordingDataQMInspection results recording
QualityNotificationDataQMQuality notification creation
GoodsMovementDataWMWarehouse goods movement
TransferOrderDataWMWarehouse transfer order
AssetAcquisitionDataAMFixed asset acquisition
AssetRetirementDataAMFixed asset retirement
AssetTransferDataAMFixed asset transfer
EmployeeDataHREmployee record creation
TimeRecordingDataHRWorking time recording
AbsenceRequestDataHRLeave/absence request

Architecture​

The intent layer follows strict dependency rules:

Domain functions (procurement.ts, sales.ts, quality.ts, warehouse.ts, etc.)
|
v
Core wrappers (core-wrappers.ts)
|
v
UI5HandlerSlice (structural interface) + VocabLookup (optional)
  • Core wrappers do NOT import from any domain file (no circular dependencies).
  • Domain functions compose core wrappers into SAP business flows.
  • The UI5HandlerSlice is a structural sub-type -- it does not import the full UI5Handler class.
  • The VocabLookup interface is declared inline to avoid hard dependencies on the vocabulary module.