Skip to content

Commit

Permalink
Limit reliance on using timeouts in HubMenuViewModelTests
Browse files Browse the repository at this point in the history
Make viewDidAppear of HubMenuViewModel async which allows the tests to avoid timeouts and more importantly isInverted calls to assert that somehow is not called. It improves the speed of the tests dramatically.
  • Loading branch information
staskus committed Jan 9, 2025
1 parent 0e04ef9 commit 1567cfc
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 45 deletions.
53 changes: 39 additions & 14 deletions WooCommerce/Classes/ViewRelated/Hub Menu/HubMenuViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,22 @@ final class HubMenuViewModel: ObservableObject {
createCardPresentPaymentService()
}

func viewDidAppear() {
func viewDidAppear() async {
NotificationCenter.default.post(name: .hubMenuViewDidAppear, object: nil)
viewAppeared = true
if !hasGoogleAdsCampaigns {
refreshGoogleAdsCampaignCheck()
}

if !isSiteEligibleForBlaze {
refreshBlazeEligibilityCheck()
await withTaskGroup(of: Void.self) { group in
if !hasGoogleAdsCampaigns {
group.addTask {
await self.refreshGoogleAdsCampaignCheck()
}
}

if !isSiteEligibleForBlaze {
group.addTask {
await self.refreshBlazeEligibilityCheck()
}
}
}
}

Expand Down Expand Up @@ -207,19 +214,16 @@ final class HubMenuViewModel: ObservableObject {
navigateToDestination(.reviewDetails(parcel: parcel))
}

func refreshGoogleAdsCampaignCheck() {
Task { @MainActor in
hasGoogleAdsCampaigns = await checkIfSiteHasGoogleAdsCampaigns()
}
func refreshGoogleAdsCampaignCheck() async {
hasGoogleAdsCampaigns = await checkIfSiteHasGoogleAdsCampaigns()
}

func refreshBlazeEligibilityCheck() {
func refreshBlazeEligibilityCheck() async {
guard let site = currentSite else {
return
}
Task { @MainActor in
isSiteEligibleForBlaze = await blazeEligibilityChecker.isSiteEligible(site)
}

isSiteEligibleForBlaze = await blazeEligibilityChecker.isSiteEligible(site)
}

func updateDefaultConfigurationForPointOfSale(_ isPointOfSaleActive: Bool) {
Expand Down Expand Up @@ -477,6 +481,27 @@ private extension HubMenuViewModel {
}
}

// MARK: - Helpers
extension HubMenuViewModel {
func viewDidAppear() {
Task { @MainActor in
await viewDidAppear()
}
}

func refreshBlazeEligibilityCheck() {
Task { @MainActor in
await refreshBlazeEligibilityCheck()
}
}

func refreshGoogleAdsCampaignCheck() {
Task { @MainActor in
await refreshGoogleAdsCampaignCheck()
}
}
}

protocol HubMenuItem {
static var id: String { get }
var title: String { get }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ final class HubMenuViewModelTests: XCTestCase {
}

@MainActor
func test_viewDidAppear_triggers_blaze_eligibility_check_only_if_site_is_ineligible() {
func test_viewDidAppear_triggers_blaze_eligibility_check_only_if_site_is_ineligible() async {
// Given
let stores = MockStoresManager(sessionManager: .makeForTesting())
// Setting site ID is required before setting `Site`.
Expand All @@ -34,42 +34,33 @@ final class HubMenuViewModelTests: XCTestCase {
tapToPayBadgePromotionChecker: TapToPayBadgePromotionChecker(),
stores: stores,
blazeEligibilityChecker: blazeEligibilityChecker)
waitUntil {
await until {
// The first check is triggered by `updateMenuItemEligibility`
blazeEligibilityChecker.siteEligibilityCheckCount == 1
}

// When
viewModel.viewDidAppear()
await viewModel.viewDidAppear()

// Then
waitUntil {
blazeEligibilityChecker.siteEligibilityCheckCount == 2
}
XCTAssert(blazeEligibilityChecker.siteEligibilityCheckCount == 2)

// When
blazeEligibilityChecker.updateSiteEligibility(true)
viewModel.viewDidAppear()
await viewModel.viewDidAppear()

// Then
waitUntil {
blazeEligibilityChecker.siteEligibilityCheckCount == 3
}
XCTAssert(blazeEligibilityChecker.siteEligibilityCheckCount == 3)

// When
viewModel.viewDidAppear()
await viewModel.viewDidAppear()

// Then
waitForExpectation(timeout: 2) { expectation in
expectation.isInverted = true
if blazeEligibilityChecker.siteEligibilityCheckCount == 4 {
expectation.fulfill() // This should not happen
}
}
// Then value should remain the same
XCTAssert(blazeEligibilityChecker.siteEligibilityCheckCount == 3)
}

@MainActor
func test_createGoogleAdsCampaignCoordinator_sets_correct_value_for_shouldStartCampaignCreation() {
func test_createGoogleAdsCampaignCoordinator_sets_correct_value_for_shouldStartCampaignCreation() async {
// Given
let stores = MockStoresManager(sessionManager: .makeForTesting())
// Setting site ID is required before setting `Site`.
Expand All @@ -82,6 +73,10 @@ final class HubMenuViewModelTests: XCTestCase {
stores: stores,
googleAdsEligibilityChecker: checker)

await until {
checker.siteEligibilityCheckTriggered
}

// When
let navigationController = UINavigationController()
let coordinator = viewModel.createGoogleAdsCampaignCoordinator(with: navigationController)
Expand All @@ -92,12 +87,10 @@ final class HubMenuViewModelTests: XCTestCase {

// When
mockGoogleAdsCampaignFetch(with: .success([GoogleAdsCampaign.fake()]), for: stores)
viewModel.refreshGoogleAdsCampaignCheck()
await viewModel.refreshGoogleAdsCampaignCheck()

// Then
waitUntil {
viewModel.hasGoogleAdsCampaigns == true
}
XCTAssertTrue(viewModel.hasGoogleAdsCampaigns)
let updatedCoordinator = viewModel.createGoogleAdsCampaignCoordinator(with: navigationController)
XCTAssertFalse(updatedCoordinator.shouldStartCampaignCreation)
}
Expand Down Expand Up @@ -659,7 +652,7 @@ final class HubMenuViewModelTests: XCTestCase {
}

@MainActor
func test_hasGoogleAdsCampaigns_is_false_when_site_has_no_campaigns() {
func test_hasGoogleAdsCampaigns_is_false_when_site_has_no_campaigns() async {
// Given
let stores = MockStoresManager(sessionManager: .makeForTesting())
// Setting site ID is required before setting `Site`.
Expand All @@ -684,17 +677,18 @@ final class HubMenuViewModelTests: XCTestCase {
tapToPayBadgePromotionChecker: TapToPayBadgePromotionChecker(),
stores: stores,
googleAdsEligibilityChecker: eligibilityChecker)
viewModel.refreshGoogleAdsCampaignCheck()
waitUntil {
fetchAdsCampaignsTriggered
await until {
eligibilityChecker.siteEligibilityCheckTriggered
}
await viewModel.refreshGoogleAdsCampaignCheck()

// Then
XCTAssertTrue(fetchAdsCampaignsTriggered)
XCTAssertFalse(viewModel.hasGoogleAdsCampaigns)
}

@MainActor
func test_hasGoogleAdsCampaigns_is_true_when_site_has_campaigns() {
func test_hasGoogleAdsCampaigns_is_true_when_site_has_campaigns() async {
// Given
let stores = MockStoresManager(sessionManager: .makeForTesting())
// Setting site ID is required before setting `Site`.
Expand All @@ -720,12 +714,14 @@ final class HubMenuViewModelTests: XCTestCase {
tapToPayBadgePromotionChecker: TapToPayBadgePromotionChecker(),
stores: stores,
googleAdsEligibilityChecker: eligibilityChecker)
viewModel.refreshGoogleAdsCampaignCheck()
waitUntil {
fetchAdsCampaignsTriggered
await until {
eligibilityChecker.siteEligibilityCheckTriggered
}

await viewModel.refreshGoogleAdsCampaignCheck()

// Then
XCTAssertTrue(fetchAdsCampaignsTriggered)
XCTAssertTrue(viewModel.hasGoogleAdsCampaigns)
}

Expand Down

0 comments on commit 1567cfc

Please sign in to comment.