From 45c03f0303acab90f905cb043dab94fcfdbc346b Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 24 Sep 2025 16:42:49 +0700 Subject: [PATCH 1/5] Add new Booking action and store --- .../Storage/Tools/StorageType+Deletions.swift | 13 ++ .../Tools/StorageType+Extensions.swift | 26 ++++ .../Yosemite/Actions/BookingAction.swift | 16 ++ .../Yosemite/Stores/BookingStore.swift | 142 ++++++++++++++++++ 4 files changed, 197 insertions(+) create mode 100644 Modules/Sources/Yosemite/Actions/BookingAction.swift create mode 100644 Modules/Sources/Yosemite/Stores/BookingStore.swift diff --git a/Modules/Sources/Storage/Tools/StorageType+Deletions.swift b/Modules/Sources/Storage/Tools/StorageType+Deletions.swift index 52a1fcecc9b..9c317be95d1 100644 --- a/Modules/Sources/Storage/Tools/StorageType+Deletions.swift +++ b/Modules/Sources/Storage/Tools/StorageType+Deletions.swift @@ -243,4 +243,17 @@ public extension StorageType { deleteObject($0) } } + + // MARK: - Bookings + + /// Deletes all of the stored Bookings for the provided siteID. + /// + func deleteBookings(siteID: Int64) { + guard let bookings = loadBookings(siteID: siteID) else { + return + } + for booking in bookings { + deleteObject(booking) + } + } } diff --git a/Modules/Sources/Storage/Tools/StorageType+Extensions.swift b/Modules/Sources/Storage/Tools/StorageType+Extensions.swift index 903b2c4004c..e313a7f6978 100644 --- a/Modules/Sources/Storage/Tools/StorageType+Extensions.swift +++ b/Modules/Sources/Storage/Tools/StorageType+Extensions.swift @@ -940,4 +940,30 @@ public extension StorageType { let predicate = \MetaData.product?.siteID == siteID && \MetaData.product?.productID == productID return allObjects(ofType: MetaData.self, matching: predicate, sortedBy: nil) } + + // MARK: - Bookings + + /// Retrieves the Stored Bookings given the IDs. + /// + func loadBookings(siteID: Int64, bookingIDs: [Int64]) -> [Booking] { + let predicate = NSPredicate(format: "siteID == %lld && bookingID in %@", siteID, bookingIDs) + let descriptor = NSSortDescriptor(keyPath: \Booking.bookingID, ascending: false) + return allObjects(ofType: Booking.self, matching: predicate, sortedBy: [descriptor]) + } + + /// Retrieves the Stored Booking. + /// + func loadBooking(siteID: Int64, bookingID: Int64) -> Booking? { + let predicate = \Booking.bookingID == bookingID && \Booking.siteID == siteID + return firstObject(ofType: Booking.self, matching: predicate) + } + + /// Retrieves all stored bookings for a site. + /// + func loadBookings(siteID: Int64) -> [Booking]? { + let predicate = \Booking.siteID == siteID + let descriptor = NSSortDescriptor(keyPath: \Booking.bookingID, ascending: false) + let objects = allObjects(ofType: Booking.self, matching: predicate, sortedBy: [descriptor]) + return objects.isEmpty ? nil : objects + } } diff --git a/Modules/Sources/Yosemite/Actions/BookingAction.swift b/Modules/Sources/Yosemite/Actions/BookingAction.swift new file mode 100644 index 00000000000..be7e8a1e8dd --- /dev/null +++ b/Modules/Sources/Yosemite/Actions/BookingAction.swift @@ -0,0 +1,16 @@ +import Foundation +import Networking + +/// BookingAction: Defines all of the Actions supported by the BookingStore. +/// +public enum BookingAction: Action { + + /// Synchronizes the Bookings matching the specified criteria. + /// + /// - Parameter onCompletion: called when sync completes, returns an error or a boolean that indicates whether there might be more bookings to sync. + /// + case synchronizeBookings(siteID: Int64, + pageNumber: Int, + pageSize: Int = BookingsRemote.Default.pageSize, + onCompletion: (Result) -> Void) +} diff --git a/Modules/Sources/Yosemite/Stores/BookingStore.swift b/Modules/Sources/Yosemite/Stores/BookingStore.swift new file mode 100644 index 00000000000..b091c9fb7a6 --- /dev/null +++ b/Modules/Sources/Yosemite/Stores/BookingStore.swift @@ -0,0 +1,142 @@ +import Foundation +import Networking +import Storage + +// MARK: - BookingStore +// +public class BookingStore: Store { + private let remote: BookingsRemoteProtocol + + public override convenience init(dispatcher: Dispatcher, storageManager: StorageManagerType, network: Network) { + let remote = BookingsRemote(network: network) + self.init(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote) + } + + public init(dispatcher: Dispatcher, + storageManager: StorageManagerType, + network: Network, + remote: BookingsRemoteProtocol) { + self.remote = remote + super.init(dispatcher: dispatcher, storageManager: storageManager, network: network) + } + + /// Registers for supported Actions. + /// + override public func registerSupportedActions(in dispatcher: Dispatcher) { + dispatcher.register(processor: self, for: BookingAction.self) + } + + /// Receives and executes Actions. + /// + override public func onAction(_ action: Action) { + guard let action = action as? BookingAction else { + assertionFailure("BookingStore received an unsupported action") + return + } + + switch action { + case let .synchronizeBookings(siteID, pageNumber, pageSize, onCompletion): + synchronizeBookings(siteID: siteID, pageNumber: pageNumber, pageSize: pageSize, onCompletion: onCompletion) + } + } +} + + +// MARK: - Services +// +private extension BookingStore { + + /// Synchronizes the bookings for the specified site. + /// + func synchronizeBookings(siteID: Int64, + pageNumber: Int, + pageSize: Int, + onCompletion: @escaping (Result) -> Void) { + Task { @MainActor in + do { + let bookings = try await remote.loadAllBookings(for: siteID, + pageNumber: pageNumber, + pageSize: pageSize) + await upsertStoredBookingsInBackground(readOnlyBookings: bookings, siteID: siteID) + let hasNextPage = bookings.count == pageSize + onCompletion(.success(hasNextPage)) + } catch { + onCompletion(.failure(error)) + } + } + } +} + + +// MARK: - Storage: Booking +// +extension BookingStore { + + /// Updates (OR Inserts) the specified ReadOnly Booking Entities *in a background thread* async. + /// Also deletes existing bookings if requested. + func upsertStoredBookingsInBackground(readOnlyBookings: [Networking.Booking], + siteID: Int64, + shouldDeleteExistingBookings: Bool = false) async { + await withCheckedContinuation { [weak self] continuation in + guard let self else { + return continuation.resume() + } + upsertStoredBookingsInBackground(readOnlyBookings: readOnlyBookings, + siteID: siteID, + shouldDeleteExistingBookings: shouldDeleteExistingBookings) { + continuation.resume() + } + } + } + + /// Updates (OR Inserts) the specified ReadOnly Booking Entities *in a background thread*. + /// Also deletes existing bookings if requested. + /// `onCompletion` will be called on the main thread! + /// + func upsertStoredBookingsInBackground(readOnlyBookings: [Networking.Booking], + siteID: Int64, + shouldDeleteExistingBookings: Bool = false, + onCompletion: @escaping () -> Void) { + storageManager.performAndSave({ [weak self] storage in + guard let self else { + return onCompletion() + } + if shouldDeleteExistingBookings { + storage.deleteBookings(siteID: siteID) + } + upsertStoredBookings(readOnlyBookings: readOnlyBookings, in: storage) + }, completion: onCompletion, on: .main) + } + + /// Updates (OR Inserts) the specified ReadOnly Booking Entities into the Storage Layer. + /// + /// - Parameters: + /// - readOnlyBookings: Remote Bookings to be persisted. + /// - storage: Where we should save all the things! + /// + func upsertStoredBookings(readOnlyBookings: [Networking.Booking], in storage: StorageType) { + // Fetch all existing bookings for the site at once + let bookingIDs = readOnlyBookings.map { $0.bookingID } + let siteID = readOnlyBookings.first?.siteID ?? 0 + let storedBookings = storage.loadBookings(siteID: siteID, bookingIDs: bookingIDs) + + for readOnlyBooking in readOnlyBookings { + // Filter to find existing booking by booking ID + let storageBooking = storedBookings.first { $0.bookingID == readOnlyBooking.bookingID } ?? + storage.insertNewObject(ofType: Storage.Booking.self) + + storageBooking.update(with: readOnlyBooking) + } + } +} + +// MARK: - Unit Testing Helpers +// +extension BookingStore { + + /// Unit Testing Helper: Updates or Inserts the specified ReadOnly Booking in a given Storage Layer. + /// + func upsertStoredBooking(readOnlyBooking: Networking.Booking, in storage: StorageType) { + upsertStoredBookings(readOnlyBookings: [readOnlyBooking], in: storage) + } +} From 46566eb91aed457977ad3d96b3c907fd25a5608a Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 24 Sep 2025 16:42:55 +0700 Subject: [PATCH 2/5] Add tests --- .../Mocks/MockBookingsRemote.swift | 19 ++ .../Stores/BookingStoreTests.swift | 218 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift create mode 100644 Modules/Tests/YosemiteTests/Stores/BookingStoreTests.swift diff --git a/Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift b/Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift new file mode 100644 index 00000000000..7b6b4213b82 --- /dev/null +++ b/Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift @@ -0,0 +1,19 @@ +import Foundation +@testable import Networking + +/// Mock for BookingsRemoteProtocol +/// +final class MockBookingsRemote: BookingsRemoteProtocol { + private var loadAllBookingsResult: Result<[Booking], Error>? + + func whenLoadingAllBookings(thenReturn result: Result<[Booking], Error>) { + loadAllBookingsResult = result + } + + func loadAllBookings(for siteID: Int64, pageNumber: Int, pageSize: Int) async throws -> [Booking] { + guard let result = loadAllBookingsResult else { + throw NetworkError.timeout() + } + return try result.get() + } +} \ No newline at end of file diff --git a/Modules/Tests/YosemiteTests/Stores/BookingStoreTests.swift b/Modules/Tests/YosemiteTests/Stores/BookingStoreTests.swift new file mode 100644 index 00000000000..cab379328e3 --- /dev/null +++ b/Modules/Tests/YosemiteTests/Stores/BookingStoreTests.swift @@ -0,0 +1,218 @@ +import Testing +@testable import Networking +@testable import Storage +@testable import Yosemite + +@MainActor +struct BookingStoreTests { + /// Mock network to inject responses + /// + private var network: MockNetwork + + /// Spy remote to check request parameter use + /// + private var remote: MockBookingsRemote + + /// Mock Storage: InMemory + /// + private var storageManager: MockStorageManager + + /// Storage + /// + private var storage: StorageType { + storageManager.viewStorage + } + + /// Convenience: returns the StorageType associated with the main thread + /// + private var viewStorage: StorageType { + return storageManager.viewStorage + } + + /// Convenience: returns the number of stored bookings + /// + private var storedBookingCount: Int { + return viewStorage.countObjects(ofType: StorageBooking.self) + } + + /// SiteID + /// + private let sampleSiteID: Int64 = 120934 + + /// Default page number + /// + private let defaultPageNumber = 1 + + /// Default page size + /// + private let defaultPageSize = 25 + + init() { + network = MockNetwork() + storageManager = MockStorageManager() + remote = MockBookingsRemote() + } + + // MARK: - synchronizeBookings + + @Test func synchronizeBookings_returns_false_for_hasNextPage_when_number_of_retrieved_results_is_zero() async throws { + // Given + remote.whenLoadingAllBookings(thenReturn: .success([])) + let store = BookingStore(dispatcher: Dispatcher(), + storageManager: storageManager, + network: network, + remote: remote) + + // When + let result = await withCheckedContinuation { continuation in + store.onAction(BookingAction.synchronizeBookings(siteID: sampleSiteID, + pageNumber: defaultPageNumber, + pageSize: defaultPageSize, + onCompletion: { result in + continuation.resume(returning: result) + })) + } + + // Then + let hasNextPage = try result.get() + #expect(hasNextPage == false) + } + + @Test func synchronizeBookings_returns_true_for_hasNextPage_when_number_of_retrieved_results_equals_pageSize() async throws { + // Given + let bookings = Array(repeating: Booking.fake(), count: defaultPageSize) + remote.whenLoadingAllBookings(thenReturn: .success(bookings)) + let store = BookingStore(dispatcher: Dispatcher(), + storageManager: storageManager, + network: network, + remote: remote) + + // When + let result = await withCheckedContinuation { continuation in + store.onAction(BookingAction.synchronizeBookings(siteID: sampleSiteID, + pageNumber: defaultPageNumber, + pageSize: defaultPageSize, + onCompletion: { result in + continuation.resume(returning: result) + })) + } + + // Then + let hasNextPage = try result.get() + #expect(hasNextPage == true) + } + + @Test func synchronizeBookings_returns_error_on_failure() async throws { + // Given + remote.whenLoadingAllBookings(thenReturn: .failure(NetworkError.timeout())) + let store = BookingStore(dispatcher: Dispatcher(), + storageManager: storageManager, + network: network, + remote: remote) + + // When + let result = await withCheckedContinuation { continuation in + store.onAction(BookingAction.synchronizeBookings(siteID: sampleSiteID, + pageNumber: defaultPageNumber, + pageSize: defaultPageSize, + onCompletion: { result in + continuation.resume(returning: result) + })) + } + + // Then + #expect(result.isFailure) + let error = result.failure as? NetworkError + #expect(error == .timeout()) + } + + @Test func synchronizeBookings_stores_bookings_upon_success() async throws { + // Given + let booking = Booking.fake().copy(siteID: sampleSiteID, bookingID: 123) + remote.whenLoadingAllBookings(thenReturn: .success([booking])) + let store = BookingStore(dispatcher: Dispatcher(), + storageManager: storageManager, + network: network, + remote: remote) + #expect(storedBookingCount == 0) + + // When + let result = await withCheckedContinuation { continuation in + store.onAction(BookingAction.synchronizeBookings(siteID: sampleSiteID, + pageNumber: defaultPageNumber, + pageSize: defaultPageSize, + onCompletion: { result in + continuation.resume(returning: result) + })) + } + + // Then + #expect(result.isSuccess) + #expect(storedBookingCount == 1) + } + + @Test func synchronizeBookings_updates_existing_booking_when_booking_already_exists() async throws { + // Given + let originalBooking = Booking.fake().copy(siteID: sampleSiteID, bookingID: 123, statusKey: "pending") + storeBooking(originalBooking) + #expect(storedBookingCount == 1) + + let updatedBooking = originalBooking.copy(statusKey: "confirmed") + remote.whenLoadingAllBookings(thenReturn: .success([updatedBooking])) + let store = BookingStore(dispatcher: Dispatcher(), + storageManager: storageManager, + network: network, + remote: remote) + + // When + let result = await withCheckedContinuation { continuation in + store.onAction(BookingAction.synchronizeBookings(siteID: sampleSiteID, + pageNumber: defaultPageNumber, + pageSize: defaultPageSize, + onCompletion: { result in + continuation.resume(returning: result) + })) + } + + // Then + #expect(result.isSuccess) + #expect(storedBookingCount == 1) + let storedBooking = try #require(viewStorage.loadBooking(siteID: sampleSiteID, bookingID: 123)) + #expect(storedBooking.statusKey == "confirmed") + } + + @Test func synchronizeBookings_stores_multiple_bookings_upon_success() async throws { + // Given + let booking1 = Booking.fake().copy(siteID: sampleSiteID, bookingID: 123) + let booking2 = Booking.fake().copy(siteID: sampleSiteID, bookingID: 456) + remote.whenLoadingAllBookings(thenReturn: .success([booking1, booking2])) + let store = BookingStore(dispatcher: Dispatcher(), + storageManager: storageManager, + network: network, + remote: remote) + #expect(storedBookingCount == 0) + + // When + let result = await withCheckedContinuation { continuation in + store.onAction(BookingAction.synchronizeBookings(siteID: sampleSiteID, + pageNumber: defaultPageNumber, + pageSize: defaultPageSize, + onCompletion: { result in + continuation.resume(returning: result) + })) + } + + // Then + #expect(result.isSuccess) + #expect(storedBookingCount == 2) + } +} + +private extension BookingStoreTests { + @discardableResult + func storeBooking(_ booking: Networking.Booking) -> Storage.Booking { + let storedBooking = storage.insertNewObject(ofType: Storage.Booking.self) + storedBooking.update(with: booking) + return storedBooking + } +} From 9b4df552c97cc1ca87bf1537aa1098e59645e69f Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 24 Sep 2025 16:53:55 +0700 Subject: [PATCH 3/5] Remove periphery ignore comments --- Modules/Sources/Networking/Model/Bookings/Booking.swift | 1 - Modules/Sources/Yosemite/Model/Model.swift | 1 - Modules/Sources/Yosemite/Stores/BookingStore.swift | 6 +++--- Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Modules/Sources/Networking/Model/Bookings/Booking.swift b/Modules/Sources/Networking/Model/Bookings/Booking.swift index 38ad4a68daf..2a651205cbb 100644 --- a/Modules/Sources/Networking/Model/Bookings/Booking.swift +++ b/Modules/Sources/Networking/Model/Bookings/Booking.swift @@ -1,4 +1,3 @@ -// periphery:ignore:all import Codegen import Foundation diff --git a/Modules/Sources/Yosemite/Model/Model.swift b/Modules/Sources/Yosemite/Model/Model.swift index f87a23a533d..e7be38a3663 100644 --- a/Modules/Sources/Yosemite/Model/Model.swift +++ b/Modules/Sources/Yosemite/Model/Model.swift @@ -266,7 +266,6 @@ public typealias StorageBlazeCampaignListItem = Storage.BlazeCampaignListItem public typealias StorageBlazeTargetDevice = Storage.BlazeTargetDevice public typealias StorageBlazeTargetLanguage = Storage.BlazeTargetLanguage public typealias StorageBlazeTargetTopic = Storage.BlazeTargetTopic -// periphery:ignore - will be used later public typealias StorageBooking = Storage.Booking public typealias StorageCardReaderType = Storage.CardReaderType public typealias StorageCoupon = Storage.Coupon diff --git a/Modules/Sources/Yosemite/Stores/BookingStore.swift b/Modules/Sources/Yosemite/Stores/BookingStore.swift index b091c9fb7a6..04fcd8d425f 100644 --- a/Modules/Sources/Yosemite/Stores/BookingStore.swift +++ b/Modules/Sources/Yosemite/Stores/BookingStore.swift @@ -74,7 +74,7 @@ extension BookingStore { /// Updates (OR Inserts) the specified ReadOnly Booking Entities *in a background thread* async. /// Also deletes existing bookings if requested. - func upsertStoredBookingsInBackground(readOnlyBookings: [Networking.Booking], + func upsertStoredBookingsInBackground(readOnlyBookings: [Yosemite.Booking], siteID: Int64, shouldDeleteExistingBookings: Bool = false) async { await withCheckedContinuation { [weak self] continuation in @@ -93,7 +93,7 @@ extension BookingStore { /// Also deletes existing bookings if requested. /// `onCompletion` will be called on the main thread! /// - func upsertStoredBookingsInBackground(readOnlyBookings: [Networking.Booking], + func upsertStoredBookingsInBackground(readOnlyBookings: [Yosemite.Booking], siteID: Int64, shouldDeleteExistingBookings: Bool = false, onCompletion: @escaping () -> Void) { @@ -123,7 +123,7 @@ extension BookingStore { for readOnlyBooking in readOnlyBookings { // Filter to find existing booking by booking ID let storageBooking = storedBookings.first { $0.bookingID == readOnlyBooking.bookingID } ?? - storage.insertNewObject(ofType: Storage.Booking.self) + storage.insertNewObject(ofType: StorageBooking.self) storageBooking.update(with: readOnlyBooking) } diff --git a/Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift b/Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift index 7b6b4213b82..57065c586c6 100644 --- a/Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift +++ b/Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift @@ -16,4 +16,4 @@ final class MockBookingsRemote: BookingsRemoteProtocol { } return try result.get() } -} \ No newline at end of file +} From f650988ddc1656075074e2b2b563829f889d7d45 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 24 Sep 2025 17:33:55 +0700 Subject: [PATCH 4/5] Fix periphery issues --- Modules/Sources/Networking/Model/Bookings/Booking.swift | 5 ++--- Modules/Sources/Storage/Tools/StorageType+Extensions.swift | 2 +- Modules/Sources/Yosemite/Actions/BookingAction.swift | 1 + Modules/Sources/Yosemite/Model/Model.swift | 1 + WooCommerce/Classes/Yosemite/AuthenticatedState.swift | 3 ++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Modules/Sources/Networking/Model/Bookings/Booking.swift b/Modules/Sources/Networking/Model/Bookings/Booking.swift index 2a651205cbb..c05ab7beb05 100644 --- a/Modules/Sources/Networking/Model/Bookings/Booking.swift +++ b/Modules/Sources/Networking/Model/Bookings/Booking.swift @@ -22,8 +22,7 @@ public struct Booking: Codable, GeneratedCopiable, Equatable, GeneratedFakeable public let statusKey: String public let localTimezone: String - /// Computed Properties - /// + // periphery: ignore - to be used later public var bookingStatus: BookingStatus { return BookingStatus(rawValue: statusKey) ?? .unknown } @@ -172,8 +171,8 @@ enum BookingDecodingError: Error { // MARK: - Supporting Types // +// periphery: ignore /// Represents a Booking Status. -/// public enum BookingStatus: String, CaseIterable { case complete case paid diff --git a/Modules/Sources/Storage/Tools/StorageType+Extensions.swift b/Modules/Sources/Storage/Tools/StorageType+Extensions.swift index e313a7f6978..ea9258e4e8b 100644 --- a/Modules/Sources/Storage/Tools/StorageType+Extensions.swift +++ b/Modules/Sources/Storage/Tools/StorageType+Extensions.swift @@ -951,8 +951,8 @@ public extension StorageType { return allObjects(ofType: Booking.self, matching: predicate, sortedBy: [descriptor]) } + // periphery: ignore /// Retrieves the Stored Booking. - /// func loadBooking(siteID: Int64, bookingID: Int64) -> Booking? { let predicate = \Booking.bookingID == bookingID && \Booking.siteID == siteID return firstObject(ofType: Booking.self, matching: predicate) diff --git a/Modules/Sources/Yosemite/Actions/BookingAction.swift b/Modules/Sources/Yosemite/Actions/BookingAction.swift index be7e8a1e8dd..90c908ff7d7 100644 --- a/Modules/Sources/Yosemite/Actions/BookingAction.swift +++ b/Modules/Sources/Yosemite/Actions/BookingAction.swift @@ -1,6 +1,7 @@ import Foundation import Networking +// periphery: ignore /// BookingAction: Defines all of the Actions supported by the BookingStore. /// public enum BookingAction: Action { diff --git a/Modules/Sources/Yosemite/Model/Model.swift b/Modules/Sources/Yosemite/Model/Model.swift index e7be38a3663..621d92ab926 100644 --- a/Modules/Sources/Yosemite/Model/Model.swift +++ b/Modules/Sources/Yosemite/Model/Model.swift @@ -266,6 +266,7 @@ public typealias StorageBlazeCampaignListItem = Storage.BlazeCampaignListItem public typealias StorageBlazeTargetDevice = Storage.BlazeTargetDevice public typealias StorageBlazeTargetLanguage = Storage.BlazeTargetLanguage public typealias StorageBlazeTargetTopic = Storage.BlazeTargetTopic +// periphery: ignore public typealias StorageBooking = Storage.Booking public typealias StorageCardReaderType = Storage.CardReaderType public typealias StorageCoupon = Storage.Coupon diff --git a/WooCommerce/Classes/Yosemite/AuthenticatedState.swift b/WooCommerce/Classes/Yosemite/AuthenticatedState.swift index 5177f8695a6..97e2f60286a 100644 --- a/WooCommerce/Classes/Yosemite/AuthenticatedState.swift +++ b/WooCommerce/Classes/Yosemite/AuthenticatedState.swift @@ -126,7 +126,8 @@ class AuthenticatedState: StoresManagerState { StoreOnboardingTasksStore(dispatcher: dispatcher, storageManager: storageManager, network: network), GoogleAdsStore(dispatcher: dispatcher, storageManager: storageManager, network: network), MetaDataStore(dispatcher: dispatcher, storageManager: storageManager, network: network), - WooShippingStore(dispatcher: dispatcher, storageManager: storageManager, network: network) + WooShippingStore(dispatcher: dispatcher, storageManager: storageManager, network: network), + BookingStore(dispatcher: dispatcher, storageManager: storageManager, network: network) ] From 8fb28ad2479217cf48910d122f3c668514aa9ad8 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 24 Sep 2025 17:50:04 +0700 Subject: [PATCH 5/5] Remove unused helper --- Modules/Sources/Yosemite/Stores/BookingStore.swift | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Modules/Sources/Yosemite/Stores/BookingStore.swift b/Modules/Sources/Yosemite/Stores/BookingStore.swift index 04fcd8d425f..b36aa97bae9 100644 --- a/Modules/Sources/Yosemite/Stores/BookingStore.swift +++ b/Modules/Sources/Yosemite/Stores/BookingStore.swift @@ -129,14 +129,3 @@ extension BookingStore { } } } - -// MARK: - Unit Testing Helpers -// -extension BookingStore { - - /// Unit Testing Helper: Updates or Inserts the specified ReadOnly Booking in a given Storage Layer. - /// - func upsertStoredBooking(readOnlyBooking: Networking.Booking, in storage: StorageType) { - upsertStoredBookings(readOnlyBookings: [readOnlyBooking], in: storage) - } -}