Skip to content

Commit

Permalink
Adds a series of UI tests for State Restoration
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1199230911884351/1205717021705374/f
Tech Design URL:
CC:

**Description**: Adds a series of UI tests for State Restoration

**Steps to test this PR**:
1. Open the scheme **UI Tests**
2. Navigate to the test pane
3. Run `StateRestorationTests`

**Note**: If this builds a `review` build that is treated as a first run
on your system during every test (for instance, asking you where to put
the application), please **build and run** the scheme once instead of
running its tests, and go through the new app install first run steps
once before running the tests, and answer any first install questions.

**UI Tests general guidelines for everyone**: 

* It (unfortunately!) isn't possible to multitask while running UI tests
on your local machine, because your mousing/interface usage will change
or intercept screen interactions that the tests depend on.
* Much as we all want UI testing to work on multi-monitor setups, we
have noticed specific focus issues related to waiting for focus across
two monitors simultaneously, so we have decided to test the tests on a
single monitor.
* We are currently testing with English as the app destination language.
* If you experience test failures in your local environment, please
always send the `xcresult` bundle so it is possible to view what
happened differently on your machine, even if it seems like the same
failure as a previous failure (it may be subtly different). Please give
its screenshots or screen recording a look first before sending, just to
rule out one-off failure causes like an unrelated app unexpectedly
throwing up an update helper (or something similar) in front of where
`XCUITest` is waiting for a UI element to exist.
* Since the `xcresult` bundle will include a screen recording or
screenshots, for your privacy, please consider things like your chats,
calls, and open documents that you don't want to send to a contractor
when you are running the tests.

Thank you very much for your help!
  • Loading branch information
Halle authored Apr 9, 2024
1 parent 4b9fa1a commit 532ec92
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 3 deletions.
4 changes: 4 additions & 0 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3303,6 +3303,7 @@
EE7295ED2A545C0A008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295EC2A545C0A008C0991 /* NetworkProtection */; };
EE7295EF2A545C12008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295EE2A545C12008C0991 /* NetworkProtection */; };
EE7F74912BB5D76600CD9456 /* BookmarksBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE7F74902BB5D76600CD9456 /* BookmarksBarTests.swift */; };
EE9D81C32BC57A3700338BE3 /* StateRestorationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D81C22BC57A3700338BE3 /* StateRestorationTests.swift */; };
EEA3EEB12B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */; };
EEA3EEB32B24EC0600E8333A /* VPNLocationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */; };
EEAD7A7C2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; };
Expand Down Expand Up @@ -4777,6 +4778,7 @@
EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift"; sourceTree = "<group>"; };
EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = "<group>"; };
EE7F74902BB5D76600CD9456 /* BookmarksBarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksBarTests.swift; sourceTree = "<group>"; };
EE9D81C22BC57A3700338BE3 /* StateRestorationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateRestorationTests.swift; sourceTree = "<group>"; };
EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = "<group>"; };
EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNLocationViewModel.swift; sourceTree = "<group>"; };
EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLauncher.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6562,6 +6564,7 @@
EE7F74902BB5D76600CD9456 /* BookmarksBarTests.swift */,
EE02D41B2BB460A600DBE6B3 /* BrowsingHistoryTests.swift */,
EE0429DF2BA31D2F009EB20F /* FindInPageTests.swift */,
EE9D81C22BC57A3700338BE3 /* StateRestorationTests.swift */,
7B4CE8E626F02134009134B1 /* TabBarTests.swift */,
);
path = UITests;
Expand Down Expand Up @@ -12282,6 +12285,7 @@
EE02D41A2BB4609900DBE6B3 /* UITests.swift in Sources */,
EE0429E02BA31D2F009EB20F /* FindInPageTests.swift in Sources */,
EE02D4212BB460FE00DBE6B3 /* StringExtension.swift in Sources */,
EE9D81C32BC57A3700338BE3 /* StateRestorationTests.swift in Sources */,
EE54F7B32BBFEA49006218DB /* BookmarksAndFavoritesTests.swift in Sources */,
EE02D4222BB4611A00DBE6B3 /* TestsURLExtension.swift in Sources */,
7B4CE8E726F02135009134B1 /* TabBarTests.swift in Sources */,
Expand Down
8 changes: 5 additions & 3 deletions DuckDuckGo/Preferences/View/PreferencesGeneralView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ extension Preferences {
PreferencePaneSubSection {
Picker(selection: $startupModel.restorePreviousSession, content: {
Text(UserText.showHomePage).tag(false)
.padding(.bottom, 4)
.padding(.bottom, 4).accessibilityIdentifier("PreferencesGeneralView.stateRestorePicker.openANewWindow")
Text(UserText.reopenAllWindowsFromLastSession).tag(true)
.accessibilityIdentifier("PreferencesGeneralView.stateRestorePicker.reopenAllWindowsFromLastSession")
}, label: {})
.pickerStyle(.radioGroup)
.offset(x: PreferencesViews.Const.pickerHorizontalOffset)
.pickerStyle(.radioGroup)
.offset(x: PreferencesViews.Const.pickerHorizontalOffset)
.accessibilityIdentifier("PreferencesGeneralView.stateRestorePicker")
}
}

Expand Down
134 changes: 134 additions & 0 deletions UITests/StateRestorationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
//
// StateRestorationTests.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 XCTest

