Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jotaemepereira committed Dec 17, 2024
1 parent 3dadbce commit 0499ff2
Show file tree
Hide file tree
Showing 7 changed files with 296 additions and 42 deletions.
18 changes: 18 additions & 0 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2882,6 +2882,12 @@
BB731F312CDBA6360023D2E4 /* FireWindowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB731F302CDBA6320023D2E4 /* FireWindowTests.swift */; };
BB7B5F982C4ED73800BA4AF8 /* BookmarksSearchAndSortMetrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB7B5F972C4ED73800BA4AF8 /* BookmarksSearchAndSortMetrics.swift */; };
BB7B5F992C4ED73800BA4AF8 /* BookmarksSearchAndSortMetrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB7B5F972C4ED73800BA4AF8 /* BookmarksSearchAndSortMetrics.swift */; };
BB9BA2202D10BC72009229F3 /* TabBarRemoteMessageViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9BA21F2D10BC6B009229F3 /* TabBarRemoteMessageViewModelTests.swift */; };
BB9BA2212D10BC72009229F3 /* TabBarRemoteMessageViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9BA21F2D10BC6B009229F3 /* TabBarRemoteMessageViewModelTests.swift */; };
BB9BA2262D10C08F009229F3 /* TabBarRemoteMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9BA2252D10C089009229F3 /* TabBarRemoteMessage.swift */; };
BB9BA2272D10C08F009229F3 /* TabBarRemoteMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9BA2252D10C089009229F3 /* TabBarRemoteMessage.swift */; };
BB9BA2292D10C0A5009229F3 /* TabBarActiveRemoteMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9BA2282D10C0A3009229F3 /* TabBarActiveRemoteMessage.swift */; };
BB9BA22A2D10C0A5009229F3 /* TabBarActiveRemoteMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9BA2282D10C0A3009229F3 /* TabBarActiveRemoteMessage.swift */; };
BB9BDD492D09BAA80069E9EF /* TabBarRemoteMessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9BDD482D09BA9D0069E9EF /* TabBarRemoteMessageViewModel.swift */; };
BB9BDD4A2D09BAA80069E9EF /* TabBarRemoteMessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB9BDD482D09BA9D0069E9EF /* TabBarRemoteMessageViewModel.swift */; };
BBB881882C4029BA001247C6 /* BookmarkListTreeControllerSearchDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB881872C4029BA001247C6 /* BookmarkListTreeControllerSearchDataSource.swift */; };
Expand Down Expand Up @@ -4859,6 +4865,9 @@
BB5F46A22C8751F6005F72DF /* BookmarkSortTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkSortTests.swift; sourceTree = "<group>"; };
BB731F302CDBA6320023D2E4 /* FireWindowTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FireWindowTests.swift; sourceTree = "<group>"; };
BB7B5F972C4ED73800BA4AF8 /* BookmarksSearchAndSortMetrics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksSearchAndSortMetrics.swift; sourceTree = "<group>"; };
BB9BA21F2D10BC6B009229F3 /* TabBarRemoteMessageViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarRemoteMessageViewModelTests.swift; sourceTree = "<group>"; };
BB9BA2252D10C089009229F3 /* TabBarRemoteMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarRemoteMessage.swift; sourceTree = "<group>"; };
BB9BA2282D10C0A3009229F3 /* TabBarActiveRemoteMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarActiveRemoteMessage.swift; sourceTree = "<group>"; };
BB9BDD482D09BA9D0069E9EF /* TabBarRemoteMessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarRemoteMessageViewModel.swift; sourceTree = "<group>"; };
BBB881872C4029BA001247C6 /* BookmarkListTreeControllerSearchDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkListTreeControllerSearchDataSource.swift; sourceTree = "<group>"; };
BBBB653F2C77BB9400E69AC6 /* BookmarkSearchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkSearchTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -8567,6 +8576,8 @@
AA9FF95724A1ECE20039E328 /* Model */ = {
isa = PBXGroup;
children = (
BB9BA2282D10C0A3009229F3 /* TabBarActiveRemoteMessage.swift */,
BB9BA2252D10C089009229F3 /* TabBarRemoteMessage.swift */,
AA9FF95C24A1FA1C0039E328 /* TabCollection.swift */,
);
path = Model;
Expand Down Expand Up @@ -8779,6 +8790,7 @@
AAC9C01A24CB592E00AD1325 /* ViewModel */ = {
isa = PBXGroup;
children = (
BB9BA21F2D10BC6B009229F3 /* TabBarRemoteMessageViewModelTests.swift */,
AAC9C01D24CB6BEB00AD1325 /* TabCollectionViewModelTests.swift */,
37D23788288009CF00BCE03B /* TabCollectionViewModelTests+PinnedTabs.swift */,
37479F142891BC8300302FE2 /* TabCollectionViewModelTests+WithoutPinnedTabsManager.swift */,
Expand Down Expand Up @@ -11329,6 +11341,7 @@
BB7B5F992C4ED73800BA4AF8 /* BookmarksSearchAndSortMetrics.swift in Sources */,
B60D644A2AAF1B7C00B26F50 /* AddressBarTextSelectionNavigation.swift in Sources */,
1D01A3D52B88CF7700FE8150 /* AccessibilityPreferences.swift in Sources */,
BB9BA2262D10C08F009229F3 /* TabBarRemoteMessage.swift in Sources */,
37219B342CBFBBE800C9D7A8 /* NewTabPageSearchBoxExperiment.swift in Sources */,
3706FA98293F65D500E42796 /* SecureVaultSorting.swift in Sources */,
1DEDB3652C19934C006B6D1B /* MoreOptionsMenuButton.swift in Sources */,
Expand Down Expand Up @@ -12157,6 +12170,7 @@
3706FC6F293F65D500E42796 /* FirePopoverViewModel.swift in Sources */,
3706FC71293F65D500E42796 /* NSColorExtension.swift in Sources */,
1DB9618229F67F6100CF5568 /* FaviconNullStore.swift in Sources */,
BB9BA22A2D10C0A5009229F3 /* TabBarActiveRemoteMessage.swift in Sources */,
3706FC73293F65D500E42796 /* AddressBarButtonsViewController.swift in Sources */,
9FDA6C222B79A59D00E099A9 /* BookmarkFavoriteView.swift in Sources */,
C1372EF52BBC5BAD003F8793 /* SecureTextField.swift in Sources */,
Expand Down Expand Up @@ -12358,6 +12372,7 @@
3706FE1C293F661700E42796 /* ConnectBitwardenViewModelTests.swift in Sources */,
4B9DB0552A983B55000927DB /* MockWaitlistStorage.swift in Sources */,
1D9FDEC72B9B64DB0040B78C /* PrivacyProtectionStatusTests.swift in Sources */,
BB9BA2202D10BC72009229F3 /* TabBarRemoteMessageViewModelTests.swift in Sources */,
C13909F52B85FD79001626ED /* AutofillDeleteAllPasswordsExecutorTests.swift in Sources */,
37D046A52C7DAA8900AEAA50 /* ImageProcessorMock.swift in Sources */,
857E44642A9F70F200ED77A7 /* CampaignVariantTests.swift in Sources */,
Expand Down Expand Up @@ -13009,6 +13024,7 @@
B693955326F04BEC0015B914 /* WindowDraggingView.swift in Sources */,
4B1E6EED27AB5E5100F51793 /* SecureVaultSorting.swift in Sources */,
37CD54CE27F2FDD100F1F7B9 /* PreferencesSidebarModel.swift in Sources */,
BB9BA2272D10C08F009229F3 /* TabBarRemoteMessage.swift in Sources */,
1D43EB32292788C70065E5D6 /* BWEncryptionOutput.m in Sources */,
3707EC4A2C47E36A00B67CBE /* CloseButton.swift in Sources */,
B6106BAD26A7BF390013B453 /* PermissionState.swift in Sources */,
Expand Down Expand Up @@ -13616,6 +13632,7 @@
AA2CB1352587C29500AA6FBE /* TabBarFooter.swift in Sources */,
EEC111E6294D06290086524F /* JSAlertViewModel.swift in Sources */,
4BE5336C286912D40019DBFD /* BookmarksBarCollectionViewItem.swift in Sources */,
BB9BA2292D10C0A5009229F3 /* TabBarActiveRemoteMessage.swift in Sources */,
B6C0B23926E742610031CB7F /* FileDownloadError.swift in Sources */,
85589EA027BFE60E0038AD11 /* MoreOrLessView.swift in Sources */,
B6CC26682BAD959500F53F8D /* DownloadProgress.swift in Sources */,
Expand Down Expand Up @@ -14102,6 +14119,7 @@
B63ED0DC26AE7B1E00A9DAD1 /* WebViewMock.swift in Sources */,
56A053FF2C1AEFA1007D8FAB /* OnboardingManagerTests.swift in Sources */,
4B4F72EC266B2ED300814C60 /* CollectionExtension.swift in Sources */,
BB9BA2212D10BC72009229F3 /* TabBarRemoteMessageViewModelTests.swift in Sources */,
C172E7332C93759C00521D9A /* SyncPromoManagerTests.swift in Sources */,
AAE39D1B24F44885008EF28B /* TabCollectionViewModelDelegateMock.swift in Sources */,
9F0A2CF82B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift in Sources */,
Expand Down
52 changes: 52 additions & 0 deletions DuckDuckGo/TabBar/Model/TabBarActiveRemoteMessage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// TabBarActiveRemoteMessage.swift
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Combine
import RemoteMessaging

protocol TabBarRemoteMessageProviding {
var remoteMessagePublisher: AnyPublisher<RemoteMessageModel?, Never> { get }

func markRemoteMessageAsShown() async
func onSurveyOpened() async
func onMessageDismissed() async
}

final class TabBarActiveRemoteMessage: TabBarRemoteMessageProviding {
private let activeRemoteMessageModel: ActiveRemoteMessageModel

var remoteMessagePublisher: AnyPublisher<RemoteMessageModel?, Never> {
activeRemoteMessageModel.$remoteMessage.eraseToAnyPublisher()
}

init(activeRemoteMessageModel: ActiveRemoteMessageModel) {
self.activeRemoteMessageModel = activeRemoteMessageModel
}

func markRemoteMessageAsShown() async {
await activeRemoteMessageModel.markRemoteMessageAsShown()
}

func onSurveyOpened() async {
await activeRemoteMessageModel.dismissRemoteMessage(with: .primaryAction)
}

func onMessageDismissed() async {
await activeRemoteMessageModel.dismissRemoteMessage(with: .close)
}
}
26 changes: 26 additions & 0 deletions DuckDuckGo/TabBar/Model/TabBarRemoteMessage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// TabBarRemoteMessage.swift
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

struct TabBarRemoteMessage {
static let tabBarPermanentSurveyRemoteMessageId = "macos_permanent_survey_tab_bar"

let buttonTitle: String
let popupTitle: String
let popupSubtitle: String
let surveyURL: URL
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct TabBarRemoteMessageView: View {
let onTap: (URL) -> Void
let onHover: () -> Void
let onHoverEnd: () -> Void
let onAppear: () -> Void

var body: some View {
HStack {
Expand All @@ -42,6 +43,7 @@ struct TabBarRemoteMessageView: View {
onHoverEnd()
})
)
.onAppear(perform: { onAppear() })
.frame(width: 147)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,20 @@
import Combine
import RemoteMessaging

struct TabBarRemoteMessage {
static let tabBarPermanentSurveyRemoteMessageId = "macos_permanent_survey_tab_bar"

let buttonTitle: String
let popupTitle: String
let popupSubtitle: String
let surveyURL: URL
}

final class TabBarRemoteMessageViewModel: ObservableObject {

private let activeRemoteMessageModel: ActiveRemoteMessageModel
private let tabBarRemoteActiveMessage: TabBarRemoteMessageProviding
private var cancellable: AnyCancellable?

@Published var remoteMessage: TabBarRemoteMessage?

init(activeRemoteMessageModel: ActiveRemoteMessageModel) {
self.activeRemoteMessageModel = activeRemoteMessageModel
init(activeRemoteMessageModel: TabBarRemoteMessageProviding, isFireWindow: Bool) {
self.tabBarRemoteActiveMessage = activeRemoteMessageModel

cancellable = activeRemoteMessageModel.$remoteMessage
cancellable = tabBarRemoteActiveMessage.remoteMessagePublisher
.sink(receiveValue: { model in
guard !isFireWindow else { return }

guard let model = model else {
self.remoteMessage = nil
return
Expand All @@ -51,18 +44,16 @@ final class TabBarRemoteMessageViewModel: ObservableObject {
})
}

func onDismiss() {
Task { await activeRemoteMessageModel.dismissRemoteMessage(with: .close) }
func onSurveyOpened() {
Task { await tabBarRemoteActiveMessage.onSurveyOpened() }
}

/// When the user hovers the Tab Bar Remote Message and we show the popup, there is where when we mark
/// that the user really saw the message.
func onUserHovered() {
Task { await activeRemoteMessageModel.markRemoteMessageAsShown() }
func onMessageDismissed() {
Task { await tabBarRemoteActiveMessage.onMessageDismissed() }
}

func onOpenSurvey() {
Task { await activeRemoteMessageModel.dismissRemoteMessage(with: .primaryAction) }
func markTabBarRemoteMessageAsShown() {
Task { await tabBarRemoteActiveMessage.markRemoteMessageAsShown() }
}
}

Expand Down
48 changes: 27 additions & 21 deletions DuckDuckGo/TabBar/View/TabBarViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ final class TabBarViewController: NSViewController {

init?(coder: NSCoder, tabCollectionViewModel: TabCollectionViewModel, activeRemoteMessageModel: ActiveRemoteMessageModel) {
self.tabCollectionViewModel = tabCollectionViewModel
self.tabBarRemoteMessageViewModel = TabBarRemoteMessageViewModel(activeRemoteMessageModel: activeRemoteMessageModel)
let tabBarActiveRemoteMessageModel = TabBarActiveRemoteMessage(activeRemoteMessageModel: activeRemoteMessageModel)
self.tabBarRemoteMessageViewModel = TabBarRemoteMessageViewModel(activeRemoteMessageModel: tabBarActiveRemoteMessageModel,
isFireWindow: tabCollectionViewModel.isBurner)
if !tabCollectionViewModel.isBurner, let pinnedTabCollection = tabCollectionViewModel.pinnedTabsManager?.tabCollection {
let pinnedTabsViewModel = PinnedTabsViewModel(collection: pinnedTabCollection)
let pinnedTabsView = PinnedTabsView(model: pinnedTabsViewModel)
Expand Down Expand Up @@ -226,20 +228,22 @@ final class TabBarViewController: NSViewController {
let feedbackButtonView = TabBarRemoteMessageView(
model: tabBarRemotMessage,
onClose: {
self.tabBarRemoteMessageViewModel.onDismiss()
self.tabBarRemoteMessageViewModel.onMessageDismissed()
self.removeFeedbackButton()
},
onTap: { surveyURL in
WindowControllersManager.shared.showTab(with: .contentFromURL(surveyURL, source: .appOpenUrl))
self.tabBarRemoteMessageViewModel.onOpenSurvey()
self.tabBarRemoteMessageViewModel.onSurveyOpened()
self.removeFeedbackButton()
},
onHover: {
self.startTabBarRemotMessageTimer(message: tabBarRemotMessage)
self.tabBarRemoteMessageViewModel.onUserHovered()
},
onHoverEnd: {
self.dismissTabBarRemoteMessagePopover()
},
onAppear: {
self.tabBarRemoteMessageViewModel.markTabBarRemoteMessageAsShown()
}
)
feedbackBarButtonHostingController = NSHostingController(rootView: feedbackButtonView)
Expand All @@ -258,7 +262,7 @@ final class TabBarViewController: NSViewController {

private func startTabBarRemotMessageTimer(message: TabBarRemoteMessage) {
tabBarRemoteMessagePopoverHoverTimer?.invalidate()
tabBarRemoteMessagePopoverHoverTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { _ in
tabBarRemoteMessagePopoverHoverTimer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: false) { _ in
self.showTabBarRemotePopup(message)
}
}
Expand All @@ -269,31 +273,33 @@ final class TabBarViewController: NSViewController {
}

private func showTabBarRemotePopup(_ message: TabBarRemoteMessage) {
if let popover = tabBarRemoteMessagePopover {
guard let tabBarButtonRemoteMessageView = feedbackBarButtonHostingController?.view else {
return
}
guard let tabBarButtonRemoteMessageView = feedbackBarButtonHostingController?.view else {
return
}

if let popover = tabBarRemoteMessagePopover {
popover.show(positionedBelow: tabBarButtonRemoteMessageView.bounds, in: tabBarButtonRemoteMessageView)
} else {
tabBarRemoteMessagePopover = NSPopover()
tabBarRemoteMessagePopover?.animates = true
tabBarRemoteMessagePopover?.behavior = .semitransient
tabBarRemoteMessagePopover?.contentSize = NSSize(width: TabBarRemoteMessagePopoverContent.Constants.width,
height: TabBarRemoteMessagePopoverContent.Constants.height)

let controller = NSViewController()
controller.view = NSHostingView(rootView: TabBarRemoteMessagePopoverContent(model: message))
tabBarRemoteMessagePopover?.contentViewController = controller

guard let tabBarButtonRemoteMessageView = feedbackBarButtonHostingController?.view else {
return
}
configurePopover(with: message)

tabBarRemoteMessagePopover?.show(positionedBelow: tabBarButtonRemoteMessageView.bounds, in: tabBarButtonRemoteMessageView)
}
}

private func configurePopover(with message: TabBarRemoteMessage) {
guard let popover = tabBarRemoteMessagePopover else { return }

popover.animates = true
popover.behavior = .semitransient
popover.contentSize = NSSize(width: TabBarRemoteMessagePopoverContent.Constants.width,
height: TabBarRemoteMessagePopoverContent.Constants.height)

let controller = NSViewController()
controller.view = NSHostingView(rootView: TabBarRemoteMessagePopoverContent(model: message))
popover.contentViewController = controller
}

private func removeFeedbackButton() {
guard let hostingController = feedbackBarButtonHostingController else { return }

Expand Down
Loading

0 comments on commit 0499ff2

Please sign in to comment.