Browser and Replay Rules
Chrome, Computer Use, manifest, and resume rules for the Safin E2E
Single Tab Rule
Use one claimed Chrome tab for the full run. Do not open Salesforce, OrderDesk, Packiyo, or Katana in separate tabs. Navigate the same tab in this order:
- Salesforce Item Manager:
https://exodus--safin.sandbox.lightning.force.com/lightning/n/Item_Bulk_Editor - Salesforce Purchase Order Pipeline:
https://exodus--safin.sandbox.lightning.force.com/lightning/n/Purchase_Order_Pipeline - OrderDesk orders
- Packiyo sandbox dashboard
- Katana factory home
The browser policy is saved in the manifest as browser.mode = single-active-chrome-tab.
Do not use standard object creation URLs such as /lightning/o/Item__c/new or /lightning/o/Purchase_Order__c/new for this E2E.
Manifest
The manifest is the replay contract. It stores generated names, created Salesforce IDs, provider references, phase status, and the next resume marker.
Important fields:
| Field | Meaning |
|---|---|
runKey | Unique run label used in all generated names |
generatedNames | Human-readable names to enter in the UI |
salesforce.records | Created IDs and planned record groups |
providerReferences | Existing Pakmo/Kandy Kush and Sandbox A/B references |
phaseStatus | Current run status by phase |
resume.nextStepId | Step ID for e2e:safin:resume |
Replay Events
The harness writes sanitized events to .artifacts/e2e/safin/<run-label>/events.jsonl. It omits screenshot/image payloads and records step starts, skipped planned steps, resolved UI targets, action results, assertion queries, and errors.
The stricter Playwright contract lives at .artifacts/e2e/safin/<run-label>/ui-replay-playwright-plan.json. Every browser step should include at least one executable selector, field value, click target, or assertion. Prose-only notes are not enough for replay.
Quote approval replay must enter the submission flow before any approval or rejection action is attempted. Record these exact inputs in the strict plan:
| Field or control | Value or assertion |
|---|---|
| Submit action | page.getByRole("button", { name: "Submit Quote For Approval", exact: true }) |
| Payment method | Gateway Card |
| Card number | 4242424242424242 |
| Expiration | 12 / 2030 |
| CVV | 123 |
| Save method | checked, saved to the Account/Contact vault |
| Approval notes | Safin E2E quote approval with saved sandbox card. |
| Guardrail | Review/reject/approve controls are blocked until submission completes |
Sales Order payment replay must then verify token reuse instead of always saving a new card:
| Surface | Selector or assertion |
|---|---|
| Payment console | Account / Contact Payment Vault section is visible |
| Saved card | Visa ending in 4242 appears once |
| Gateway tokens | `Sandbox A |
| Route selector | Existing saved token appears before the new-card option |
| Add action | page.getByRole("button", { name: "Add Account Payment Method", exact: true }) |
3PL inventory replay no longer creates or resolves Inventory Sync Audit records. Provider-owned stock is asserted on Inventory__c:
| Assertion | Expected value |
|---|---|
Inventory__c.Inventory_Source__c | 3PL Provider for Pakmo/Kandy Kush rows |
Inventory__c.Provider_Quantity_On_Hand__c | Latest Packiyo/Katana provider count |
| Manual adjustment on 3PL warehouse | blocked in Salesforce |
| Manual adjustment on non-3PL warehouse | allowed through manual inventory controls |
| Internal count correction | Item Manager Set counted on hand, reason Cycle Count, details, and reference create Inventory_Transaction__c history |
| Internal delta adjustment | Item Manager Apply quantity change, reason such as Packaging Consumption or Marketing Kit or Sample, details, and reference create before/after history |
| Sales Order sync tag | ThreePL_Order_Sync_Tag__c records the provider sync outcome |
| Sales Order sync issue | ThreePL_Order_Sync_Issue__c records provider item/order sync failures |
For the OrderDesk to Packiyo sandbox bridge, replay these exact controls:
| App | Selector | Value or assertion |
|---|---|---|
| OrderDesk New folder | input[name="search_order_id"] | Provider display number, for example SO-011654-10C97805B2, then Enter |
| OrderDesk order detail | button[name="submit_to_packiyo"][value="1"], button.btn-integration-packiyo | Click to send to Packiyo |
| OrderDesk history | page text | Order Submitted to Packiyo and Packiyo: <id> |
| Packiyo order edit | button:has-text("Mark as fulfilled") | Click, then confirm |
| OrderDesk order detail | a[href*="packiyo_check_shipment=1"] | Click and expect No Tracking Found when the sandbox fulfillment has no shipment |
| Salesforce assertion | SOQL | Sales Order remains In Progress / Acknowledged / incomplete when no packed-line quantities exist |
On the Packiyo Pack Orders page, do not click the blue order-number link. That link opens the order edit page. Click the table row itself, or navigate to the row's packing_url, for example:
const row = page.locator('tr[role="row"]').filter({ hasText: 'SO-011654-10C97805B2' }).first();
await row.click({ position: { x: 20, y: 20 } });
await expect(page).toHaveURL(/\\/packing\\/single_order_shipping\\/19176/);If the row is not visible, use the equivalent direct route: https://sandbox.app.packiyo.com/packing/single_order_shipping/<packiyoOrderId>.
For Packiyo cleanup and real packing, replay must scope row actions by exact SKU text before clicking cancel/uncancel controls. The exploration accidentally cancelled E2E-NIC-12T163353Z-FG-BI9 once and immediately uncancelled it, which is now recorded as a failure mode. Use row-scoped locators:
const row = page.locator('tr, .row, [role="row"]').filter({ hasText: sku }).first();
await row.locator('button[title*="Cancel"], a[title*="Cancel"], button:has-text("Cancel")').first().click();The current Packiyo inventory import replay data is:
| Field | Value |
|---|---|
| CSV | tmp/safin-packiyo-inventory-import-SO-011654.csv |
| Customer | Exodus Canna (SandBox) |
| Warehouse | Primary |
| Location | TEST LOCATION |
| Quantity | 120 per physical SKU |
| Physical SKUs | E2E-NIC-12T163353Z-FG-BI9, E2E-NIC-12T163353Z-FG-MF9, E2E-NIC-12T163353Z-FG-CM3 |
| Tote | SAFIN-11654- |
Packiyo Stock Creation
When Packiyo reports order 19176 / SO-011654-10C97805B2 as backordered, the replay should try the native PO path before CSV import:
| Step | Selector | Value or assertion |
|---|---|---|
| Create PO | URL | https://sandbox.app.packiyo.com/purchase_orders/create |
| PO number | input[name="number"] | SAFINPO011654 |
| Add backorders | button:has-text("Add all backorders") | Click once |
| Backorder rows | table text | E2E-NIC-12T163353Z-FG-BI9 quantity 24; E2E-NIC-12T163353Z-FG-MF9 quantity 24; E2E-NIC-12T163353Z-FG-CM3 quantity 60 |
| Warehouse | first Select2 warehouse combobox | Select Primary |
| Save | button[type="submit"], button:has([title="Save"]) | Click, then receive/confirm if Packiyo prompts |
The current Chrome exploration reached the populated backorder rows, but warehouse selection and subsequent save could not be completed because Packiyo's Select2 field needed text/dropdown input after showing Please enter 1 or more characters, and the Chrome extension reported the Browser Use virtual clipboard was not installed for text entry. The working fallback is the Salesforce managed Packiyo provider account, not the local .env.safin.local token. Managed auth resolved TEST LOCATION as id 318 under warehouse Primary id 40; POST /api/v1/products/{productId}/inventory with { "location_id": 318, "quantity": 120 } cleared the three physical backorders.
Packiyo Shipment Creation
After stock cleared, the strict replay can create the sandbox shipment through the Packiyo API when the packing UI is unavailable:
| Step | Endpoint or file | Value or assertion |
|---|---|---|
| Find box | tmp/safin_packiyo_list_boxes_managed_auth.apex | TEST BOX id 10 |
| Create shipment | tmp/safin_packiyo_create_shipment_managed_auth.apex | POST /api/v1/orders/19176/shipments |
| Tracking | payload | SAFIN-TRACK-SO-011654 |
| Package rows | payload | order item 52820 = 24, 52821 = 24, 52822 = 60 |
| Verify | tmp/safin_packiyo_order_items_managed_auth.apex | order 19176 is Fulfilled, ready_to_ship = 0, ready_to_pick = 0, quantity_pending = 0 |
The completed provider writeback replay for SO-011654 has these exact steps:
| Step | File or command | Assertion |
|---|---|---|
| Create Katana order | node scripts/e2e/safin-katana-fulfill-so.mjs --sales-order-id a4sfY000000BK53QAG --target-org raf@exoclub.com.safin --artifact-root .artifacts/e2e/safin/SAFIN-E2E-NIC-20260512T163353Z | Katana sales order 45090132, stock adjustment 2418278, fulfillment 39275646, tracking SAFIN-KATANA-SO-011654-10C97805B2. |
| Deploy validation-rule fix | sf project deploy start --target-org raf@exoclub.com.safin --source-dir features-orders/main/default/objects/Sales_Order_Line__c/validationRules/Immutable_Order_Credit_Adjustments_Only.validationRule-meta.xml --json | Deploy 0AffY000004C0UzSAK succeeds. |
| Write provider evidence | sf apex run --target-org raf@exoclub.com.safin --file tmp/safin_provider_scoped_writeback_so_011654.apex --json | Packiyo line BI9=24; Katana lines MF9=24, CM3=60; both provider sync states are success. |
| Verify Salesforce | SOQL and Chrome URL https://exodus--safin.sandbox.lightning.force.com/lightning/r/Sales_Order__c/a4sfY000000BK53QAG/view | SO-011654 is Closed, Fulfilled, 108/108, and the UI shows all three physical lines fulfilled. |
The replay harness currently wraps the Salesforce writeback with SalesOrderTriggerHandler.pushRuntimeFinancialAuditBypass() and DataImportRuntimeGuard.push() to keep nonessential financial-audit and customer-email side effects out of the heavy fulfillment transaction. A production fix for FulfillmentOrderUpdateService.updateOrderRecord is local, but Apex deploy 0AffY000004C0bRSAS failed because the sandbox org exceeds the 6,000,000 Apex character limit.
Safety Gates
Mutating Salesforce and provider-app steps require:
--allow-mutationsPayment submission or payment-like approval actions require:
--allow-payment-submitThe setup command also requires --allow-mutations because it inserts fake Vendor Accounts and fake internal Warehouses.
Resume
Use the failed step ID from events.jsonl or manifest.resume.nextStepId.
npm run e2e:safin:resume -- --from quote-reject-approve-sync --allow-mutationsAfter an LWC fix, run the focused Jest test, deploy the changed metadata, then resume without changing the run label. This preserves provider references and keeps the generated data set linear.
Future Recording Placement
Place screen recordings and still evidence in:
docs/evidence/safin-e2e/<run-label>/Use filenames that start with the step ID, for example quote-reject-approve-sync-approval-modal.mov.
Last updated on