diff --git a/Networking/NetworkingTests/Mapper/WCAnalyticsCustomerMapperTests.swift b/Networking/NetworkingTests/Mapper/WCAnalyticsCustomerMapperTests.swift index dc5247597d6..057f949da45 100644 --- a/Networking/NetworkingTests/Mapper/WCAnalyticsCustomerMapperTests.swift +++ b/Networking/NetworkingTests/Mapper/WCAnalyticsCustomerMapperTests.swift @@ -35,7 +35,7 @@ class WCAnalyticsCustomerMapperTests: XCTestCase { customers = try! mapper.map(response: data) // Then - XCTAssertEqual(customers.count, 3) + XCTAssertEqual(customers.count, 4) } func test_WCAnalyticsCustomer_array_response_values_are_correctly_parsed() { @@ -50,11 +50,13 @@ class WCAnalyticsCustomerMapperTests: XCTestCase { let customers = try! mapper.map(response: data) // Then - XCTAssertEqual(customers[0].userID, 1) - XCTAssertEqual(customers[0].name, "John") - XCTAssertEqual(customers[1].userID, 2) - XCTAssertEqual(customers[1].name, "Paul") - XCTAssertEqual(customers[2].userID, 3) - XCTAssertEqual(customers[2].name, "John Doe") + XCTAssertEqual(customers[0].userID, 0) + XCTAssertEqual(customers[0].name, "Matt The Unregistered") + XCTAssertEqual(customers[1].userID, 1) + XCTAssertEqual(customers[1].name, "John") + XCTAssertEqual(customers[2].userID, 2) + XCTAssertEqual(customers[2].name, "Paul") + XCTAssertEqual(customers[3].userID, 3) + XCTAssertEqual(customers[3].name, "John Doe") } } diff --git a/Networking/NetworkingTests/Remote/WCAnalyticsCustomerRemoteTests.swift b/Networking/NetworkingTests/Remote/WCAnalyticsCustomerRemoteTests.swift index b8a400a1042..0d7ee9c1401 100644 --- a/Networking/NetworkingTests/Remote/WCAnalyticsCustomerRemoteTests.swift +++ b/Networking/NetworkingTests/Remote/WCAnalyticsCustomerRemoteTests.swift @@ -45,13 +45,15 @@ class WCAnalyticsCustomerRemoteTests: XCTestCase { let customers = try XCTUnwrap(result.get()) let hasSearchParameter = network.queryParameters?.contains(where: { $0 == "search=John" }) ?? false XCTAssertTrue(hasSearchParameter) - assertEqual(3, customers.count) - assertEqual(1, customers[0].userID) - assertEqual(2, customers[1].userID) - assertEqual(3, customers[2].userID) - assertEqual("John", customers[0].name) - assertEqual("Paul", customers[1].name) - assertEqual("John Doe", customers[2].name) + assertEqual(4, customers.count) + assertEqual(0, customers[0].userID) + assertEqual(1, customers[1].userID) + assertEqual(2, customers[2].userID) + assertEqual(3, customers[3].userID) + assertEqual("Matt The Unregistered", customers[0].name) + assertEqual("John", customers[1].name) + assertEqual("Paul", customers[2].name) + assertEqual("John Doe", customers[3].name) } func test_WCAnalyticsCustomerRemote_when_calls_retrieveCustomersByName_fails_then_returns_result_isFailure() { diff --git a/Networking/NetworkingTests/Responses/wc-analytics-customers.json b/Networking/NetworkingTests/Responses/wc-analytics-customers.json index 3988a0f1aab..7c92958649b 100644 --- a/Networking/NetworkingTests/Responses/wc-analytics-customers.json +++ b/Networking/NetworkingTests/Responses/wc-analytics-customers.json @@ -1,5 +1,24 @@ { "data": [ + { + "id":0, + "user_id":0, + "username":"Matt.the.unregistered", + "name":"Matt The Unregistered", + "email":"matt.t.u@example.com", + "country":"US", + "city":"San Francisco", + "state":"CA", + "postcode":"94103", + "date_registered":null, + "date_last_active":"2022-07-12T08:36:54", + "date_last_order":"2022-07-12 08:36:54", + "orders_count":1, + "total_spend":10, + "avg_order_value":10, + "date_registered_gmt":null, + "date_last_active_gmt":"2022-07-12T08:36:54" + }, { "id":1, "user_id":1, diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CreateOrderAddressFormViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CreateOrderAddressFormViewModel.swift index 8257f3214fe..da51c1dd233 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CreateOrderAddressFormViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CreateOrderAddressFormViewModel.swift @@ -97,24 +97,6 @@ final class CreateOrderAddressFormViewModel: AddressFormViewModel, AddressFormVi override func trackOnLoad() { } func userDidCancelFlow() { } - - /// Dispatches the searchCustomers action when the Search button is tapped. - /// The hardcoded `keyword` is temporary until we implement the rest of the feature: - /// https://github.com/woocommerce/woocommerce-ios/issues/7741 - /// - func customerSearchTapped() { - let action = CustomerAction.searchCustomers( - siteID: siteID, - keyword: "hello") { result in - switch result { - case .success(_): - print("Success") - case .failure(let error): - print(error) - } - } - stores.dispatch(action) - } } private extension CreateOrderAddressFormViewModel { diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSearchUICommand.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSearchUICommand.swift index 9cbb069975e..eeed2279bd2 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSearchUICommand.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSearchUICommand.swift @@ -34,7 +34,17 @@ final class CustomerSearchUICommand: SearchUICommand { } func createStarterViewController() -> UIViewController? { - nil + createEmptyStateViewController() + } + + func configureEmptyStateViewControllerBeforeDisplay(viewController: EmptyStateViewController, searchKeyword: String) { + let boldSearchKeyword = NSAttributedString(string: searchKeyword, + attributes: [.font: EmptyStateViewController.Config.messageFont.bold]) + let format = Localization.emptySearchResults + let message = NSMutableAttributedString(string: format) + + message.replaceFirstOccurrence(of: "%@", with: boldSearchKeyword) + viewController.configure(.simple(message: message, image: .emptySearchResultsImage)) } func createCellViewModel(model: Customer) -> TitleAndSubtitleAndStatusTableViewCell.ViewModel { @@ -61,10 +71,6 @@ final class CustomerSearchUICommand: SearchUICommand { } func didSelectSearchResult(model: Customer, from viewController: UIViewController, reloadData: () -> Void, updateActionButton: () -> Void) { - // Not implemented yet - print("1 - Customer tapped") - print("2 - Customer ID: \(model.customerID) - Name: \(model.firstName ?? ""))") - // Customer data will go up to EditOrderAddressForm, via OrderCustomerListView completion handler onDidSelectSearchResult(model) } @@ -75,7 +81,11 @@ final class CustomerSearchUICommand: SearchUICommand { private extension CustomerSearchUICommand { enum Localization { - static let searchBarPlaceHolder = NSLocalizedString("Search all customers", - comment: "Customer Search Placeholder") + static let searchBarPlaceHolder = NSLocalizedString( + "Search all customers", + comment: "Customer Search Placeholder") + static let emptySearchResults = NSLocalizedString( + "We're sorry, we couldn't find results for “%@”", + comment: "Message for empty Customers search results. %@ is a placeholder for the text entered by the user.") } } diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/OrderCustomerListView.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/OrderCustomerListView.swift index 2dc0468d988..206373be6fa 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/OrderCustomerListView.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/OrderCustomerListView.swift @@ -3,7 +3,7 @@ import Yosemite import SwiftUI /// `SwiftUI` wrapper for `SearchViewController` using `CustomerSearchUICommand` -/// TODO: Make it generic +/// struct OrderCustomerListView: UIViewControllerRepresentable { let siteID: Int64 @@ -16,8 +16,6 @@ struct OrderCustomerListView: UIViewControllerRepresentable { storeID: siteID, command: CustomerSearchUICommand(siteID: siteID, onDidSelectSearchResult: onCustomerTapped), cellType: TitleAndSubtitleAndStatusTableViewCell.self, - // Must conform to SearchResultCell. - // TODO: Proper cell for this cellType. cellSeparator: .none ) let navigationController = WooNavigationController(rootViewController: viewController) @@ -25,6 +23,6 @@ struct OrderCustomerListView: UIViewControllerRepresentable { } func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { - // nope + // not implemented } } diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressFormViewModelProtocol.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressFormViewModelProtocol.swift index 120575655b1..aa27e5d518c 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressFormViewModelProtocol.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/AddressFormViewModelProtocol.swift @@ -104,9 +104,9 @@ protocol AddressFormViewModelProtocol: ObservableObject { /// func createSecondaryStateViewModel() -> StateSelectorViewModel - /// Callback method when the Customer Search button is tapped + /// Triggers the logic to fill Customer Order details when a Customer is selected /// - func customerSearchTapped() + func customerSelectedFromSearch(customer: Customer) } /// Type to hold values from all the form fields @@ -401,6 +401,40 @@ open class AddressFormViewModel: ObservableObject { let secondaryEmailIsValid = secondaryFields.email.isEmpty || EmailFormatValidator.validate(string: fields.email) return primaryEmailIsValid && secondaryEmailIsValid } + + /// Fills Order AddressFormFields with Customer details + /// + func customerSelectedFromSearch(customer: Customer) { + fillCustomerFields(customer: customer) + let addressesDiffer = customer.billing != customer.shipping + showDifferentAddressForm = addressesDiffer + } + + private func fillCustomerFields(customer: Customer) { + fields = populate(fields: fields, with: customer.billing) + secondaryFields = populate(fields: secondaryFields, with: customer.shipping) + } + + private func populate(fields: AddressFormFields, with address: Address?) -> AddressFormFields { + var fields = fields + + fields.firstName = address?.firstName ?? "" + fields.lastName = address?.lastName ?? "" + // Email is declared optional because we're using the same property from the Address model + // for both Shipping and Billing details: + // https://github.com/woocommerce/woocommerce-ios/issues/7993 + fields.email = address?.email ?? "" + fields.phone = address?.phone ?? "" + fields.company = address?.company ?? "" + fields.address1 = address?.address1 ?? "" + fields.address2 = address?.address2 ?? "" + fields.city = address?.city ?? "" + fields.postcode = address?.postcode ?? "" + fields.country = address?.country ?? "" + fields.state = address?.state ?? "" + + return fields + } } extension AddressFormViewModel { diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressForm.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressForm.swift index fcce4552a1c..51bf0069510 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressForm.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressForm.swift @@ -172,9 +172,8 @@ struct EditOrderAddressForm: View { .notice($viewModel.notice) .sheet(isPresented: $showingCustomerSearch, content: { OrderCustomerListView(siteID: viewModel.siteID, onCustomerTapped: { customer in - // Not implemented yet. - print("3 - Customer Callback. Fill Order data with Customer details") - print("4 - Customer ID: \(customer.customerID) - Name: \(customer.firstName ?? ""))") + viewModel.customerSelectedFromSearch(customer: customer) + showingCustomerSearch = false }) }) } diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressFormViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressFormViewModel.swift index 48475fec3ff..1644f52465d 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressFormViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Address Edit/EditOrderAddressFormViewModel.swift @@ -164,8 +164,6 @@ final class EditOrderAddressFormViewModel: AddressFormViewModel, AddressFormView func userDidCancelFlow() { analytics.track(event: WooAnalyticsEvent.OrderDetailsEdit.orderDetailEditFlowCanceled(subject: self.analyticsFlowType())) } - - func customerSearchTapped() {} } extension EditOrderAddressFormViewModel { diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index 7f4a31ac970..233ecbb7776 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -991,6 +991,7 @@ 57F2C6CD246DECC10074063B /* SummaryTableViewCellViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57F2C6CC246DECC10074063B /* SummaryTableViewCellViewModelTests.swift */; }; 57F42E40253768D600EA87F7 /* TitleAndEditableValueTableViewCellViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57F42E3F253768D600EA87F7 /* TitleAndEditableValueTableViewCellViewModelTests.swift */; }; 581D5052274AA2480089B6AD /* View+AutofocusTextModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581D5051274AA2480089B6AD /* View+AutofocusTextModifier.swift */; }; + 682210ED2909666600814E14 /* CustomerSearchUICommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682210EC2909666600814E14 /* CustomerSearchUICommandTests.swift */; }; 6827140F28A3988300E6E3F6 /* DismissableNoticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6827140E28A3988300E6E3F6 /* DismissableNoticeView.swift */; }; 6827141128A5410D00E6E3F6 /* NewSimplePaymentsLocationNoticeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6827141028A5410D00E6E3F6 /* NewSimplePaymentsLocationNoticeViewModel.swift */; }; 6827141528A671B900E6E3F6 /* NewSimplePaymentsLocationNoticeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6827141428A671B900E6E3F6 /* NewSimplePaymentsLocationNoticeViewController.swift */; }; @@ -2890,6 +2891,7 @@ 57F2C6CC246DECC10074063B /* SummaryTableViewCellViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SummaryTableViewCellViewModelTests.swift; sourceTree = ""; }; 57F42E3F253768D600EA87F7 /* TitleAndEditableValueTableViewCellViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleAndEditableValueTableViewCellViewModelTests.swift; sourceTree = ""; }; 581D5051274AA2480089B6AD /* View+AutofocusTextModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+AutofocusTextModifier.swift"; sourceTree = ""; }; + 682210EC2909666600814E14 /* CustomerSearchUICommandTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerSearchUICommandTests.swift; sourceTree = ""; }; 6827140E28A3988300E6E3F6 /* DismissableNoticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissableNoticeView.swift; sourceTree = ""; }; 6827141028A5410D00E6E3F6 /* NewSimplePaymentsLocationNoticeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewSimplePaymentsLocationNoticeViewModel.swift; sourceTree = ""; }; 6827141428A671B900E6E3F6 /* NewSimplePaymentsLocationNoticeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewSimplePaymentsLocationNoticeViewController.swift; sourceTree = ""; }; @@ -5990,6 +5992,7 @@ 573D0ACC2458665C004DE614 /* Search */ = { isa = PBXGroup; children = ( + 682210EB2909664800814E14 /* Customer */, 020C908224C84638001E2BEB /* Product */, ); path = Search; @@ -6165,6 +6168,14 @@ path = TitleAndEditableValueTableViewCell; sourceTree = ""; }; + 682210EB2909664800814E14 /* Customer */ = { + isa = PBXGroup; + children = ( + 682210EC2909666600814E14 /* CustomerSearchUICommandTests.swift */, + ); + path = Customer; + sourceTree = ""; + }; 6856D6E9B1C3C89938DCAD5C /* Testing */ = { isa = PBXGroup; children = ( @@ -10593,6 +10604,7 @@ 03FBDAFD263EE4E800ACE257 /* CouponListViewModelTests.swift in Sources */, 036F6EA6281847D5006D84F8 /* PaymentCaptureOrchestratorTests.swift in Sources */, B555531321B57E8800449E71 /* MockUserNotificationsCenterAdapter.swift in Sources */, + 682210ED2909666600814E14 /* CustomerSearchUICommandTests.swift in Sources */, 4590B652261C8D1E00A6FCE0 /* WeightFormatterTests.swift in Sources */, D8C11A6022E2479800D4A88D /* OrderPaymentDetailsViewModelTests.swift in Sources */, B622BC74289CF19400B10CEC /* WaitingTimeTrackerTests.swift in Sources */, diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Details/Addresses/EditOrderAddressFormViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Details/Addresses/EditOrderAddressFormViewModelTests.swift index 1e64378949f..3947050db71 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Details/Addresses/EditOrderAddressFormViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Details/Addresses/EditOrderAddressFormViewModelTests.swift @@ -716,6 +716,76 @@ final class EditOrderAddressFormViewModelTests: XCTestCase { // Then XCTAssertEqual(notice, AddressFormViewModel.NoticeFactory.createInvalidEmailNotice()) } + + func test_OrderAddressForm_billing_fields_are_updated_when_customerSelectedFromSearch() { + // Given + let viewModel = EditOrderAddressFormViewModel(order: Order.fake(), type: .billing) + let customer = Customer.fake().copy( + email: "scrambled@scrambled.com", + firstName: "Johnny", + lastName: "Appleseed", + billing: sampleAddressWithEmptyNullableFields(), + shipping: sampleAddressWithEmptyNullableFields() + ) + + // When + viewModel.customerSelectedFromSearch(customer: customer) + + // Then + XCTAssertEqual(viewModel.fields.email, customer.billing?.email) + XCTAssertEqual(viewModel.fields.firstName, customer.firstName) + XCTAssertEqual(viewModel.fields.lastName, customer.lastName) + XCTAssertEqual(viewModel.fields.company, customer.billing?.company) + XCTAssertEqual(viewModel.fields.address1, customer.billing?.address1) + XCTAssertEqual(viewModel.fields.address2, customer.billing?.address2) + XCTAssertEqual(viewModel.fields.city, customer.billing?.city) + XCTAssertEqual(viewModel.fields.state, customer.billing?.state) + XCTAssertEqual(viewModel.fields.postcode, customer.billing?.postcode) + XCTAssertEqual(viewModel.fields.country, customer.billing?.country) + XCTAssertEqual(viewModel.fields.phone, customer.billing?.phone) + } + + func test_OrderAddressForm_shipping_fields_are_updated_when_customerSelectedFromSearch() { + // Given + let viewModel = EditOrderAddressFormViewModel(order: Order.fake(), type: .shipping) + let customer = Customer.fake().copy( + email: "scrambled@scrambled.com", + firstName: "Johnny", + lastName: "Appleseed", + billing: sampleAddressWithEmptyNullableFields(), + shipping: sampleAddressWithEmptyNullableFields() + ) + + // When + viewModel.customerSelectedFromSearch(customer: customer) + + // Then + XCTAssertEqual(viewModel.fields.email, customer.shipping?.email) + XCTAssertEqual(viewModel.fields.firstName, customer.firstName) + XCTAssertEqual(viewModel.fields.lastName, customer.lastName) + XCTAssertEqual(viewModel.fields.company, customer.shipping?.company) + XCTAssertEqual(viewModel.fields.address1, customer.shipping?.address1) + XCTAssertEqual(viewModel.fields.address2, customer.shipping?.address2) + XCTAssertEqual(viewModel.fields.city, customer.shipping?.city) + XCTAssertEqual(viewModel.fields.state, customer.shipping?.state) + XCTAssertEqual(viewModel.fields.postcode, customer.shipping?.postcode) + XCTAssertEqual(viewModel.fields.country, customer.shipping?.country) + XCTAssertEqual(viewModel.fields.phone, customer.shipping?.phone) + } + + func test_OrderAddressForm_shows_different_address_form_fields_when_addresses_differ_and_customerSelectedFromSearch() { + // Given + let viewModel = EditOrderAddressFormViewModel(order: Order.fake(), type: .billing) + let billing = sampleAddressWithEmptyNullableFields() + let shipping = Address.fake().copy(address1: "123 different fake street") + let customer = Customer.fake().copy(billing: billing, shipping: shipping) + + // When + viewModel.customerSelectedFromSearch(customer: customer) + + // Then + XCTAssertTrue(viewModel.showDifferentAddressForm) + } } private extension EditOrderAddressFormViewModelTests { diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Search/Customer/CustomerSearchUICommandTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Search/Customer/CustomerSearchUICommandTests.swift new file mode 100644 index 00000000000..5281cc97c35 --- /dev/null +++ b/WooCommerce/WooCommerceTests/ViewRelated/Search/Customer/CustomerSearchUICommandTests.swift @@ -0,0 +1,38 @@ +import XCTest +@testable import WooCommerce +import Yosemite + +final class CustomerSearchUICommandTests: XCTestCase { + private let sampleSiteID: Int64 = 123 + + func test_searchResultsPredicate_includes_siteID_and_keyword_when_keyword() { + // Given + let command = CustomerSearchUICommand(siteID: sampleSiteID) { _ in } + + // When + let predicate = command.searchResultsPredicate(keyword: "some") + let expectedQuery = "siteID == 123 AND ANY searchResults.keyword == \"some\"" + + // Then + XCTAssertEqual(predicate?.predicateFormat, expectedQuery) + } + + func test_cellViewModel_display_correct_customer_details() { + let command = CustomerSearchUICommand(siteID: sampleSiteID) { _ in } + let customer = Customer( + siteID: sampleSiteID, + customerID: 1, + email: "john.w@email.com", + firstName: "John", + lastName: "W", + billing: nil, + shipping: nil + ) + + let cellViewModel = command.createCellViewModel(model: customer) + + XCTAssertEqual(cellViewModel.id, String(customer.customerID)) + XCTAssertEqual(cellViewModel.title, "\(customer.firstName ?? "") \(customer.lastName ?? "")") + XCTAssertEqual(cellViewModel.subtitle, String(customer.email)) + } +} diff --git a/Yosemite/Yosemite/Stores/CustomerStore.swift b/Yosemite/Yosemite/Stores/CustomerStore.swift index 1cd6bdd6be9..4e2a797dacf 100644 --- a/Yosemite/Yosemite/Stores/CustomerStore.swift +++ b/Yosemite/Yosemite/Stores/CustomerStore.swift @@ -119,6 +119,12 @@ public final class CustomerStore: Store { var customers = [Customer]() let group = DispatchGroup() for result in searchResults { + // At the moment, we're not searching through non-registered customers + // As we only search by customer ID, calls to /wc/v3/customers/0 will always fail + // https://github.com/woocommerce/woocommerce-ios/issues/7741 + if result.userID == 0 { + continue + } group.enter() self.retrieveCustomer(for: siteID, with: result.userID, onCompletion: { result in if let customer = try? result.get() { diff --git a/Yosemite/YosemiteTests/Stores/CustomerStoreTests.swift b/Yosemite/YosemiteTests/Stores/CustomerStoreTests.swift index 458020ef3a6..9f0aada3a15 100644 --- a/Yosemite/YosemiteTests/Stores/CustomerStoreTests.swift +++ b/Yosemite/YosemiteTests/Stores/CustomerStoreTests.swift @@ -184,4 +184,23 @@ final class CustomerStoreTests: XCTestCase { XCTAssertEqual(storedCustomer?.customerID, dummyCustomerID) XCTAssertEqual(storedCustomer?.firstName, "John") } + + func test_searchCustomers_returns_no_customers_when_customer_is_not_registered() throws { + // Given + network.simulateResponse(requestUrlSuffix: "customers", filename: "wc-analytics-customers") + + // When + () = waitFor { promise in + let action = CustomerAction.searchCustomers(siteID: self.dummySiteID, keyword: self.dummyKeyword) { result in + promise(()) + } + self.dispatcher.dispatch(action) + } + + // Then + let requests = network.requestsForResponseData.compactMap { $0 as? JetpackRequest } + XCTAssertFalse(requests.contains(where: { request in + request.path == "customers/0" + })) + } }