class StateRestorationTests: XCTestCase {
private var app: XCUIApplication!
private var firstPageTitle: String!
private var secondPageTitle: String!
private var firstURLForBookmarksBar: URL!
private var secondURLForBookmarksBar: URL!
private let titleStringLength = 12
private var addressBarTextField: XCUIElement!
private var settingsGeneralButton: XCUIElement!
private var openANewWindowPreference: XCUIElement!
private var reopenAllWindowsFromLastSessionPreference: XCUIElement!

override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication()
app.launchEnvironment["UITEST_MODE"] = "1"
firstPageTitle = UITests.randomPageTitle(length: titleStringLength)
secondPageTitle = UITests.randomPageTitle(length: titleStringLength)
firstURLForBookmarksBar = UITests.simpleServedPage(titled: firstPageTitle)
secondURLForBookmarksBar = UITests.simpleServedPage(titled: secondPageTitle)
addressBarTextField = app.windows.textFields["AddressBarViewController.addressBarTextField"]
settingsGeneralButton = app.buttons["PreferencesSidebar.generalButton"]
openANewWindowPreference = app.radioButtons["PreferencesGeneralView.stateRestorePicker.openANewWindow"]
reopenAllWindowsFromLastSessionPreference = app.radioButtons["PreferencesGeneralView.stateRestorePicker.reopenAllWindowsFromLastSession"]

app.launch()
app.typeKey("w", modifierFlags: [.command, .option, .shift]) // Let's enforce a single window
app.typeKey("n", modifierFlags: .command)
}

override func tearDownWithError() throws {
app.terminate()
}

func test_tabStateAtRelaunch_shouldContainTwoSitesVisitedInPreviousSession_whenReopenAllWindowsFromLastSessionIsSet() {
app.typeKey(",", modifierFlags: [.command]) // Open settings
settingsGeneralButton.click(forDuration: 0.5, thenDragTo: settingsGeneralButton)
reopenAllWindowsFromLastSessionPreference.clickAfterExistenceTestSucceeds()
app.typeKey("w", modifierFlags: [.command, .option, .shift]) // Close windows
app.typeKey("n", modifierFlags: .command)
XCTAssertTrue(
addressBarTextField.waitForExistence(timeout: UITests.Timeouts.elementExistence),
"The address bar text field didn't become available in a reasonable timeframe."
)
addressBarTextField.typeURL(firstURLForBookmarksBar)
XCTAssertTrue(
app.windows.webViews[firstPageTitle].waitForExistence(timeout: UITests.Timeouts.elementExistence),
"Site didn't load with the expected title in a reasonable timeframe."
)
app.typeKey("t", modifierFlags: [.command])
app.typeURL(secondURLForBookmarksBar)
XCTAssertTrue(
app.windows.webViews[secondPageTitle].waitForExistence(timeout: UITests.Timeouts.elementExistence),
"Site didn't load with the expected title in a reasonable timeframe."
)

app.terminate()
app.launch()

XCTAssertTrue(
app.windows.webViews[secondPageTitle].waitForExistence(timeout: UITests.Timeouts.elementExistence),
"Second visited site wasn't found in a webview with the expected title in a reasonable timeframe."
)
app.typeKey("w", modifierFlags: [.command])
XCTAssertTrue(
app.windows.webViews[firstPageTitle].waitForExistence(timeout: UITests.Timeouts.elementExistence),
"First visited site wasn't found in a webview with the expected title in a reasonable timeframe."
)
}

func test_tabStateAtRelaunch_shouldContainNoSitesVisitedInPreviousSession_whenReopenAllWindowsFromLastSessionIsUnset() {
app.typeKey(",", modifierFlags: [.command]) // Open settings
settingsGeneralButton.click(forDuration: 0.5, thenDragTo: settingsGeneralButton)
openANewWindowPreference.clickAfterExistenceTestSucceeds()
app.typeKey("w", modifierFlags: [.command, .option, .shift]) // Close windows
app.typeKey("n", modifierFlags: .command)
XCTAssertTrue(
addressBarTextField.waitForExistence(timeout: UITests.Timeouts.elementExistence),
"The address bar text field didn't become available in a reasonable timeframe."
)
addressBarTextField.typeURL(firstURLForBookmarksBar)
XCTAssertTrue(
app.windows.webViews[firstPageTitle].waitForExistence(timeout: UITests.Timeouts.elementExistence),
"Site didn't load with the expected title in a reasonable timeframe."
)
app.typeKey("t", modifierFlags: [.command])
app.typeURL(secondURLForBookmarksBar)
XCTAssertTrue(
app.windows.webViews[secondPageTitle].waitForExistence(timeout: UITests.Timeouts.elementExistence),
"Site didn't load with the expected title in a reasonable timeframe."
)

app.terminate()
app.launch()

XCTAssertTrue(
app.windows.webViews[secondPageTitle].waitForNonExistence(timeout: UITests.Timeouts.elementExistence),
"Second visited site from previous session should not be in any webview."
)
XCTAssertTrue(
app.windows.webViews[firstPageTitle].waitForNonExistence(timeout: UITests.Timeouts.elementExistence),
"First visited site from previous session should not be in any webview."
)
app.typeKey("w", modifierFlags: [.command])
XCTAssertTrue(
app.windows.webViews[firstPageTitle].waitForNonExistence(timeout: UITests.Timeouts.elementExistence),
"First visited site from previous session should not be in any webview."
)
XCTAssertTrue(
app.windows.webViews[secondPageTitle].waitForNonExistence(timeout: UITests.Timeouts.elementExistence),
"Second visited site from previous session should not be in any webview."
)
}
}

0 comments on commit 532ec92

Please sign in to comment.