meadow-endpoints 4.0.15 → 4.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/indoctrinate_content_staging/Indoctrinate-Catalog-AppData.json +1286 -1065
- package/dist/meadow-endpoints.js +285 -148
- package/dist/meadow-endpoints.js.map +1 -1
- package/dist/meadow-endpoints.min.js +7 -7
- package/dist/meadow-endpoints.min.js.map +1 -1
- package/docs/_version.json +7 -0
- package/docs/css/docuserve.css +277 -23
- package/docs/index.html +2 -2
- package/docs/retold-catalog.json +13 -1
- package/docs/retold-keyword-index.json +1 -1
- package/package.json +8 -7
- package/source/Meadow-Endpoints-Browser-Shim.js +4 -1
- package/source/Meadow-Endpoints.js +6 -6
- package/source/controller/Meadow-Endpoints-Controller-Base.js +6 -6
- package/source/controller/components/Meadow-Endpoints-Controller-BehaviorInjection.js +11 -11
- package/source/controller/components/Meadow-Endpoints-Controller-Error.js +23 -15
- package/source/controller/components/Meadow-Endpoints-Controller-Log.js +9 -9
- package/source/controller/utility/Meadow-Endpoints-Filter-Parser.js +16 -16
- package/source/controller/utility/Meadow-Endpoints-Session-Marshaler.js +42 -42
- package/source/controller/utility/Meadow-Endpoints-Stream-RecordArray.js +6 -6
- package/source/endpoints/create/Meadow-Endpoint-BulkCreate.js +6 -0
- package/source/endpoints/create/Meadow-Endpoint-Create.js +8 -0
- package/source/endpoints/create/Meadow-Operation-Create.js +1 -1
- package/source/endpoints/delete/Meadow-Endpoint-Delete.js +6 -0
- package/source/endpoints/delete/Meadow-Endpoint-Undelete.js +5 -0
- package/source/endpoints/read/Meadow-Endpoint-ReadDistinctList.js +7 -0
- package/source/endpoints/read/Meadow-Endpoint-ReadLiteList.js +6 -0
- package/source/endpoints/read/Meadow-Endpoint-ReadSelectList.js +6 -0
- package/source/endpoints/schema/Meadow-Endpoint-Validate.js +1 -1
- package/source/endpoints/update/Meadow-Endpoint-BulkUpdate.js +2 -0
- package/source/endpoints/update/Meadow-Operation-Update.js +10 -0
- package/source/endpoints/upsert/Meadow-Endpoint-BulkUpsert.js +3 -1
- package/test/MeadowEndpoints_basic_tests.js +1069 -0
|
@@ -1408,6 +1408,743 @@ suite
|
|
|
1408
1408
|
);
|
|
1409
1409
|
}
|
|
1410
1410
|
);
|
|
1411
|
+
|
|
1412
|
+
// ==================================================================
|
|
1413
|
+
// New hooks added 2026-04-18 to restore ME2 parity
|
|
1414
|
+
// (Update-Pre, Update-Query) and to extend ME4's bulk-level hooks
|
|
1415
|
+
// to Update/Upsert (UpdateBulk-*, UpsertBulk-*).
|
|
1416
|
+
// ==================================================================
|
|
1417
|
+
|
|
1418
|
+
test
|
|
1419
|
+
(
|
|
1420
|
+
'setBehavior: Update-PreOperation hook can mutate RecordToModify before DAL update',
|
|
1421
|
+
function (fDone)
|
|
1422
|
+
{
|
|
1423
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Update-PreOperation',
|
|
1424
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1425
|
+
{
|
|
1426
|
+
// Hook sees the incoming payload on RecordToModify,
|
|
1427
|
+
// existing loaded row on Record. Mutations to
|
|
1428
|
+
// RecordToModify flow through to the DAL update.
|
|
1429
|
+
Expect(pRequestState.RecordToModify).to.be.an('object');
|
|
1430
|
+
pRequestState.RecordToModify.Genre = 'MutatedByPreOp';
|
|
1431
|
+
return fCallback();
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
_SuperTest
|
|
1435
|
+
.put('1.0/Book')
|
|
1436
|
+
.send({ IDBook: 4, Title: 'Snow Crash (v2)' })
|
|
1437
|
+
.end(
|
|
1438
|
+
(pError, pResponse) =>
|
|
1439
|
+
{
|
|
1440
|
+
let tmpResult = JSON.parse(pResponse.text);
|
|
1441
|
+
Expect(tmpResult.Genre).to.equal('MutatedByPreOp');
|
|
1442
|
+
Expect(tmpResult.Title).to.equal('Snow Crash (v2)');
|
|
1443
|
+
|
|
1444
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Update-PreOperation'];
|
|
1445
|
+
fDone();
|
|
1446
|
+
}
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
);
|
|
1450
|
+
test
|
|
1451
|
+
(
|
|
1452
|
+
'setBehavior: Update-PreOperation hook can reject an update',
|
|
1453
|
+
function (fDone)
|
|
1454
|
+
{
|
|
1455
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Update-PreOperation',
|
|
1456
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1457
|
+
{
|
|
1458
|
+
if (!pRequestState.RecordToModify.Title)
|
|
1459
|
+
{
|
|
1460
|
+
const tmpError = new Error('Title is required');
|
|
1461
|
+
tmpError.StatusCode = 400;
|
|
1462
|
+
return fCallback(tmpError);
|
|
1463
|
+
}
|
|
1464
|
+
return fCallback();
|
|
1465
|
+
});
|
|
1466
|
+
|
|
1467
|
+
_SuperTest
|
|
1468
|
+
.put('1.0/Book')
|
|
1469
|
+
.send({ IDBook: 3 })
|
|
1470
|
+
.end(
|
|
1471
|
+
(pError, pResponse) =>
|
|
1472
|
+
{
|
|
1473
|
+
const tmpResult = JSON.parse(pResponse.text);
|
|
1474
|
+
Expect(tmpResult).to.have.property('Error');
|
|
1475
|
+
|
|
1476
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Update-PreOperation'];
|
|
1477
|
+
fDone();
|
|
1478
|
+
}
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
);
|
|
1482
|
+
test
|
|
1483
|
+
(
|
|
1484
|
+
'setBehavior: Update-QueryConfiguration hook fires after Query.addRecord',
|
|
1485
|
+
function (fDone)
|
|
1486
|
+
{
|
|
1487
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Update-QueryConfiguration',
|
|
1488
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1489
|
+
{
|
|
1490
|
+
// Query should exist and have had the record added;
|
|
1491
|
+
// hook can scope the update further.
|
|
1492
|
+
Expect(pRequestState.Query).to.exist;
|
|
1493
|
+
pRequestState.Query.addFilter('Deleted', 0);
|
|
1494
|
+
return fCallback();
|
|
1495
|
+
});
|
|
1496
|
+
|
|
1497
|
+
_SuperTest
|
|
1498
|
+
.put('1.0/Book')
|
|
1499
|
+
.send({ IDBook: 2, Title: 'Dune (updated)' })
|
|
1500
|
+
.end(
|
|
1501
|
+
(pError, pResponse) =>
|
|
1502
|
+
{
|
|
1503
|
+
const tmpResult = JSON.parse(pResponse.text);
|
|
1504
|
+
Expect(tmpResult.Title).to.equal('Dune (updated)');
|
|
1505
|
+
|
|
1506
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Update-QueryConfiguration'];
|
|
1507
|
+
fDone();
|
|
1508
|
+
}
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
);
|
|
1512
|
+
test
|
|
1513
|
+
(
|
|
1514
|
+
'setBehavior: UpdateBulk-PreOperation fires once before the batch',
|
|
1515
|
+
function (fDone)
|
|
1516
|
+
{
|
|
1517
|
+
let _CallCount = 0;
|
|
1518
|
+
let _SawBulkRecords = false;
|
|
1519
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('UpdateBulk-PreOperation',
|
|
1520
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1521
|
+
{
|
|
1522
|
+
_CallCount++;
|
|
1523
|
+
_SawBulkRecords = Array.isArray(pRequestState.BulkRecords);
|
|
1524
|
+
return fCallback();
|
|
1525
|
+
});
|
|
1526
|
+
|
|
1527
|
+
_SuperTest
|
|
1528
|
+
.put('1.0/Books')
|
|
1529
|
+
.send([
|
|
1530
|
+
{ IDBook: 1, Title: 'Angels & Demons (batch)' },
|
|
1531
|
+
{ IDBook: 2, Title: 'Dune (batch)' },
|
|
1532
|
+
])
|
|
1533
|
+
.end(
|
|
1534
|
+
(pError, pResponse) =>
|
|
1535
|
+
{
|
|
1536
|
+
Expect(_CallCount).to.equal(1);
|
|
1537
|
+
Expect(_SawBulkRecords).to.equal(true);
|
|
1538
|
+
|
|
1539
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['UpdateBulk-PreOperation'];
|
|
1540
|
+
fDone();
|
|
1541
|
+
}
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1544
|
+
);
|
|
1545
|
+
test
|
|
1546
|
+
(
|
|
1547
|
+
'setBehavior: UpdateBulk-PostOperation fires once after the batch',
|
|
1548
|
+
function (fDone)
|
|
1549
|
+
{
|
|
1550
|
+
let _CallCount = 0;
|
|
1551
|
+
let _SawUpdatedRecords = false;
|
|
1552
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('UpdateBulk-PostOperation',
|
|
1553
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1554
|
+
{
|
|
1555
|
+
_CallCount++;
|
|
1556
|
+
_SawUpdatedRecords = Array.isArray(pRequestState.UpdatedRecords) && pRequestState.UpdatedRecords.length > 0;
|
|
1557
|
+
return fCallback();
|
|
1558
|
+
});
|
|
1559
|
+
|
|
1560
|
+
_SuperTest
|
|
1561
|
+
.put('1.0/Books')
|
|
1562
|
+
.send([
|
|
1563
|
+
{ IDBook: 3, Title: 'Neuromancer (batch post)' },
|
|
1564
|
+
])
|
|
1565
|
+
.end(
|
|
1566
|
+
(pError, pResponse) =>
|
|
1567
|
+
{
|
|
1568
|
+
Expect(_CallCount).to.equal(1);
|
|
1569
|
+
Expect(_SawUpdatedRecords).to.equal(true);
|
|
1570
|
+
|
|
1571
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['UpdateBulk-PostOperation'];
|
|
1572
|
+
fDone();
|
|
1573
|
+
}
|
|
1574
|
+
);
|
|
1575
|
+
}
|
|
1576
|
+
);
|
|
1577
|
+
test
|
|
1578
|
+
(
|
|
1579
|
+
'setBehavior: UpsertBulk-PreOperation fires once before the batch',
|
|
1580
|
+
function (fDone)
|
|
1581
|
+
{
|
|
1582
|
+
let _CallCount = 0;
|
|
1583
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('UpsertBulk-PreOperation',
|
|
1584
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1585
|
+
{
|
|
1586
|
+
_CallCount++;
|
|
1587
|
+
Expect(Array.isArray(pRequestState.BulkRecords)).to.equal(true);
|
|
1588
|
+
return fCallback();
|
|
1589
|
+
});
|
|
1590
|
+
|
|
1591
|
+
_SuperTest
|
|
1592
|
+
.put('1.0/Book/Upserts')
|
|
1593
|
+
.send([
|
|
1594
|
+
{ Title: 'Bulk Upsert New 1' },
|
|
1595
|
+
{ Title: 'Bulk Upsert New 2' },
|
|
1596
|
+
])
|
|
1597
|
+
.end(
|
|
1598
|
+
(pError, pResponse) =>
|
|
1599
|
+
{
|
|
1600
|
+
Expect(_CallCount).to.equal(1);
|
|
1601
|
+
|
|
1602
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['UpsertBulk-PreOperation'];
|
|
1603
|
+
fDone();
|
|
1604
|
+
}
|
|
1605
|
+
);
|
|
1606
|
+
}
|
|
1607
|
+
);
|
|
1608
|
+
test
|
|
1609
|
+
(
|
|
1610
|
+
'setBehavior: UpsertBulk-PostOperation fires once after the batch',
|
|
1611
|
+
function (fDone)
|
|
1612
|
+
{
|
|
1613
|
+
let _CallCount = 0;
|
|
1614
|
+
let _SawUpserted = false;
|
|
1615
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('UpsertBulk-PostOperation',
|
|
1616
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1617
|
+
{
|
|
1618
|
+
_CallCount++;
|
|
1619
|
+
_SawUpserted = Array.isArray(pRequestState.UpsertedRecords) && pRequestState.UpsertedRecords.length > 0;
|
|
1620
|
+
return fCallback();
|
|
1621
|
+
});
|
|
1622
|
+
|
|
1623
|
+
_SuperTest
|
|
1624
|
+
.put('1.0/Book/Upserts')
|
|
1625
|
+
.send([
|
|
1626
|
+
{ Title: 'Bulk Upsert Post 1' },
|
|
1627
|
+
])
|
|
1628
|
+
.end(
|
|
1629
|
+
(pError, pResponse) =>
|
|
1630
|
+
{
|
|
1631
|
+
Expect(_CallCount).to.equal(1);
|
|
1632
|
+
Expect(_SawUpserted).to.equal(true);
|
|
1633
|
+
|
|
1634
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['UpsertBulk-PostOperation'];
|
|
1635
|
+
fDone();
|
|
1636
|
+
}
|
|
1637
|
+
);
|
|
1638
|
+
}
|
|
1639
|
+
);
|
|
1640
|
+
|
|
1641
|
+
// ==================================================================
|
|
1642
|
+
// Coverage backfill for hooks that were present but previously
|
|
1643
|
+
// untested. Each test registers a handler, fires the endpoint,
|
|
1644
|
+
// and asserts the hook observed the expected state. These also
|
|
1645
|
+
// act as stage-semantics documentation for the hook surface.
|
|
1646
|
+
// ==================================================================
|
|
1647
|
+
|
|
1648
|
+
test
|
|
1649
|
+
(
|
|
1650
|
+
'setBehavior: Create-QueryConfiguration fires after Query.addRecord',
|
|
1651
|
+
function (fDone)
|
|
1652
|
+
{
|
|
1653
|
+
let _Seen = null;
|
|
1654
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Create-QueryConfiguration',
|
|
1655
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1656
|
+
{
|
|
1657
|
+
_Seen = {
|
|
1658
|
+
hasQuery: !!pRequestState.Query,
|
|
1659
|
+
hasRecordToCreate: !!pRequestState.RecordToCreate,
|
|
1660
|
+
};
|
|
1661
|
+
return fCallback();
|
|
1662
|
+
});
|
|
1663
|
+
|
|
1664
|
+
_SuperTest
|
|
1665
|
+
.post('1.0/Book')
|
|
1666
|
+
.send({ Title: 'Query-Config hook target' })
|
|
1667
|
+
.end(
|
|
1668
|
+
(pError, pResponse) =>
|
|
1669
|
+
{
|
|
1670
|
+
Expect(_Seen).to.deep.equal({ hasQuery: true, hasRecordToCreate: true });
|
|
1671
|
+
|
|
1672
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Create-QueryConfiguration'];
|
|
1673
|
+
fDone();
|
|
1674
|
+
}
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
);
|
|
1678
|
+
test
|
|
1679
|
+
(
|
|
1680
|
+
'setBehavior: Create-PostOperation sees the freshly-inserted Record',
|
|
1681
|
+
function (fDone)
|
|
1682
|
+
{
|
|
1683
|
+
let _SeenIDBook = null;
|
|
1684
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Create-PostOperation',
|
|
1685
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1686
|
+
{
|
|
1687
|
+
_SeenIDBook = pRequestState.Record && pRequestState.Record.IDBook;
|
|
1688
|
+
pRequestState.Record.PostOpTag = 'was-here';
|
|
1689
|
+
return fCallback();
|
|
1690
|
+
});
|
|
1691
|
+
|
|
1692
|
+
_SuperTest
|
|
1693
|
+
.post('1.0/Book')
|
|
1694
|
+
.send({ Title: 'Post-op hook target' })
|
|
1695
|
+
.end(
|
|
1696
|
+
(pError, pResponse) =>
|
|
1697
|
+
{
|
|
1698
|
+
const tmpResult = JSON.parse(pResponse.text);
|
|
1699
|
+
Expect(_SeenIDBook).to.be.above(0);
|
|
1700
|
+
Expect(tmpResult.PostOpTag).to.equal('was-here');
|
|
1701
|
+
|
|
1702
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Create-PostOperation'];
|
|
1703
|
+
fDone();
|
|
1704
|
+
}
|
|
1705
|
+
);
|
|
1706
|
+
}
|
|
1707
|
+
);
|
|
1708
|
+
test
|
|
1709
|
+
(
|
|
1710
|
+
'setBehavior: CreateBulk-PreOperation fires once with RecordsToBulkCreate',
|
|
1711
|
+
function (fDone)
|
|
1712
|
+
{
|
|
1713
|
+
let _CallCount = 0;
|
|
1714
|
+
let _SawRecords = false;
|
|
1715
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('CreateBulk-PreOperation',
|
|
1716
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1717
|
+
{
|
|
1718
|
+
_CallCount++;
|
|
1719
|
+
_SawRecords = Array.isArray(pRequest.RecordsToBulkCreate);
|
|
1720
|
+
return fCallback();
|
|
1721
|
+
});
|
|
1722
|
+
|
|
1723
|
+
_SuperTest
|
|
1724
|
+
.post('1.0/Books')
|
|
1725
|
+
.send([
|
|
1726
|
+
{ Title: 'Bulk Create 1' },
|
|
1727
|
+
{ Title: 'Bulk Create 2' },
|
|
1728
|
+
])
|
|
1729
|
+
.end(
|
|
1730
|
+
(pError, pResponse) =>
|
|
1731
|
+
{
|
|
1732
|
+
Expect(_CallCount).to.equal(1);
|
|
1733
|
+
Expect(_SawRecords).to.equal(true);
|
|
1734
|
+
|
|
1735
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['CreateBulk-PreOperation'];
|
|
1736
|
+
fDone();
|
|
1737
|
+
}
|
|
1738
|
+
);
|
|
1739
|
+
}
|
|
1740
|
+
);
|
|
1741
|
+
test
|
|
1742
|
+
(
|
|
1743
|
+
'setBehavior: CreateBulk-PostOperation fires once with CreatedRecords',
|
|
1744
|
+
function (fDone)
|
|
1745
|
+
{
|
|
1746
|
+
let _SawCreated = null;
|
|
1747
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('CreateBulk-PostOperation',
|
|
1748
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1749
|
+
{
|
|
1750
|
+
_SawCreated = Array.isArray(pRequestState.CreatedRecords) && pRequestState.CreatedRecords.length;
|
|
1751
|
+
return fCallback();
|
|
1752
|
+
});
|
|
1753
|
+
|
|
1754
|
+
_SuperTest
|
|
1755
|
+
.post('1.0/Books')
|
|
1756
|
+
.send([
|
|
1757
|
+
{ Title: 'Bulk Create Post 1' },
|
|
1758
|
+
])
|
|
1759
|
+
.end(
|
|
1760
|
+
(pError, pResponse) =>
|
|
1761
|
+
{
|
|
1762
|
+
Expect(_SawCreated).to.equal(1);
|
|
1763
|
+
|
|
1764
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['CreateBulk-PostOperation'];
|
|
1765
|
+
fDone();
|
|
1766
|
+
}
|
|
1767
|
+
);
|
|
1768
|
+
}
|
|
1769
|
+
);
|
|
1770
|
+
test
|
|
1771
|
+
(
|
|
1772
|
+
'setBehavior: Delete-QueryConfiguration can scope the delete query',
|
|
1773
|
+
function (fDone)
|
|
1774
|
+
{
|
|
1775
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Delete-QueryConfiguration',
|
|
1776
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1777
|
+
{
|
|
1778
|
+
Expect(pRequestState.Query).to.exist;
|
|
1779
|
+
return fCallback();
|
|
1780
|
+
});
|
|
1781
|
+
|
|
1782
|
+
// Use a record we don't care about the state of; create one inline.
|
|
1783
|
+
_SuperTest
|
|
1784
|
+
.post('1.0/Book')
|
|
1785
|
+
.send({ Title: 'Delete-Query target' })
|
|
1786
|
+
.end(
|
|
1787
|
+
(pPostErr, pPostRes) =>
|
|
1788
|
+
{
|
|
1789
|
+
const tmpID = JSON.parse(pPostRes.text).IDBook;
|
|
1790
|
+
_SuperTest
|
|
1791
|
+
.delete(`1.0/Book/${tmpID}`)
|
|
1792
|
+
.end(
|
|
1793
|
+
(pDelErr, pDelRes) =>
|
|
1794
|
+
{
|
|
1795
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Delete-QueryConfiguration'];
|
|
1796
|
+
fDone();
|
|
1797
|
+
}
|
|
1798
|
+
);
|
|
1799
|
+
}
|
|
1800
|
+
);
|
|
1801
|
+
}
|
|
1802
|
+
);
|
|
1803
|
+
test
|
|
1804
|
+
(
|
|
1805
|
+
'setBehavior: Delete-PostOperation fires after soft-delete',
|
|
1806
|
+
function (fDone)
|
|
1807
|
+
{
|
|
1808
|
+
let _HookFired = false;
|
|
1809
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Delete-PostOperation',
|
|
1810
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1811
|
+
{
|
|
1812
|
+
_HookFired = true;
|
|
1813
|
+
return fCallback();
|
|
1814
|
+
});
|
|
1815
|
+
|
|
1816
|
+
_SuperTest
|
|
1817
|
+
.post('1.0/Book')
|
|
1818
|
+
.send({ Title: 'Delete-Post target' })
|
|
1819
|
+
.end(
|
|
1820
|
+
(pPostErr, pPostRes) =>
|
|
1821
|
+
{
|
|
1822
|
+
const tmpID = JSON.parse(pPostRes.text).IDBook;
|
|
1823
|
+
_SuperTest
|
|
1824
|
+
.delete(`1.0/Book/${tmpID}`)
|
|
1825
|
+
.end(
|
|
1826
|
+
() =>
|
|
1827
|
+
{
|
|
1828
|
+
Expect(_HookFired).to.equal(true);
|
|
1829
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Delete-PostOperation'];
|
|
1830
|
+
fDone();
|
|
1831
|
+
}
|
|
1832
|
+
);
|
|
1833
|
+
}
|
|
1834
|
+
);
|
|
1835
|
+
}
|
|
1836
|
+
);
|
|
1837
|
+
test
|
|
1838
|
+
(
|
|
1839
|
+
'setBehavior: Read-QueryConfiguration runs after filter is applied',
|
|
1840
|
+
function (fDone)
|
|
1841
|
+
{
|
|
1842
|
+
let _SeenCriteria = null;
|
|
1843
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Read-QueryConfiguration',
|
|
1844
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1845
|
+
{
|
|
1846
|
+
_SeenCriteria = pRequestState.RecordSearchCriteria;
|
|
1847
|
+
return fCallback();
|
|
1848
|
+
});
|
|
1849
|
+
|
|
1850
|
+
_SuperTest
|
|
1851
|
+
.get('1.0/Book/1')
|
|
1852
|
+
.end(
|
|
1853
|
+
() =>
|
|
1854
|
+
{
|
|
1855
|
+
Expect(_SeenCriteria).to.be.a('string').and.satisfy((pS) => pS.includes('IDBook'));
|
|
1856
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Read-QueryConfiguration'];
|
|
1857
|
+
fDone();
|
|
1858
|
+
}
|
|
1859
|
+
);
|
|
1860
|
+
}
|
|
1861
|
+
);
|
|
1862
|
+
test
|
|
1863
|
+
(
|
|
1864
|
+
'setBehavior: Reads-PostOperation fires after list load',
|
|
1865
|
+
function (fDone)
|
|
1866
|
+
{
|
|
1867
|
+
let _SawRecords = false;
|
|
1868
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Reads-PostOperation',
|
|
1869
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1870
|
+
{
|
|
1871
|
+
_SawRecords = Array.isArray(pRequestState.Records) && pRequestState.Records.length > 0;
|
|
1872
|
+
return fCallback();
|
|
1873
|
+
});
|
|
1874
|
+
|
|
1875
|
+
_SuperTest
|
|
1876
|
+
.get('1.0/Books/0/10')
|
|
1877
|
+
.end(
|
|
1878
|
+
() =>
|
|
1879
|
+
{
|
|
1880
|
+
Expect(_SawRecords).to.equal(true);
|
|
1881
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Reads-PostOperation'];
|
|
1882
|
+
fDone();
|
|
1883
|
+
}
|
|
1884
|
+
);
|
|
1885
|
+
}
|
|
1886
|
+
);
|
|
1887
|
+
test
|
|
1888
|
+
(
|
|
1889
|
+
'setBehavior: ReadMax-QueryConfiguration fires with column name',
|
|
1890
|
+
function (fDone)
|
|
1891
|
+
{
|
|
1892
|
+
let _SeenColumn = null;
|
|
1893
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('ReadMax-QueryConfiguration',
|
|
1894
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1895
|
+
{
|
|
1896
|
+
_SeenColumn = pRequestState.ColumnName;
|
|
1897
|
+
return fCallback();
|
|
1898
|
+
});
|
|
1899
|
+
|
|
1900
|
+
_SuperTest
|
|
1901
|
+
.get('1.0/Book/Max/PublicationYear')
|
|
1902
|
+
.end(
|
|
1903
|
+
() =>
|
|
1904
|
+
{
|
|
1905
|
+
Expect(_SeenColumn).to.equal('PublicationYear');
|
|
1906
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['ReadMax-QueryConfiguration'];
|
|
1907
|
+
fDone();
|
|
1908
|
+
}
|
|
1909
|
+
);
|
|
1910
|
+
}
|
|
1911
|
+
);
|
|
1912
|
+
test
|
|
1913
|
+
(
|
|
1914
|
+
'setBehavior: ReadMax-PostOperation fires after max lookup',
|
|
1915
|
+
function (fDone)
|
|
1916
|
+
{
|
|
1917
|
+
let _HookFired = false;
|
|
1918
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('ReadMax-PostOperation',
|
|
1919
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1920
|
+
{
|
|
1921
|
+
_HookFired = true;
|
|
1922
|
+
return fCallback();
|
|
1923
|
+
});
|
|
1924
|
+
|
|
1925
|
+
_SuperTest
|
|
1926
|
+
.get('1.0/Book/Max/PublicationYear')
|
|
1927
|
+
.end(
|
|
1928
|
+
() =>
|
|
1929
|
+
{
|
|
1930
|
+
Expect(_HookFired).to.equal(true);
|
|
1931
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['ReadMax-PostOperation'];
|
|
1932
|
+
fDone();
|
|
1933
|
+
}
|
|
1934
|
+
);
|
|
1935
|
+
}
|
|
1936
|
+
);
|
|
1937
|
+
test
|
|
1938
|
+
(
|
|
1939
|
+
'setBehavior: CountBy-QueryConfiguration can modify count-by query',
|
|
1940
|
+
function (fDone)
|
|
1941
|
+
{
|
|
1942
|
+
let _HookFired = false;
|
|
1943
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('CountBy-QueryConfiguration',
|
|
1944
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1945
|
+
{
|
|
1946
|
+
_HookFired = true;
|
|
1947
|
+
Expect(pRequestState.Query).to.exist;
|
|
1948
|
+
return fCallback();
|
|
1949
|
+
});
|
|
1950
|
+
|
|
1951
|
+
_SuperTest
|
|
1952
|
+
.get('1.0/Books/Count/By/Genre/Thriller')
|
|
1953
|
+
.end(
|
|
1954
|
+
() =>
|
|
1955
|
+
{
|
|
1956
|
+
Expect(_HookFired).to.equal(true);
|
|
1957
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['CountBy-QueryConfiguration'];
|
|
1958
|
+
fDone();
|
|
1959
|
+
}
|
|
1960
|
+
);
|
|
1961
|
+
}
|
|
1962
|
+
);
|
|
1963
|
+
test
|
|
1964
|
+
(
|
|
1965
|
+
'setBehavior: Undelete-PreOperation fires before undelete',
|
|
1966
|
+
function (fDone)
|
|
1967
|
+
{
|
|
1968
|
+
let _HookFired = false;
|
|
1969
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Undelete-PreOperation',
|
|
1970
|
+
(pRequest, pRequestState, fCallback) =>
|
|
1971
|
+
{
|
|
1972
|
+
_HookFired = true;
|
|
1973
|
+
return fCallback();
|
|
1974
|
+
});
|
|
1975
|
+
|
|
1976
|
+
// Create, delete, then undelete to hit the hook.
|
|
1977
|
+
_SuperTest
|
|
1978
|
+
.post('1.0/Book')
|
|
1979
|
+
.send({ Title: 'Undelete-Pre target' })
|
|
1980
|
+
.end(
|
|
1981
|
+
(pPostErr, pPostRes) =>
|
|
1982
|
+
{
|
|
1983
|
+
const tmpID = JSON.parse(pPostRes.text).IDBook;
|
|
1984
|
+
_SuperTest
|
|
1985
|
+
.delete(`1.0/Book/${tmpID}`)
|
|
1986
|
+
.end(
|
|
1987
|
+
() =>
|
|
1988
|
+
{
|
|
1989
|
+
_SuperTest
|
|
1990
|
+
.get(`1.0/Book/Undelete/${tmpID}`)
|
|
1991
|
+
.end(
|
|
1992
|
+
() =>
|
|
1993
|
+
{
|
|
1994
|
+
Expect(_HookFired).to.equal(true);
|
|
1995
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Undelete-PreOperation'];
|
|
1996
|
+
fDone();
|
|
1997
|
+
}
|
|
1998
|
+
);
|
|
1999
|
+
}
|
|
2000
|
+
);
|
|
2001
|
+
}
|
|
2002
|
+
);
|
|
2003
|
+
}
|
|
2004
|
+
);
|
|
2005
|
+
test
|
|
2006
|
+
(
|
|
2007
|
+
'setBehavior: Undelete-PostOperation fires after undelete',
|
|
2008
|
+
function (fDone)
|
|
2009
|
+
{
|
|
2010
|
+
let _HookFired = false;
|
|
2011
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Undelete-PostOperation',
|
|
2012
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2013
|
+
{
|
|
2014
|
+
_HookFired = true;
|
|
2015
|
+
return fCallback();
|
|
2016
|
+
});
|
|
2017
|
+
|
|
2018
|
+
_SuperTest
|
|
2019
|
+
.post('1.0/Book')
|
|
2020
|
+
.send({ Title: 'Undelete-Post target' })
|
|
2021
|
+
.end(
|
|
2022
|
+
(pPostErr, pPostRes) =>
|
|
2023
|
+
{
|
|
2024
|
+
const tmpID = JSON.parse(pPostRes.text).IDBook;
|
|
2025
|
+
_SuperTest
|
|
2026
|
+
.delete(`1.0/Book/${tmpID}`)
|
|
2027
|
+
.end(
|
|
2028
|
+
() =>
|
|
2029
|
+
{
|
|
2030
|
+
_SuperTest
|
|
2031
|
+
.get(`1.0/Book/Undelete/${tmpID}`)
|
|
2032
|
+
.end(
|
|
2033
|
+
() =>
|
|
2034
|
+
{
|
|
2035
|
+
Expect(_HookFired).to.equal(true);
|
|
2036
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Undelete-PostOperation'];
|
|
2037
|
+
fDone();
|
|
2038
|
+
}
|
|
2039
|
+
);
|
|
2040
|
+
}
|
|
2041
|
+
);
|
|
2042
|
+
}
|
|
2043
|
+
);
|
|
2044
|
+
}
|
|
2045
|
+
);
|
|
2046
|
+
test
|
|
2047
|
+
(
|
|
2048
|
+
'setBehavior: Schema-PreOperation fires before schema render',
|
|
2049
|
+
function (fDone)
|
|
2050
|
+
{
|
|
2051
|
+
let _HookFired = false;
|
|
2052
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Schema-PreOperation',
|
|
2053
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2054
|
+
{
|
|
2055
|
+
_HookFired = true;
|
|
2056
|
+
return fCallback();
|
|
2057
|
+
});
|
|
2058
|
+
|
|
2059
|
+
_SuperTest
|
|
2060
|
+
.get('1.0/Book/Schema')
|
|
2061
|
+
.end(
|
|
2062
|
+
() =>
|
|
2063
|
+
{
|
|
2064
|
+
Expect(_HookFired).to.equal(true);
|
|
2065
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Schema-PreOperation'];
|
|
2066
|
+
fDone();
|
|
2067
|
+
}
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
);
|
|
2071
|
+
test
|
|
2072
|
+
(
|
|
2073
|
+
'setBehavior: Validate-PreOperation fires before validate',
|
|
2074
|
+
function (fDone)
|
|
2075
|
+
{
|
|
2076
|
+
let _HookFired = false;
|
|
2077
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Validate-PreOperation',
|
|
2078
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2079
|
+
{
|
|
2080
|
+
_HookFired = true;
|
|
2081
|
+
return fCallback();
|
|
2082
|
+
});
|
|
2083
|
+
|
|
2084
|
+
_SuperTest
|
|
2085
|
+
.post('1.0/Book/Schema/Validate')
|
|
2086
|
+
.send({ Title: 'Validate target' })
|
|
2087
|
+
.end(
|
|
2088
|
+
() =>
|
|
2089
|
+
{
|
|
2090
|
+
Expect(_HookFired).to.equal(true);
|
|
2091
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Validate-PreOperation'];
|
|
2092
|
+
fDone();
|
|
2093
|
+
}
|
|
2094
|
+
);
|
|
2095
|
+
}
|
|
2096
|
+
);
|
|
2097
|
+
test
|
|
2098
|
+
(
|
|
2099
|
+
'setBehavior: Validate-PostOperation fires after validate',
|
|
2100
|
+
function (fDone)
|
|
2101
|
+
{
|
|
2102
|
+
let _HookFired = false;
|
|
2103
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Validate-PostOperation',
|
|
2104
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2105
|
+
{
|
|
2106
|
+
_HookFired = true;
|
|
2107
|
+
return fCallback();
|
|
2108
|
+
});
|
|
2109
|
+
|
|
2110
|
+
_SuperTest
|
|
2111
|
+
.post('1.0/Book/Schema/Validate')
|
|
2112
|
+
.send({ Title: 'Validate target 2' })
|
|
2113
|
+
.end(
|
|
2114
|
+
() =>
|
|
2115
|
+
{
|
|
2116
|
+
Expect(_HookFired).to.equal(true);
|
|
2117
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Validate-PostOperation'];
|
|
2118
|
+
fDone();
|
|
2119
|
+
}
|
|
2120
|
+
);
|
|
2121
|
+
}
|
|
2122
|
+
);
|
|
2123
|
+
test
|
|
2124
|
+
(
|
|
2125
|
+
'setBehavior: New-PreOperation fires before empty record render',
|
|
2126
|
+
function (fDone)
|
|
2127
|
+
{
|
|
2128
|
+
let _HookFired = false;
|
|
2129
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('New-PreOperation',
|
|
2130
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2131
|
+
{
|
|
2132
|
+
_HookFired = true;
|
|
2133
|
+
return fCallback();
|
|
2134
|
+
});
|
|
2135
|
+
|
|
2136
|
+
_SuperTest
|
|
2137
|
+
.get('1.0/Book/Schema/New')
|
|
2138
|
+
.end(
|
|
2139
|
+
() =>
|
|
2140
|
+
{
|
|
2141
|
+
Expect(_HookFired).to.equal(true);
|
|
2142
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['New-PreOperation'];
|
|
2143
|
+
fDone();
|
|
2144
|
+
}
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
);
|
|
1411
2148
|
}
|
|
1412
2149
|
);
|
|
1413
2150
|
|
|
@@ -1667,5 +2404,337 @@ suite
|
|
|
1667
2404
|
);
|
|
1668
2405
|
}
|
|
1669
2406
|
);
|
|
2407
|
+
|
|
2408
|
+
// ======================================================================
|
|
2409
|
+
// v4.0.17 additions: Create-PreRequest, OriginalRecord retention,
|
|
2410
|
+
// Reads-PostOperation on Lite / Select / Distinct list endpoints.
|
|
2411
|
+
// ======================================================================
|
|
2412
|
+
suite
|
|
2413
|
+
(
|
|
2414
|
+
'Create-PreRequest fires before Create-Operation',
|
|
2415
|
+
() =>
|
|
2416
|
+
{
|
|
2417
|
+
test
|
|
2418
|
+
(
|
|
2419
|
+
'setBehavior: Create-PreRequest hook fires before the operation pipeline',
|
|
2420
|
+
function (fDone)
|
|
2421
|
+
{
|
|
2422
|
+
let tmpFired = false;
|
|
2423
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Create-PreRequest',
|
|
2424
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2425
|
+
{
|
|
2426
|
+
tmpFired = true;
|
|
2427
|
+
// At this stage the operation hasn't started — Record
|
|
2428
|
+
// should be undefined, RecordToCreate shouldn't exist yet
|
|
2429
|
+
// either. The HTTP body is the only record source.
|
|
2430
|
+
Expect(pRequestState.Record).to.be.undefined;
|
|
2431
|
+
Expect(pRequest.body.Title).to.equal('PreRequest Test');
|
|
2432
|
+
return fCallback();
|
|
2433
|
+
});
|
|
2434
|
+
|
|
2435
|
+
_SuperTest
|
|
2436
|
+
.post('1.0/Book')
|
|
2437
|
+
.send({ Title: 'PreRequest Test' })
|
|
2438
|
+
.end(
|
|
2439
|
+
(pError, pResponse) =>
|
|
2440
|
+
{
|
|
2441
|
+
Expect(tmpFired, 'Create-PreRequest did not fire').to.be.true;
|
|
2442
|
+
let tmpResult = JSON.parse(pResponse.text);
|
|
2443
|
+
Expect(tmpResult.Title).to.equal('PreRequest Test');
|
|
2444
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Create-PreRequest'];
|
|
2445
|
+
fDone();
|
|
2446
|
+
}
|
|
2447
|
+
);
|
|
2448
|
+
}
|
|
2449
|
+
);
|
|
2450
|
+
test
|
|
2451
|
+
(
|
|
2452
|
+
'setBehavior: Create-PreRequest hook can abort the operation',
|
|
2453
|
+
function (fDone)
|
|
2454
|
+
{
|
|
2455
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Create-PreRequest',
|
|
2456
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2457
|
+
{
|
|
2458
|
+
let tmpError = new Error('Rejected by pre-request');
|
|
2459
|
+
tmpError.StatusCode = 400;
|
|
2460
|
+
return fCallback(tmpError);
|
|
2461
|
+
});
|
|
2462
|
+
|
|
2463
|
+
_SuperTest
|
|
2464
|
+
.post('1.0/Book')
|
|
2465
|
+
.send({ Title: 'Should be rejected' })
|
|
2466
|
+
.end(
|
|
2467
|
+
(pError, pResponse) =>
|
|
2468
|
+
{
|
|
2469
|
+
let tmpResult = JSON.parse(pResponse.text);
|
|
2470
|
+
Expect(tmpResult).to.have.property('Error');
|
|
2471
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Create-PreRequest'];
|
|
2472
|
+
fDone();
|
|
2473
|
+
}
|
|
2474
|
+
);
|
|
2475
|
+
}
|
|
2476
|
+
);
|
|
2477
|
+
test
|
|
2478
|
+
(
|
|
2479
|
+
'setBehavior: CreateBulk-PreRequest fires before per-record operations',
|
|
2480
|
+
function (fDone)
|
|
2481
|
+
{
|
|
2482
|
+
let tmpFired = false;
|
|
2483
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('CreateBulk-PreRequest',
|
|
2484
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2485
|
+
{
|
|
2486
|
+
tmpFired = true;
|
|
2487
|
+
Expect(Array.isArray(pRequest.RecordsToBulkCreate)).to.be.true;
|
|
2488
|
+
Expect(pRequest.RecordsToBulkCreate).to.have.lengthOf(2);
|
|
2489
|
+
return fCallback();
|
|
2490
|
+
});
|
|
2491
|
+
|
|
2492
|
+
_SuperTest
|
|
2493
|
+
.post('1.0/Books')
|
|
2494
|
+
.send([ { Title: 'Bulk A' }, { Title: 'Bulk B' } ])
|
|
2495
|
+
.end(
|
|
2496
|
+
(pError, pResponse) =>
|
|
2497
|
+
{
|
|
2498
|
+
Expect(tmpFired, 'CreateBulk-PreRequest did not fire').to.be.true;
|
|
2499
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['CreateBulk-PreRequest'];
|
|
2500
|
+
fDone();
|
|
2501
|
+
}
|
|
2502
|
+
);
|
|
2503
|
+
}
|
|
2504
|
+
);
|
|
2505
|
+
}
|
|
2506
|
+
);
|
|
2507
|
+
|
|
2508
|
+
suite
|
|
2509
|
+
(
|
|
2510
|
+
'OriginalRecord retained on pRequestState after Update/Delete/Undelete',
|
|
2511
|
+
() =>
|
|
2512
|
+
{
|
|
2513
|
+
let _OriginalTestID = 0;
|
|
2514
|
+
test
|
|
2515
|
+
(
|
|
2516
|
+
'pre-op: create a seed record for OriginalRecord testing',
|
|
2517
|
+
function (fDone)
|
|
2518
|
+
{
|
|
2519
|
+
_SuperTest
|
|
2520
|
+
.post('1.0/Book')
|
|
2521
|
+
.send({ Title: 'Original Title', Genre: 'Original Genre' })
|
|
2522
|
+
.end(
|
|
2523
|
+
(pError, pResponse) =>
|
|
2524
|
+
{
|
|
2525
|
+
let tmpResult = JSON.parse(pResponse.text);
|
|
2526
|
+
_OriginalTestID = tmpResult.IDBook;
|
|
2527
|
+
Expect(_OriginalTestID).to.be.above(0);
|
|
2528
|
+
fDone();
|
|
2529
|
+
}
|
|
2530
|
+
);
|
|
2531
|
+
}
|
|
2532
|
+
);
|
|
2533
|
+
test
|
|
2534
|
+
(
|
|
2535
|
+
'Update-PostOperation: pRequestState.OriginalRecord holds the pre-update row',
|
|
2536
|
+
function (fDone)
|
|
2537
|
+
{
|
|
2538
|
+
let tmpSeenOriginal = null;
|
|
2539
|
+
let tmpSeenRecord = null;
|
|
2540
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Update-PostOperation',
|
|
2541
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2542
|
+
{
|
|
2543
|
+
tmpSeenOriginal = pRequestState.OriginalRecord;
|
|
2544
|
+
tmpSeenRecord = pRequestState.Record;
|
|
2545
|
+
return fCallback();
|
|
2546
|
+
});
|
|
2547
|
+
|
|
2548
|
+
_SuperTest
|
|
2549
|
+
.put('1.0/Book')
|
|
2550
|
+
.send({ IDBook: _OriginalTestID, Title: 'Updated Title', Genre: 'Updated Genre' })
|
|
2551
|
+
.end(
|
|
2552
|
+
(pError, pResponse) =>
|
|
2553
|
+
{
|
|
2554
|
+
Expect(tmpSeenOriginal, 'OriginalRecord should be set at post-op').to.not.be.null;
|
|
2555
|
+
Expect(tmpSeenOriginal.Title).to.equal('Original Title');
|
|
2556
|
+
Expect(tmpSeenRecord.Title).to.equal('Updated Title');
|
|
2557
|
+
// The two references must be DIFFERENT objects — the
|
|
2558
|
+
// operation overwrites Record with the post-update row
|
|
2559
|
+
// while OriginalRecord keeps the pre-update reference.
|
|
2560
|
+
Expect(tmpSeenOriginal).to.not.equal(tmpSeenRecord);
|
|
2561
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Update-PostOperation'];
|
|
2562
|
+
fDone();
|
|
2563
|
+
}
|
|
2564
|
+
);
|
|
2565
|
+
}
|
|
2566
|
+
);
|
|
2567
|
+
test
|
|
2568
|
+
(
|
|
2569
|
+
'Delete-PostOperation: pRequestState.OriginalRecord holds the pre-delete row',
|
|
2570
|
+
function (fDone)
|
|
2571
|
+
{
|
|
2572
|
+
let tmpSeenOriginal = null;
|
|
2573
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Delete-PostOperation',
|
|
2574
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2575
|
+
{
|
|
2576
|
+
tmpSeenOriginal = pRequestState.OriginalRecord;
|
|
2577
|
+
return fCallback();
|
|
2578
|
+
});
|
|
2579
|
+
|
|
2580
|
+
_SuperTest
|
|
2581
|
+
.delete(`1.0/Book/${_OriginalTestID}`)
|
|
2582
|
+
.end(
|
|
2583
|
+
(pError, pResponse) =>
|
|
2584
|
+
{
|
|
2585
|
+
Expect(tmpSeenOriginal, 'OriginalRecord should be set at delete post-op').to.not.be.null;
|
|
2586
|
+
Expect(tmpSeenOriginal.IDBook).to.equal(_OriginalTestID);
|
|
2587
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Delete-PostOperation'];
|
|
2588
|
+
fDone();
|
|
2589
|
+
}
|
|
2590
|
+
);
|
|
2591
|
+
}
|
|
2592
|
+
);
|
|
2593
|
+
test
|
|
2594
|
+
(
|
|
2595
|
+
'Undelete-PostOperation: pRequestState.OriginalRecord holds the pre-undelete row',
|
|
2596
|
+
function (fDone)
|
|
2597
|
+
{
|
|
2598
|
+
let tmpSeenOriginal = null;
|
|
2599
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Undelete-PostOperation',
|
|
2600
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2601
|
+
{
|
|
2602
|
+
tmpSeenOriginal = pRequestState.OriginalRecord;
|
|
2603
|
+
return fCallback();
|
|
2604
|
+
});
|
|
2605
|
+
|
|
2606
|
+
_SuperTest
|
|
2607
|
+
.get(`1.0/Book/Undelete/${_OriginalTestID}`)
|
|
2608
|
+
.end(
|
|
2609
|
+
(pError, pResponse) =>
|
|
2610
|
+
{
|
|
2611
|
+
Expect(tmpSeenOriginal, 'OriginalRecord should be set at undelete post-op').to.not.be.null;
|
|
2612
|
+
Expect(tmpSeenOriginal.IDBook).to.equal(_OriginalTestID);
|
|
2613
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Undelete-PostOperation'];
|
|
2614
|
+
fDone();
|
|
2615
|
+
}
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
);
|
|
2619
|
+
}
|
|
2620
|
+
);
|
|
2621
|
+
|
|
2622
|
+
suite
|
|
2623
|
+
(
|
|
2624
|
+
'Stage-specific PostOperation hooks on Lite / SelectList / Distinct list endpoints',
|
|
2625
|
+
() =>
|
|
2626
|
+
{
|
|
2627
|
+
test
|
|
2628
|
+
(
|
|
2629
|
+
'ReadsLite-PostOperation fires on /s/Lite and receives loaded records before marshal (ME 2.x hash)',
|
|
2630
|
+
function (fDone)
|
|
2631
|
+
{
|
|
2632
|
+
let tmpFired = false;
|
|
2633
|
+
let tmpSeenRecords = null;
|
|
2634
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('ReadsLite-PostOperation',
|
|
2635
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2636
|
+
{
|
|
2637
|
+
tmpFired = true;
|
|
2638
|
+
tmpSeenRecords = pRequestState.Records;
|
|
2639
|
+
return fCallback();
|
|
2640
|
+
});
|
|
2641
|
+
|
|
2642
|
+
_SuperTest
|
|
2643
|
+
.get('1.0/Books/Lite')
|
|
2644
|
+
.end(
|
|
2645
|
+
(pError, pResponse) =>
|
|
2646
|
+
{
|
|
2647
|
+
Expect(tmpFired, 'ReadsLite-PostOperation did not fire on lite list').to.be.true;
|
|
2648
|
+
Expect(Array.isArray(tmpSeenRecords)).to.be.true;
|
|
2649
|
+
// Hook runs BEFORE marshalling — records should still
|
|
2650
|
+
// have their full-row shape (Title + Genre + IDBook etc.),
|
|
2651
|
+
// not the lite (Hash/Value) shape the client receives.
|
|
2652
|
+
if (tmpSeenRecords.length > 0)
|
|
2653
|
+
{
|
|
2654
|
+
Expect(tmpSeenRecords[0]).to.have.property('IDBook');
|
|
2655
|
+
}
|
|
2656
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['ReadsLite-PostOperation'];
|
|
2657
|
+
fDone();
|
|
2658
|
+
}
|
|
2659
|
+
);
|
|
2660
|
+
}
|
|
2661
|
+
);
|
|
2662
|
+
test
|
|
2663
|
+
(
|
|
2664
|
+
'Reads-PostOperation does NOT fire on /s/Lite (stage isolation)',
|
|
2665
|
+
function (fDone)
|
|
2666
|
+
{
|
|
2667
|
+
let tmpFiredReads = false;
|
|
2668
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('Reads-PostOperation',
|
|
2669
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2670
|
+
{
|
|
2671
|
+
tmpFiredReads = true;
|
|
2672
|
+
return fCallback();
|
|
2673
|
+
});
|
|
2674
|
+
|
|
2675
|
+
_SuperTest
|
|
2676
|
+
.get('1.0/Books/Lite')
|
|
2677
|
+
.end(
|
|
2678
|
+
() =>
|
|
2679
|
+
{
|
|
2680
|
+
Expect(tmpFiredReads, 'Reads-PostOperation should NOT fire on lite list — consumers register at ReadsLite-PostOperation').to.be.false;
|
|
2681
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['Reads-PostOperation'];
|
|
2682
|
+
fDone();
|
|
2683
|
+
}
|
|
2684
|
+
);
|
|
2685
|
+
}
|
|
2686
|
+
);
|
|
2687
|
+
test
|
|
2688
|
+
(
|
|
2689
|
+
'ReadSelectList-PostOperation fires on /Select before marshal',
|
|
2690
|
+
function (fDone)
|
|
2691
|
+
{
|
|
2692
|
+
let tmpFired = false;
|
|
2693
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('ReadSelectList-PostOperation',
|
|
2694
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2695
|
+
{
|
|
2696
|
+
tmpFired = true;
|
|
2697
|
+
return fCallback();
|
|
2698
|
+
});
|
|
2699
|
+
|
|
2700
|
+
_SuperTest
|
|
2701
|
+
.get('1.0/BookSelect')
|
|
2702
|
+
.end(
|
|
2703
|
+
(pError, pResponse) =>
|
|
2704
|
+
{
|
|
2705
|
+
Expect(tmpFired, 'ReadSelectList-PostOperation did not fire on select list').to.be.true;
|
|
2706
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['ReadSelectList-PostOperation'];
|
|
2707
|
+
fDone();
|
|
2708
|
+
}
|
|
2709
|
+
);
|
|
2710
|
+
}
|
|
2711
|
+
);
|
|
2712
|
+
test
|
|
2713
|
+
(
|
|
2714
|
+
'ReadDistinct-PostOperation fires on /s/Distinct/:Columns before marshal',
|
|
2715
|
+
function (fDone)
|
|
2716
|
+
{
|
|
2717
|
+
let tmpFired = false;
|
|
2718
|
+
_MeadowEndpoints.controller.BehaviorInjection.setBehavior('ReadDistinct-PostOperation',
|
|
2719
|
+
(pRequest, pRequestState, fCallback) =>
|
|
2720
|
+
{
|
|
2721
|
+
tmpFired = true;
|
|
2722
|
+
return fCallback();
|
|
2723
|
+
});
|
|
2724
|
+
|
|
2725
|
+
_SuperTest
|
|
2726
|
+
.get('1.0/Books/Distinct/Genre')
|
|
2727
|
+
.end(
|
|
2728
|
+
(pError, pResponse) =>
|
|
2729
|
+
{
|
|
2730
|
+
Expect(tmpFired, 'ReadDistinct-PostOperation did not fire on distinct list').to.be.true;
|
|
2731
|
+
delete _MeadowEndpoints.controller.BehaviorInjection._BehaviorFunctions['ReadDistinct-PostOperation'];
|
|
2732
|
+
fDone();
|
|
2733
|
+
}
|
|
2734
|
+
);
|
|
2735
|
+
}
|
|
2736
|
+
);
|
|
2737
|
+
}
|
|
2738
|
+
);
|
|
1670
2739
|
}
|
|
1671
2740
|
);
|