- name
- wms-testing-patterns
- description
- Warehouse Management System testing patterns for inventory operations, pick/pack/ship workflows, wave management, EDI X12/EDIFACT compliance, RF/barcode scanning, and WMS-ERP integration. Use when testing WMS platforms (Blue Yonder, Manhattan, SAP EWM).
- category
- enterprise-integration
- priority
- high
- tokenEstimate
- 1800
- agents
- ["qe-middleware-validator","qe-contract-validator","qe-sap-idoc-tester","qe-odata-contract-tester"]
- implementation_status
- optimized
- optimization_version
- 2
- last_optimized
- 2026-02-04T00:00:00.000Z
- dependencies
- ["api-testing-patterns","contract-testing","enterprise-integration-testing"]
- quick_reference_card
- true
- tags
- ["wms","warehouse","inventory","edi","pick-pack-ship","blue-yonder","manhattan","sap-ewm","rf-scanning"]
- trust_tier
- 3
- validation
- {"schema_path":"schemas/output.json","validator_path":"scripts/validate-config.json","eval_path":"evals/wms-testing-patterns.yaml"}
# WMS Testing Patterns
<default_to_action>
When testing Warehouse Management Systems:
1. VALIDATE inventory accuracy (receipt, putaway, cycle count, adjustments)
2. TEST pick/pack/ship workflows end-to-end (wave release -> shipment confirm)
3. VERIFY EDI message processing (856 ASN, 940 Order, 945 Confirmation, 943/944 Stock)
4. ASSERT RF/barcode scanning flows (scan -> validate -> update -> confirm)
5. EXERCISE allocation and replenishment logic (FIFO, FEFO, lot control)
6. TEST WMS-ERP integration (inventory sync, order status, goods receipt)
7. VALIDATE wave management (wave planning, release, short-pick handling)
**Quick Pattern Selection:**
- Inventory discrepancies -> Cycle count and adjustment tests
- Order fulfillment issues -> Pick/pack/ship workflow tests
- EDI failures -> Message format and acknowledgment tests
- Scanning problems -> RF device simulation tests
- Allocation errors -> Lot control and FIFO/FEFO tests
- Integration gaps -> WMS-ERP sync boundary tests
**Critical Success Factors:**
- WMS accuracy directly impacts customer experience and financial reporting
- Always test both normal and exception flows (short picks, damaged goods, returns)
- EDI testing must cover both syntax validation AND business rule validation
</default_to_action>
## Quick Reference Card
### When to Use
- Testing WMS platforms (Blue Yonder/JDA, Manhattan Associates, SAP EWM, Oracle WMS)
- Validating inventory transaction accuracy (receipts, picks, adjustments)
- Testing EDI document exchange (X12 856/940/945/943/944, EDIFACT DESADV/ORDERS)
- Verifying RF/mobile scanning workflows
- Testing wave management and allocation logic
- Validating WMS-to-ERP integration (SAP MM/WM, Oracle)
### Testing Levels
| Level | Purpose | Dependencies | Speed |
|-------|---------|--------------|-------|
| Unit Logic | Allocation/replenishment rules | None | Fast |
| API Contract | WMS REST/SOAP endpoint contracts | API stubs | Fast |
| EDI Validation | Document syntax + business rules | EDI parser | Medium |
| Integration | WMS-ERP inventory sync | Full stack | Slower |
| E2E Workflow | Complete order fulfillment cycle | WMS + ERP + TMS | Slow |
### Critical Test Scenarios
| Scenario | Must Test | Example |
|----------|----------|---------|
| Receiving | Inbound accuracy | PO receipt with over/under delivery tolerance |
| Putaway | Location assignment | Directed putaway by product attributes |
| Picking | Wave/batch pick | Multi-order wave with priority allocation |
| Packing | Pack verification | Cartonization and weight/dim validation |
| Shipping | Carrier assignment | Rate shopping and label generation |
| Cycle Count | Inventory accuracy | Blind count vs. guided count reconciliation |
| Returns | Reverse logistics | RMA receipt, inspection, disposition |
| EDI 856 | ASN generation | Ship-confirm triggers correct ASN to customer |
| EDI 940 | Warehouse order | Inbound order creates correct work orders |
| Short Pick | Exception handling | Partial allocation with backorder creation |
### Tools
- **WMS Platforms**: Blue Yonder WMS, Manhattan WMOS, SAP EWM, Oracle WMS Cloud
- **EDI Testing**: Bots EDI, SPS Commerce Test, Cleo Clarify
- **RF Simulation**: Custom RF emulators, Zebra SDK test harnesses
- **Integration**: SAP PI/PO, MuleSoft, Dell Boomi
- **Monitoring**: Splunk, WMS dashboards, EDI tracking portals
### Agent Coordination
- `qe-middleware-validator`: WMS-ERP integration flows and message transformation validation
- `qe-contract-validator`: EDI document contracts and WMS API contracts
- `qe-sap-idoc-tester`: WMS-SAP IDoc validation (WMMBID01, SHPCON)
- `qe-odata-contract-tester`: SAP EWM OData service testing
---
## Inventory Transaction Testing
### Receipt and Putaway
```javascript
describe('Inbound Receipt - PO with Lot Control', () => {
it('receives goods against PO with lot tracking', async () => {
const receipt = await wms.receive({
po: 'PO-4500001234',
item: 'MAT-100',
quantity: 100,
lot: 'LOT-2026-001',
expiryDate: '2027-06-30',
uom: 'EA'
});
expect(receipt.status).toBe('RECEIVED');
expect(receipt.quantityReceived).toBe(100);
expect(receipt.lot).toBe('LOT-2026-001');
// Verify putaway task was created
const putawayTask = await wms.getTask(receipt.putawayTaskId);
expect(putawayTask.type).toBe('DIRECTED_PUTAWAY');
expect(putawayTask.suggestedLocation).toMatch(/^BIN-/);
});
it('rejects over-receipt beyond tolerance', async () => {
// PO line is for 100 EA, tolerance is 10%
const result = await wms.receive({
po: 'PO-4500001234',
item: 'MAT-100',
quantity: 115, // 15% over, exceeds 10% tolerance
lot: 'LOT-2026-002'
});
expect(result.status).toBe('REJECTED');
expect(result.reason).toContain('Over-receipt tolerance exceeded');
expect(result.maxAllowed).toBe(110);
});
it('accepts under-receipt and creates remaining open quantity', async () => {
const result = await wms.receive({
po: 'PO-4500001234',
item: 'MAT-100',
quantity: 80,
lot: 'LOT-2026-003'
});
expect(result.status).toBe('PARTIAL_RECEIPT');
expect(result.quantityReceived).toBe(80);
expect(result.remainingOpen).toBe(20);
});
});
describe('Directed Putaway', () => {
it('assigns location based on product attributes', async () => {
// Hazmat product should go to hazmat zone
const putaway = await wms.executePutaway({
item: 'MAT-HAZ-001',
attributes: { hazmat: true, temperature: 'ambient' },
quantity: 50,
lot: 'LOT-HAZ-001'
});
expect(putaway.location).toMatch(/^HAZ-/); // Hazmat zone prefix
expect(putaway.status).toBe('PUTAWAY_COMPLETE');
});
it('falls back to overflow when primary zone is full', async () => {
// Fill the primary zone first
await wms.fillZone('ZONE-A', 100); // 100% capacity
const putaway = await wms.executePutaway({
item: 'MAT-200',
quantity: 10,
preferredZone: 'ZONE-A'
});
expect(putaway.location).toMatch(/^OVF-/); // Overflow zone
expect(putaway.overflowReason).toBe('PRIMARY_ZONE_FULL');
});
});
```
### Cycle Count and Adjustments
```javascript
describe('Cycle Count - Blind Count', () => {
it('auto-approves variance within threshold', async () => {
// System shows 100 EA, physical count is 98
const count = await wms.submitCycleCount({
location: 'BIN-A-01-01',
item: 'MAT-100',
countedQuantity: 98,
countType: 'BLIND', // Counter does not see system quantity
varianceThreshold: 5 // percent
});
expect(count.systemQuantity).toBe(100);
expect(count.variance).toBe(-2);
expect(count.variancePercent).toBeCloseTo(2.0);
expect(count.autoApproved).toBe(true);
expect(count.adjustmentPosted).toBe(true);
});
it('requires supervisor approval when variance exceeds threshold', async () => {
const count = await wms.submitCycleCount({
location: 'BIN-A-01-02',
item: 'MAT-200',
countedQuantity: 80,
countType: 'BLIND',
varianceThreshold: 5 // 20% variance exceeds 5% threshold
});
expect(count.variancePercent).toBeCloseTo(20.0);
expect(count.autoApproved).toBe(false);
expect(count.adjustmentPosted).toBe(false);
expect(count.status).toBe('PENDING_SUPERVISOR_APPROVAL');
});
it('triggers recount when variance is critical', async () => {
const count = await wms.submitCycleCount({
location: 'BIN-A-01-03',
item: 'MAT-300',
countedQuantity: 0, // System shows 50
countType: 'BLIND',
varianceThreshold: 5,
criticalThreshold: 50
});
expect(count.variancePercent).toBe(100);
expect(count.status).toBe('RECOUNT_REQUIRED');
expect(count.recountAssigned).toBe(true);
expect(count.recountAssignee).not.toBe(count.originalCounter);
});
});
```
---
## Pick/Pack/Ship Workflow Testing
### Wave Management
```javascript
describe('Wave Planning and Release', () => {
it('creates wave from eligible orders with batch-pick strategy', async () => {
// Create 5 orders for wave planning
const orders = await Promise.all(
Array.from({ length: 5 }, (_, i) => wms.createOrder({
orderId: `SO-100${i}`,
lines: [
{ item: 'MAT-100', qty: 10 },
{ item: 'MAT-200', qty: 5 }
],
priority: i === 0 ? 'RUSH' : 'STANDARD',
shipBy: '2026-02-05'
}))
);
const wave = await wms.planWave({
strategy: 'BATCH_PICK',
maxOrders: 10,
cutoffTime: '2026-02-05T14:00:00Z'
});
expect(wave.orderCount).toBe(5);
expect(wave.pickTasks).toBeGreaterThan(0);
expect(wave.status).toBe('PLANNED');
// Rush order should be first in pick sequence
const firstTask = wave.pickTasks[0];
expect(firstTask.orderId).toBe('SO-1000');
expect(firstTask.priority).toBe('RUSH');
});
it('handles short-pick by creating backorder', async () => {
// Only 5 EA available, order needs 10
await wms.setInventory('BIN-B-01-01', 'MAT-500', 5);
const order = await wms.createOrder({
orderId: 'SO-SHORT',
lines: [{ item: 'MAT-500', qty: 10 }]
});
const wave = await wms.planWave({ strategy: 'SINGLE_ORDER' });
await wms.releaseWave(wave.id);
// Attempt to pick
const pickResult = await wms.confirmPick({
taskId: wave.pickTasks[0].id,
pickedQty: 5 // Only 5 available
});
expect(pickResult.status).toBe('SHORT_PICK');
expect(pickResult.pickedQuantity).toBe(5);
expect(pickResult.shortQuantity).toBe(5);
expect(pickResult.backorderCreated).toBe(true);
expect(pickResult.backorderId).toBeDefined();
});
});
```
### Allocation Logic
```javascript
describe('FIFO Allocation', () => {
it('allocates oldest lot first', async () => {
// Set up two lots with different receipt dates
await wms.receiveInventory('MAT-FIFO', 50, { lot: 'LOT-OLD', receiptDate: '2026-01-01' });
await wms.receiveInventory('MAT-FIFO', 50, { lot: 'LOT-NEW', receiptDate: '2026-02-01' });
const allocation = await wms.allocate({
item: 'MAT-FIFO',
quantity: 30,
method: 'FIFO'
});
expect(allocation.allocatedLot).toBe('LOT-OLD');
expect(allocation.quantity).toBe(30);
});
it('splits allocation across lots when oldest is insufficient', async () => {
await wms.receiveInventory('MAT-SPLIT', 20, { lot: 'LOT-A', receiptDate: '2026-01-01' });
await wms.receiveInventory('MAT-SPLIT', 50, { lot: 'LOT-B', receiptDate: '2026-01-15' });
const allocation = await wms.allocate({
item: 'MAT-SPLIT',
quantity: 40,
method: 'FIFO'
});
expect(allocation.splits).toHaveLength(2);
expect(allocation.splits[0]).toEqual({ lot: 'LOT-A', quantity: 20 });
expect(allocation.splits[1]).toEqual({ lot: 'LOT-B', quantity: 20 });
});
});
describe('FEFO Allocation (First Expired, First Out)', () => {
it('allocates lot with earliest expiry first', async () => {
await wms.receiveInventory('MAT-FEFO', 50, { lot: 'LOT-EXP-LATE', expiry: '2027-12-31' });
await wms.receiveInventory('MAT-FEFO', 50, { lot: 'LOT-EXP-SOON', expiry: '2026-06-30' });
const allocation = await wms.allocate({
item: 'MAT-FEFO',
quantity: 30,
method: 'FEFO'
});
expect(allocation.allocatedLot).toBe('LOT-EXP-SOON');
});
it('excludes expired lots from allocation', async () => {
View on GitHub