Skip to content

Commit

Permalink
Merge branch 'main' into dominik/xcode-16
Browse files Browse the repository at this point in the history
  • Loading branch information
jotaemepereira committed Nov 1, 2024
2 parents 5aa1c0f + 72c9e16 commit 02b5a06
Show file tree
Hide file tree
Showing 14 changed files with 104 additions and 79 deletions.
2 changes: 1 addition & 1 deletion Configuration/BuildNumber.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
CURRENT_PROJECT_VERSION = 293
CURRENT_PROJECT_VERSION = 295
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
{
"identity" : "lottie-spm",
"kind" : "remoteSourceControl",
"location" : "https://github.com/airbnb/lottie-spm.git",
"location" : "https://github.com/airbnb/lottie-spm",
"state" : {
"revision" : "1d29eccc24cc8b75bff9f6804155112c0ffc9605",
"version" : "4.4.3"
Expand Down
28 changes: 27 additions & 1 deletion DuckDuckGo/Application/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate {

public let subscriptionManager: SubscriptionManager
public let subscriptionUIHandler: SubscriptionUIHandling
public let subscriptionCookieManager: SubscriptionCookieManaging
private let subscriptionCookieManager: SubscriptionCookieManaging

Check failure on line 100 in DuckDuckGo/Application/AppDelegate.swift

View workflow job for this annotation

GitHub Actions / Build Notarized Review app / Export Notarized App

cannot find type 'SubscriptionCookieManaging' in scope

Check failure on line 100 in DuckDuckGo/Application/AppDelegate.swift

View workflow job for this annotation

GitHub Actions / Test (Non-Sandbox)

cannot find type 'SubscriptionCookieManaging' in scope

Check failure on line 100 in DuckDuckGo/Application/AppDelegate.swift

View workflow job for this annotation

GitHub Actions / Make Release Build

cannot find type 'SubscriptionCookieManaging' in scope

Check failure on line 100 in DuckDuckGo/Application/AppDelegate.swift

View workflow job for this annotation

GitHub Actions / Test (Sandbox)

cannot find type 'SubscriptionCookieManaging' in scope

Check failure on line 100 in DuckDuckGo/Application/AppDelegate.swift

View workflow job for this annotation

GitHub Actions / Test (Sandbox)

cannot find type 'SubscriptionCookieManaging' in scope
private var subscriptionCookieManagerFeatureFlagCancellable: AnyCancellable?

// MARK: - Freemium DBP
public let freemiumDBPFeature: FreemiumDBPFeature
Expand Down Expand Up @@ -325,6 +326,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
freemiumDBPFeature.subscribeToDependencyUpdates()
}

// swiftlint:disable:next cyclomatic_complexity
func applicationDidFinishLaunching(_ notification: Notification) {
guard NSApp.runType.requiresEnvironment else { return }
defer {
Expand Down Expand Up @@ -367,6 +369,30 @@ final class AppDelegate: NSObject, NSApplicationDelegate {

subscriptionManager.loadInitialData()

let privacyConfigurationManager = ContentBlocking.shared.privacyConfigurationManager

// Enable subscriptionCookieManager if feature flag is present
if privacyConfigurationManager.privacyConfig.isSubfeatureEnabled(PrivacyProSubfeature.setAccessTokenCookieForSubscriptionDomains) {
subscriptionCookieManager.enableSettingSubscriptionCookie()
}

// Keep track of feature flag changes
subscriptionCookieManagerFeatureFlagCancellable = privacyConfigurationManager.updatesPublisher
.sink { [weak self, weak privacyConfigurationManager] in
guard let self, let privacyConfigurationManager else { return }

let isEnabled = privacyConfigurationManager.privacyConfig.isSubfeatureEnabled(PrivacyProSubfeature.setAccessTokenCookieForSubscriptionDomains)

Task { [weak self] in
if isEnabled {
self?.subscriptionCookieManager.enableSettingSubscriptionCookie()
await self?.subscriptionCookieManager.refreshSubscriptionCookie()
} else {
await self?.subscriptionCookieManager.disableSettingSubscriptionCookie()
}
}
}

if [.normal, .uiTests].contains(NSApp.runType) {
stateRestorationManager.applicationDidFinishLaunching()
}
Expand Down
6 changes: 6 additions & 0 deletions DuckDuckGo/Common/Extensions/NSViewExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ extension NSView {
set { isHidden = !newValue }
}

var isVisible: Bool {
guard !isHiddenOrHasHiddenAncestor,
let window, window.isVisible else { return false }
return true
}

func makeMeFirstResponder() {
guard let window = window else {
Logger.general.error("\(self.className): Window not available")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ extension NSPopover {
// https://app.asana.com/0/1201037661562251/1206407295280737/f
@objc(swizzled_showRelativeToRect:ofView:preferredEdge:)
private dynamic func swizzled_show(relativeTo positioningRect: NSRect, of positioningView: NSView, preferredEdge: NSRectEdge) {
if positioningView.superview == nil {
if positioningView.window == nil {
var observer: Cancellable?
observer = positioningView.observe(\.window) { positioningView, _ in
if positioningView.window != nil {
Expand Down
4 changes: 4 additions & 0 deletions DuckDuckGo/MainWindow/MainWindowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,12 @@ final class MainWindowController: NSWindowController {
return false
#elseif REVIEW
if Application.runType == .uiTests {
Application.appDelegate.onboardingStateMachine.state = .onboardingCompleted
return false
} else {
if Application.runType == .uiTestsOnboarding {
Application.appDelegate.onboardingStateMachine.state = .onboardingCompleted
}
let onboardingIsComplete = OnboardingViewModel.isOnboardingFinished || LocalStatisticsStore().waitlistUnlocked
return !onboardingIsComplete
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ final class AddressBarButtonsViewController: NSViewController {
@IBOutlet weak var imageButtonWrapper: NSView!
@IBOutlet weak var imageButton: NSButton!
@IBOutlet weak var clearButton: NSButton!
@IBOutlet weak var buttonsContainer: NSStackView!
@IBOutlet private weak var buttonsContainer: NSStackView!

@IBOutlet weak var animationWrapperView: NSView!
var trackerAnimationView1: LottieAnimationView!
Expand All @@ -72,7 +72,7 @@ final class AddressBarButtonsViewController: NSViewController {

@IBOutlet weak var notificationAnimationView: NavigationBarBadgeAnimationView!

@IBOutlet weak var permissionButtons: NSView!
@IBOutlet private weak var permissionButtons: NSView!
@IBOutlet weak var cameraButton: PermissionButton! {
didSet {
cameraButton.isHidden = true
Expand Down Expand Up @@ -368,7 +368,7 @@ final class AddressBarButtonsViewController: NSViewController {
return
}
}
guard button.isShown, permissionButtons.isShown else { return }
guard button.isVisible else { return }

(popover.contentViewController as? PermissionAuthorizationViewController)?.query = query
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .maxY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,18 @@ import Subscription
enum SubscriptionCookieManagerPixel: PixelKitEventV2 {

case missingTokenOnSignIn
case missingCookieOnSignOut
case cookieRefreshedWithUpdate
case cookieRefreshedWithDelete
case cookieRefreshedWithAccessToken
case cookieRefreshedWithEmptyValue
case failedToSetSubscriptionCookie

var name: String {
switch self {
case .missingTokenOnSignIn:
return "m_mac_privacy-pro_subscription-cookie-missing_token_on_sign_in"
case .missingCookieOnSignOut:
return "m_mac_privacy-pro_subscription-cookie-missing_cookie_on_sign_out"
case .cookieRefreshedWithUpdate:
return "m_mac_privacy-pro_subscription-cookie-refreshed_with_update"
case .cookieRefreshedWithDelete:
return "m_mac_privacy-pro_subscription-cookie-refreshed_with_delete"
case .cookieRefreshedWithAccessToken:
return "m_mac_privacy-pro_subscription-cookie-refreshed_with_access_token"
case .cookieRefreshedWithEmptyValue:
return "m_mac_privacy-pro_subscription-cookie-refreshed_with_empty_value"
case .failedToSetSubscriptionCookie:
return "m_mac_privacy-pro_subscription-cookie-failed_to_set_subscription_cookie"
}
Expand All @@ -61,12 +58,10 @@ public final class SubscriptionCookieManageEventPixelMapping: EventMapping<Subsc
switch event {
case .errorHandlingAccountDidSignInTokenIsMissing:
return .missingTokenOnSignIn
case .errorHandlingAccountDidSignOutCookieIsMissing:
return .missingCookieOnSignOut
case .subscriptionCookieRefreshedWithUpdate:
return .cookieRefreshedWithUpdate
case .subscriptionCookieRefreshedWithDelete:
return .cookieRefreshedWithDelete
case .subscriptionCookieRefreshedWithAccessToken:
return .cookieRefreshedWithAccessToken
case .subscriptionCookieRefreshedWithEmptyValue:
return .cookieRefreshedWithEmptyValue
case .failedToSetSubscriptionCookie:
return .failedToSetSubscriptionCookie
}
Expand Down
3 changes: 2 additions & 1 deletion DuckDuckGo/Tab/Services/WebsiteDataStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import Common
import WebKit
import GRDB
import Subscription
import os.log

public protocol HTTPCookieStore {
Expand Down Expand Up @@ -154,7 +155,7 @@ internal class WebCacheManager {

// Don't clear fireproof domains
let cookiesToRemove = cookies.filter { cookie in
!self.fireproofDomains.isFireproof(cookieDomain: cookie.domain) && cookie.domain != URL.cookieDomain
!self.fireproofDomains.isFireproof(cookieDomain: cookie.domain) && ![URL.cookieDomain, SubscriptionCookieManager.cookieDomain].contains(cookie.domain)

Check failure on line 158 in DuckDuckGo/Tab/Services/WebsiteDataStore.swift

View workflow job for this annotation

GitHub Actions / Build Notarized Review app / Export Notarized App

cannot find 'SubscriptionCookieManager' in scope

Check failure on line 158 in DuckDuckGo/Tab/Services/WebsiteDataStore.swift

View workflow job for this annotation

GitHub Actions / Make Release Build

cannot find 'SubscriptionCookieManager' in scope
}

for cookie in cookiesToRemove {
Expand Down
2 changes: 1 addition & 1 deletion LocalPackages/DataBrokerProtection/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ let package = Package(
targets: ["DataBrokerProtection"])
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "202.2.0"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "202.3.0"),
.package(path: "../SwiftUIExtensions"),
.package(path: "../XPCHelper"),
.package(path: "../Freemium"),
Expand Down
2 changes: 1 addition & 1 deletion LocalPackages/NetworkProtectionMac/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ let package = Package(
.library(name: "VPNAppLauncher", targets: ["VPNAppLauncher"]),
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "202.2.0"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "202.3.0"),
.package(url: "https://github.com/airbnb/lottie-spm", exact: "4.4.3"),
.package(path: "../AppLauncher"),
.package(path: "../UDSHelper"),
Expand Down
2 changes: 1 addition & 1 deletion LocalPackages/SubscriptionUI/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let package = Package(
targets: ["SubscriptionUI"]),
],
dependencies: [
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "202.2.0"),
.package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "202.3.0"),
.package(path: "../SwiftUIExtensions")
],
targets: [
Expand Down
2 changes: 2 additions & 0 deletions UITests/Common/UITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ enum UITests {
/// - Parameter requestedToggleState: How the autocomplete checkbox state should be set
static func setAutocompleteToggleBeforeTestcaseRuns(_ requestedToggleState: Bool) {
let app = XCUIApplication()
app.launchEnvironment["UITEST_MODE"] = "1"
app.launch()

let settings = app.menuItems["MainMenu.preferencesMenuItem"]
Expand Down Expand Up @@ -102,6 +103,7 @@ enum UITests {
notificationCenter.typeKey(.escape, modifierFlags: [])
}
let app = XCUIApplication()
app.launchEnvironment["UITEST_MODE"] = "1"
app.launch()
app.typeKey("n", modifierFlags: .command)
app.typeKey("w", modifierFlags: [.command, .option])
Expand Down
97 changes: 44 additions & 53 deletions UITests/OnboardingUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ final class OnboardingUITests: UITestCase {
try resetApplicationData()
}

override func tearDownWithError() throws {
try resetApplicationData()
}

func testOnboardingToBrowsing() throws {
try resetApplicationData()
continueAfterFailure = false
Expand All @@ -39,76 +43,63 @@ final class OnboardingUITests: UITestCase {
XCTAssertFalse(optionsButton.isEnabled)

// Get Started
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Tired of being tracked online? We can help!"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
let getStartedButton = welcomeWindow.webViews["Welcome"].buttons["Get Started"]
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Ready for a faster browser that keeps you protected?"].waitForExistence(timeout: UITests.Timeouts.elementExistence))

let getStartedButton = welcomeWindow.webViews["Welcome"].buttons["Let’s Do It!"]
XCTAssertTrue(getStartedButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
getStartedButton.click()
// When it clicks on the button the y it's not alligned
let centerCoordinate = getStartedButton.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.2))
centerCoordinate.tap()

// Protections activated
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Protections activated!"].waitForExistence(timeout: UITests.Timeouts.elementExistence))

// Default Privacy
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Unlike other browsers, DuckDuckGo comes with privacy by default"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Private Search"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Advanced Tracking Protection"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Automatic Cookie Pop-Up Blocking"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
let gotItButton = welcomeWindow.webViews["Welcome"].buttons["Got It"]
XCTAssertTrue(gotItButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
gotItButton.click()

// Fewer ads and popups
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Private also means fewer ads and pop-ups"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["While browsing the web"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
let seeWithTrackerBlockingButton = welcomeWindow.webViews["Welcome"].buttons["See With Tracker Blocking"]
XCTAssertTrue(seeWithTrackerBlockingButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
seeWithTrackerBlockingButton.click()
XCTAssertTrue(gotItButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
gotItButton.click()
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["While watching YouTube"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
let seeWithDuckPlayerButton = welcomeWindow.webViews["Welcome"].buttons["See With Duck Player"]
XCTAssertTrue(seeWithDuckPlayerButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
seeWithDuckPlayerButton.click()
let nextGotItButton = welcomeWindow.webViews["Welcome"].buttons["Got It"]
XCTAssertTrue(nextGotItButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
nextGotItButton.click()
welcomeWindow.webViews["Welcome"].click()
let nextButton = welcomeWindow.webViews["Welcome"].buttons["Next"]
XCTAssertTrue(nextButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
nextButton.click()

// Make Privacy your go-to
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Make privacy your go-to"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
let skipButton = welcomeWindow.webViews["Welcome"].buttons["Skip"]
XCTAssertTrue(skipButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
skipButton.click()
welcomeWindow.webViews["Welcome"].click()
let importButton = welcomeWindow.webViews["Welcome"].buttons["Import"]
XCTAssertTrue(importButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
importButton.click()

// Let’s get you set up
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Let’s get you set up!"].waitForExistence(timeout: UITests.Timeouts.elementExistence))

XCTAssertTrue(skipButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
skipButton.click()

let importNowButton = welcomeWindow.webViews["Welcome"].buttons["Import Now"]
XCTAssertTrue(importNowButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
importNowButton.click()

let cancelButton = welcomeWindow.sheets.buttons["Cancel"]
XCTAssertTrue(cancelButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
cancelButton.click()

let nextButtonSetUp = welcomeWindow.webViews["Welcome"].buttons["Next"]
XCTAssertTrue(nextButtonSetUp.waitForExistence(timeout: UITests.Timeouts.elementExistence))
nextButtonSetUp.click()

// Duck Player
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Drowning in ads on YouTube? Not with Duck Player!"].waitForExistence(timeout: UITests.Timeouts.elementExistence))

let nextButtonDuckPlayer = welcomeWindow.webViews["Welcome"].buttons["Next"]
XCTAssertTrue(nextButtonDuckPlayer.waitForExistence(timeout: UITests.Timeouts.elementExistence))
nextButtonDuckPlayer.click()

// Customize Experience
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Let’s customize a few things…"].waitForExistence(timeout: UITests.Timeouts.elementExistence))

// Session Restore
XCTAssertTrue(skipButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
skipButton.click()
welcomeWindow.webViews["Welcome"].click()
XCTAssertTrue(nextButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
nextButton.click()

// Customize your experience
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Customize your experience"].waitForExistence(timeout: UITests.Timeouts.elementExistence))
XCTAssertTrue(welcomeWindow.webViews["Welcome"].staticTexts["Make DuckDuckGo work just the way you want."].waitForExistence(timeout: UITests.Timeouts.elementExistence))
let showBookmarksBarButton = welcomeWindow.webViews["Welcome"].buttons["Show Bookmarks Bar"]
XCTAssertTrue(showBookmarksBarButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
showBookmarksBarButton.click()
XCTAssertTrue(welcomeWindow.collectionViews["BookmarksBarViewController.bookmarksBarCollectionView"].waitForExistence(timeout: UITests.Timeouts.elementExistence))

let enableSessionRestoreButton = welcomeWindow.webViews["Welcome"].buttons["Enable Session Restore"]
XCTAssertTrue(enableSessionRestoreButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
enableSessionRestoreButton.click()
welcomeWindow.webViews["Welcome"].click()

let showHomeButton = welcomeWindow.webViews["Welcome"].buttons["Show Home Button"]
XCTAssertTrue(showHomeButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
showHomeButton.click()
XCTAssertTrue(welcomeWindow.children(matching: .button).element(boundBy: 3).waitForExistence(timeout: UITests.Timeouts.elementExistence))
welcomeWindow.webViews["Welcome"].click()
XCTAssertTrue(nextButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
nextButton.click()

// Start Browsing
let startBrowsingButton = welcomeWindow.webViews["Welcome"].buttons["Start Browsing"]
XCTAssertTrue(startBrowsingButton.waitForExistence(timeout: UITests.Timeouts.elementExistence))
startBrowsingButton.click()
Expand Down

0 comments on commit 02b5a06

Please sign in to comment.