Exodus Salesforce Docs
QA Runbooks

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:

  1. Salesforce Item Manager: https://exodus--safin.sandbox.lightning.force.com/lightning/n/Item_Bulk_Editor
  2. Salesforce Purchase Order Pipeline: https://exodus--safin.sandbox.lightning.force.com/lightning/n/Purchase_Order_Pipeline
  3. OrderDesk orders
  4. Packiyo sandbox dashboard
  5. 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:

FieldMeaning
runKeyUnique run label used in all generated names
generatedNamesHuman-readable names to enter in the UI
salesforce.recordsCreated IDs and planned record groups
providerReferencesExisting Pakmo/Kandy Kush and Sandbox A/B references
phaseStatusCurrent run status by phase
resume.nextStepIdStep 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 controlValue or assertion
Submit actionpage.getByRole("button", { name: "Submit Quote For Approval", exact: true })
Payment methodGateway Card
Card number4242424242424242
Expiration12 / 2030
CVV123
Save methodchecked, saved to the Account/Contact vault
Approval notesSafin E2E quote approval with saved sandbox card.
GuardrailReview/reject/approve controls are blocked until submission completes

Sales Order payment replay must then verify token reuse instead of always saving a new card:

SurfaceSelector or assertion
Payment consoleAccount / Contact Payment Vault section is visible
Saved cardVisa ending in 4242 appears once
Gateway tokens`Sandbox A
Route selectorExisting saved token appears before the new-card option
Add actionpage.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:

AssertionExpected value
Inventory__c.Inventory_Source__c3PL Provider for Pakmo/Kandy Kush rows
Inventory__c.Provider_Quantity_On_Hand__cLatest Packiyo/Katana provider count
Manual adjustment on 3PL warehouseblocked in Salesforce
Manual adjustment on non-3PL warehouseallowed through manual inventory controls
Internal count correctionItem Manager Set counted on hand, reason Cycle Count, details, and reference create Inventory_Transaction__c history
Internal delta adjustmentItem Manager Apply quantity change, reason such as Packaging Consumption or Marketing Kit or Sample, details, and reference create before/after history
Sales Order sync tagThreePL_Order_Sync_Tag__c records the provider sync outcome
Sales Order sync issueThreePL_Order_Sync_Issue__c records provider item/order sync failures

For the OrderDesk to Packiyo sandbox bridge, replay these exact controls:

AppSelectorValue or assertion
OrderDesk New folderinput[name="search_order_id"]Provider display number, for example SO-011654-10C97805B2, then Enter
OrderDesk order detailbutton[name="submit_to_packiyo"][value="1"], button.btn-integration-packiyoClick to send to Packiyo
OrderDesk historypage textOrder Submitted to Packiyo and Packiyo: <id>
Packiyo order editbutton:has-text("Mark as fulfilled")Click, then confirm
OrderDesk order detaila[href*="packiyo_check_shipment=1"]Click and expect No Tracking Found when the sandbox fulfillment has no shipment
Salesforce assertionSOQLSales 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:

FieldValue
CSVtmp/safin-packiyo-inventory-import-SO-011654.csv
CustomerExodus Canna (SandBox)
WarehousePrimary
LocationTEST LOCATION
Quantity120 per physical SKU
Physical SKUsE2E-NIC-12T163353Z-FG-BI9, E2E-NIC-12T163353Z-FG-MF9, E2E-NIC-12T163353Z-FG-CM3
ToteSAFIN-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:

StepSelectorValue or assertion
Create POURLhttps://sandbox.app.packiyo.com/purchase_orders/create
PO numberinput[name="number"]SAFINPO011654
Add backordersbutton:has-text("Add all backorders")Click once
Backorder rowstable textE2E-NIC-12T163353Z-FG-BI9 quantity 24; E2E-NIC-12T163353Z-FG-MF9 quantity 24; E2E-NIC-12T163353Z-FG-CM3 quantity 60
Warehousefirst Select2 warehouse comboboxSelect Primary
Savebutton[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:

StepEndpoint or fileValue or assertion
Find boxtmp/safin_packiyo_list_boxes_managed_auth.apexTEST BOX id 10
Create shipmenttmp/safin_packiyo_create_shipment_managed_auth.apexPOST /api/v1/orders/19176/shipments
TrackingpayloadSAFIN-TRACK-SO-011654
Package rowspayloadorder item 52820 = 24, 52821 = 24, 52822 = 60
Verifytmp/safin_packiyo_order_items_managed_auth.apexorder 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:

StepFile or commandAssertion
Create Katana ordernode 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-20260512T163353ZKatana sales order 45090132, stock adjustment 2418278, fulfillment 39275646, tracking SAFIN-KATANA-SO-011654-10C97805B2.
Deploy validation-rule fixsf 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 --jsonDeploy 0AffY000004C0UzSAK succeeds.
Write provider evidencesf apex run --target-org raf@exoclub.com.safin --file tmp/safin_provider_scoped_writeback_so_011654.apex --jsonPackiyo line BI9=24; Katana lines MF9=24, CM3=60; both provider sync states are success.
Verify SalesforceSOQL and Chrome URL https://exodus--safin.sandbox.lightning.force.com/lightning/r/Sales_Order__c/a4sfY000000BK53QAG/viewSO-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-mutations

Payment submission or payment-like approval actions require:

--allow-payment-submit

The 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-mutations

After 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

On this page