order.model.property.test.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import * as fc from 'fast-check';
  2. import {
  3. OrderStatus,
  4. VALID_ORDER_TRANSITIONS,
  5. isValidOrderTransition,
  6. generateOrderNo
  7. } from '../../../src/models/order.model';
  8. /**
  9. * **Feature: backend-frontend-integration, Property 3: Order Status Transition Validity**
  10. * **Validates: Requirements 2.5, 2.6**
  11. *
  12. * *For any* order status update, the new status SHALL only be reachable from valid previous states
  13. * (e.g., Shipped can only follow PendingShipment, Cancelled can only follow PendingPayment or PendingShipment).
  14. */
  15. describe('Order Model Property Tests', () => {
  16. // 所有订单状态
  17. const allStatuses = Object.values(OrderStatus);
  18. // 生成任意订单状态的arbitrary
  19. const orderStatusArb = fc.constantFrom(...allStatuses);
  20. describe('Property 3: Order Status Transition Validity', () => {
  21. it('should only allow valid status transitions as defined in VALID_ORDER_TRANSITIONS', () => {
  22. fc.assert(
  23. fc.property(
  24. orderStatusArb,
  25. orderStatusArb,
  26. (fromStatus, toStatus) => {
  27. const isValid = isValidOrderTransition(fromStatus, toStatus);
  28. const expectedValid = VALID_ORDER_TRANSITIONS[fromStatus].includes(toStatus);
  29. // 验证isValidOrderTransition函数与VALID_ORDER_TRANSITIONS映射一致
  30. return isValid === expectedValid;
  31. }
  32. ),
  33. { numRuns: 100 }
  34. );
  35. });
  36. it('Shipped status can only be reached from PendingShipment', () => {
  37. fc.assert(
  38. fc.property(
  39. orderStatusArb,
  40. (fromStatus) => {
  41. const canTransitionToShipped = isValidOrderTransition(fromStatus, OrderStatus.Shipped);
  42. // 只有PendingShipment可以转换到Shipped
  43. if (fromStatus === OrderStatus.PendingShipment) {
  44. return canTransitionToShipped === true;
  45. } else {
  46. return canTransitionToShipped === false;
  47. }
  48. }
  49. ),
  50. { numRuns: 100 }
  51. );
  52. });
  53. it('Completed status can only be reached from Shipped', () => {
  54. fc.assert(
  55. fc.property(
  56. orderStatusArb,
  57. (fromStatus) => {
  58. const canTransitionToCompleted = isValidOrderTransition(fromStatus, OrderStatus.Completed);
  59. // 只有Shipped可以转换到Completed
  60. if (fromStatus === OrderStatus.Shipped) {
  61. return canTransitionToCompleted === true;
  62. } else {
  63. return canTransitionToCompleted === false;
  64. }
  65. }
  66. ),
  67. { numRuns: 100 }
  68. );
  69. });
  70. it('Cancelled status can only be reached from PendingPayment or PendingShipment', () => {
  71. fc.assert(
  72. fc.property(
  73. orderStatusArb,
  74. (fromStatus) => {
  75. const canTransitionToCancelled = isValidOrderTransition(fromStatus, OrderStatus.Cancelled);
  76. // 只有PendingPayment和PendingShipment可以转换到Cancelled
  77. if (fromStatus === OrderStatus.PendingPayment || fromStatus === OrderStatus.PendingShipment) {
  78. return canTransitionToCancelled === true;
  79. } else {
  80. return canTransitionToCancelled === false;
  81. }
  82. }
  83. ),
  84. { numRuns: 100 }
  85. );
  86. });
  87. it('terminal states (Completed, Cancelled) cannot transition to any other state', () => {
  88. fc.assert(
  89. fc.property(
  90. orderStatusArb,
  91. (toStatus) => {
  92. // Completed和Cancelled是终态,不能转换到任何其他状态
  93. const fromCompleted = isValidOrderTransition(OrderStatus.Completed, toStatus);
  94. const fromCancelled = isValidOrderTransition(OrderStatus.Cancelled, toStatus);
  95. return fromCompleted === false && fromCancelled === false;
  96. }
  97. ),
  98. { numRuns: 100 }
  99. );
  100. });
  101. });
  102. describe('Order Number Generation', () => {
  103. it('should generate order numbers with correct format (yyyyMMddHHmmss + 6 digits)', () => {
  104. fc.assert(
  105. fc.property(
  106. fc.integer({ min: 1, max: 100 }),
  107. () => {
  108. const orderNo = generateOrderNo();
  109. // 订单号应该是20位:14位时间戳 + 6位随机数
  110. if (orderNo.length !== 20) return false;
  111. // 应该全是数字
  112. if (!/^\d{20}$/.test(orderNo)) return false;
  113. return true;
  114. }
  115. ),
  116. { numRuns: 100 }
  117. );
  118. });
  119. it('should generate unique order numbers', () => {
  120. fc.assert(
  121. fc.property(
  122. fc.integer({ min: 10, max: 50 }),
  123. (count) => {
  124. const orderNos = new Set<string>();
  125. for (let i = 0; i < count; i++) {
  126. orderNos.add(generateOrderNo());
  127. }
  128. // 生成的订单号应该都是唯一的
  129. return orderNos.size === count;
  130. }
  131. ),
  132. { numRuns: 20 }
  133. );
  134. });
  135. });
  136. });