@@ -1337,6 +1337,111 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
13371337 )
13381338 }
13391339
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 {
13401445 /// Asserts a matching action was received from an effect and asserts how the state changes.
13411446 ///
13421447 /// 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 {
14121517 // NB: Only needed until Xcode ships a macOS SDK that uses the 5.7 standard library.
14131518 // See: https://forums.swift.org/t/xcode-14-rc-cannot-specialize-protocol-type/60171/15
14141519 #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-
14621520 /// Asserts an action was received from an effect that matches a predicate, and asserts how the
14631521 /// state changes.
14641522 ///
@@ -1511,58 +1569,6 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
15111569 }
15121570 #endif
15131571
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-
15661572 /// Asserts an action was received from an effect that matches a predicate, and asserts how the
15671573 /// state changes.
15681574 ///
@@ -1760,10 +1766,9 @@ extension TestStore where ScopedState: Equatable, Action: Equatable {
17601766 while let receivedAction = self . reducer. receivedActions. first,
17611767 !predicate( receivedAction. action)
17621768 {
1769+ self . reducer. receivedActions. removeFirst ( )
17631770 actions. append ( receivedAction. action)
1764- self . withExhaustivity ( . off) {
1765- self . receive ( receivedAction. action, file: file, line: line)
1766- }
1771+ self . reducer. state = receivedAction. state
17671772 }
17681773
17691774 if !actions. isEmpty {
0 commit comments