@@ -1337,6 +1337,111 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
1337
1337
)
1338
1338
}
1339
1339
1340
+ // NB: Only needed until Xcode ships a macOS SDK that uses the 5.7 standard library.
1341
+ // See: https://forums.swift.org/t/xcode-14-rc-cannot-specialize-protocol-type/60171/15
1342
+ #if swift(>=5.7) && !os(macOS) && !targetEnvironment(macCatalyst)
1343
+ /// Asserts an action was received from an effect and asserts how the state changes.
1344
+ ///
1345
+ /// When an effect is executed in your feature and sends an action back into the system, you can
1346
+ /// use this method to assert that fact, and further assert how state changes after the effect
1347
+ /// action is received:
1348
+ ///
1349
+ /// ```swift
1350
+ /// await store.send(.buttonTapped)
1351
+ /// await store.receive(.response(.success(42)) {
1352
+ /// $0.count = 42
1353
+ /// }
1354
+ /// ```
1355
+ ///
1356
+ /// Due to the variability of concurrency in Swift, sometimes a small amount of time needs to
1357
+ /// pass before effects execute and send actions, and that is why this method suspends. The
1358
+ /// default time waited is very small, and typically it is enough so you should be controlling
1359
+ /// your dependencies so that they do not wait for real world time to pass (see
1360
+ /// <doc:DependencyManagement> for more information on how to do that).
1361
+ ///
1362
+ /// To change the amount of time this method waits for an action, pass an explicit `timeout`
1363
+ /// argument, or set the ``timeout`` on the ``TestStore``.
1364
+ ///
1365
+ /// - Parameters:
1366
+ /// - expectedAction: An action expected from an effect.
1367
+ /// - duration: The amount of time to wait for the expected action.
1368
+ /// - updateStateToExpectedResult: A closure that asserts state changed by sending the action
1369
+ /// to the store. The mutable state sent to this closure must be modified to match the state
1370
+ /// of the store after processing the given action. Do not provide a closure if no change
1371
+ /// is expected.
1372
+ @available ( iOS 16 , macOS 13 , tvOS 16 , watchOS 9 , * )
1373
+ @MainActor
1374
+ public func receive(
1375
+ _ expectedAction: Action ,
1376
+ timeout duration: Duration ,
1377
+ assert updateStateToExpectedResult: ( ( inout ScopedState ) throws -> Void ) ? = nil ,
1378
+ file: StaticString = #file,
1379
+ line: UInt = #line
1380
+ ) async {
1381
+ await self . receive (
1382
+ expectedAction,
1383
+ timeout: duration. nanoseconds,
1384
+ assert: updateStateToExpectedResult,
1385
+ file: file,
1386
+ line: line
1387
+ )
1388
+ }
1389
+ #endif
1390
+
1391
+ /// Asserts an action was received from an effect and asserts how the state changes.
1392
+ ///
1393
+ /// When an effect is executed in your feature and sends an action back into the system, you can
1394
+ /// use this method to assert that fact, and further assert how state changes after the effect
1395
+ /// action is received:
1396
+ ///
1397
+ /// ```swift
1398
+ /// await store.send(.buttonTapped)
1399
+ /// await store.receive(.response(.success(42)) {
1400
+ /// $0.count = 42
1401
+ /// }
1402
+ /// ```
1403
+ ///
1404
+ /// Due to the variability of concurrency in Swift, sometimes a small amount of time needs to pass
1405
+ /// before effects execute and send actions, and that is why this method suspends. The default
1406
+ /// time waited is very small, and typically it is enough so you should be controlling your
1407
+ /// dependencies so that they do not wait for real world time to pass (see
1408
+ /// <doc:DependencyManagement> for more information on how to do that).
1409
+ ///
1410
+ /// To change the amount of time this method waits for an action, pass an explicit `timeout`
1411
+ /// argument, or set the ``timeout`` on the ``TestStore``.
1412
+ ///
1413
+ /// - Parameters:
1414
+ /// - expectedAction: An action expected from an effect.
1415
+ /// - nanoseconds: The amount of time to wait for the expected action.
1416
+ /// - updateStateToExpectedResult: A closure that asserts state changed by sending the action to
1417
+ /// the store. The mutable state sent to this closure must be modified to match the state of
1418
+ /// the store after processing the given action. Do not provide a closure if no change is
1419
+ /// expected.
1420
+ @MainActor
1421
+ @_disfavoredOverload
1422
+ public func receive(
1423
+ _ expectedAction: Action ,
1424
+ timeout nanoseconds: UInt64 ? = nil ,
1425
+ assert updateStateToExpectedResult: ( ( inout ScopedState ) throws -> Void ) ? = nil ,
1426
+ file: StaticString = #file,
1427
+ line: UInt = #line
1428
+ ) async {
1429
+ guard !self . reducer. inFlightEffects. isEmpty
1430
+ else {
1431
+ _ = {
1432
+ self . receive ( expectedAction, assert: updateStateToExpectedResult, file: file, line: line)
1433
+ } ( )
1434
+ return
1435
+ }
1436
+ await self . receiveAction ( timeout: nanoseconds, file: file, line: line)
1437
+ _ = {
1438
+ self . receive ( expectedAction, assert: updateStateToExpectedResult, file: file, line: line)
1439
+ } ( )
1440
+ await Task . megaYield ( )
1441
+ }
1442
+ }
1443
+
1444
+ extension TestStore where ScopedState: Equatable {
1340
1445
/// Asserts a matching action was received from an effect and asserts how the state changes.
1341
1446
///
1342
1447
/// See ``receive(_:timeout:assert:file:line:)-3myco`` for more information of how to use this
@@ -1412,53 +1517,6 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
1412
1517
// NB: Only needed until Xcode ships a macOS SDK that uses the 5.7 standard library.
1413
1518
// See: https://forums.swift.org/t/xcode-14-rc-cannot-specialize-protocol-type/60171/15
1414
1519
#if swift(>=5.7) && !os(macOS) && !targetEnvironment(macCatalyst)
1415
- /// Asserts an action was received from an effect and asserts how the state changes.
1416
- ///
1417
- /// When an effect is executed in your feature and sends an action back into the system, you can
1418
- /// use this method to assert that fact, and further assert how state changes after the effect
1419
- /// action is received:
1420
- ///
1421
- /// ```swift
1422
- /// await store.send(.buttonTapped)
1423
- /// await store.receive(.response(.success(42)) {
1424
- /// $0.count = 42
1425
- /// }
1426
- /// ```
1427
- ///
1428
- /// Due to the variability of concurrency in Swift, sometimes a small amount of time needs to
1429
- /// pass before effects execute and send actions, and that is why this method suspends. The
1430
- /// default time waited is very small, and typically it is enough so you should be controlling
1431
- /// your dependencies so that they do not wait for real world time to pass (see
1432
- /// <doc:DependencyManagement> for more information on how to do that).
1433
- ///
1434
- /// To change the amount of time this method waits for an action, pass an explicit `timeout`
1435
- /// argument, or set the ``timeout`` on the ``TestStore``.
1436
- ///
1437
- /// - Parameters:
1438
- /// - expectedAction: An action expected from an effect.
1439
- /// - duration: The amount of time to wait for the expected action.
1440
- /// - updateStateToExpectedResult: A closure that asserts state changed by sending the action
1441
- /// to the store. The mutable state sent to this closure must be modified to match the state
1442
- /// of the store after processing the given action. Do not provide a closure if no change
1443
- /// is expected.
1444
- @available ( iOS 16 , macOS 13 , tvOS 16 , watchOS 9 , * )
1445
- @MainActor
1446
- public func receive(
1447
- _ expectedAction: Action ,
1448
- timeout duration: Duration ,
1449
- assert updateStateToExpectedResult: ( ( inout ScopedState ) throws -> Void ) ? = nil ,
1450
- file: StaticString = #file,
1451
- line: UInt = #line
1452
- ) async {
1453
- await self . receive (
1454
- expectedAction,
1455
- timeout: duration. nanoseconds,
1456
- assert: updateStateToExpectedResult,
1457
- file: file,
1458
- line: line
1459
- )
1460
- }
1461
-
1462
1520
/// Asserts an action was received from an effect that matches a predicate, and asserts how the
1463
1521
/// state changes.
1464
1522
///
@@ -1511,58 +1569,6 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
1511
1569
}
1512
1570
#endif
1513
1571
1514
- /// Asserts an action was received from an effect and asserts how the state changes.
1515
- ///
1516
- /// When an effect is executed in your feature and sends an action back into the system, you can
1517
- /// use this method to assert that fact, and further assert how state changes after the effect
1518
- /// action is received:
1519
- ///
1520
- /// ```swift
1521
- /// await store.send(.buttonTapped)
1522
- /// await store.receive(.response(.success(42)) {
1523
- /// $0.count = 42
1524
- /// }
1525
- /// ```
1526
- ///
1527
- /// Due to the variability of concurrency in Swift, sometimes a small amount of time needs to pass
1528
- /// before effects execute and send actions, and that is why this method suspends. The default
1529
- /// time waited is very small, and typically it is enough so you should be controlling your
1530
- /// dependencies so that they do not wait for real world time to pass (see
1531
- /// <doc:DependencyManagement> for more information on how to do that).
1532
- ///
1533
- /// To change the amount of time this method waits for an action, pass an explicit `timeout`
1534
- /// argument, or set the ``timeout`` on the ``TestStore``.
1535
- ///
1536
- /// - Parameters:
1537
- /// - expectedAction: An action expected from an effect.
1538
- /// - nanoseconds: The amount of time to wait for the expected action.
1539
- /// - updateStateToExpectedResult: A closure that asserts state changed by sending the action to
1540
- /// the store. The mutable state sent to this closure must be modified to match the state of
1541
- /// the store after processing the given action. Do not provide a closure if no change is
1542
- /// expected.
1543
- @MainActor
1544
- @_disfavoredOverload
1545
- public func receive(
1546
- _ expectedAction: Action ,
1547
- timeout nanoseconds: UInt64 ? = nil ,
1548
- assert updateStateToExpectedResult: ( ( inout ScopedState ) throws -> Void ) ? = nil ,
1549
- file: StaticString = #file,
1550
- line: UInt = #line
1551
- ) async {
1552
- guard !self . reducer. inFlightEffects. isEmpty
1553
- else {
1554
- _ = {
1555
- self . receive ( expectedAction, assert: updateStateToExpectedResult, file: file, line: line)
1556
- } ( )
1557
- return
1558
- }
1559
- await self . receiveAction ( timeout: nanoseconds, file: file, line: line)
1560
- _ = {
1561
- self . receive ( expectedAction, assert: updateStateToExpectedResult, file: file, line: line)
1562
- } ( )
1563
- await Task . megaYield ( )
1564
- }
1565
-
1566
1572
/// Asserts an action was received from an effect that matches a predicate, and asserts how the
1567
1573
/// state changes.
1568
1574
///
@@ -1760,10 +1766,9 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
1760
1766
while let receivedAction = self . reducer. receivedActions. first,
1761
1767
!predicate( receivedAction. action)
1762
1768
{
1769
+ self . reducer. receivedActions. removeFirst ( )
1763
1770
actions. append ( receivedAction. action)
1764
- self . withExhaustivity ( . off) {
1765
- self . receive ( receivedAction. action, file: file, line: line)
1766
- }
1771
+ self . reducer. state = receivedAction. state
1767
1772
}
1768
1773
1769
1774
if !actions. isEmpty {
0 commit comments