Skip to content

Commit

Permalink
update settings tip (#84)
Browse files Browse the repository at this point in the history
update tests
update cloud kit database
  • Loading branch information
erolburak authored May 23, 2024
1 parent c5461e4 commit 44698fc
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 35 deletions.
6 changes: 6 additions & 0 deletions BobbysNews/Presentation/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ struct ContentView: View {
Image(systemName: "gearshape.circle.fill")
.popoverTip(viewModel.settingsTip,
arrowEdge: .top)
.onAppear {
Task {
try await Task.sleep(for: .seconds(1))
try await viewModel.showSettingsTip()
}
}
.accessibilityIdentifier("SettingsImage")
}
.onTapGesture {
Expand Down
17 changes: 12 additions & 5 deletions BobbysNews/Presentation/ContentViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,15 @@ final class ContentViewModel: Sendable {

// MARK: - Properties

@Parameter
static var show: Bool = false
var image: Image? = Image(systemName: "gearshape.circle.fill")
var message: Text? = Text("SettingsTipMessage")
var rules: [Rule] {
[#Rule(Self.$show) {
$0 == true
}]
}
var title = Text("Settings")
}

Expand All @@ -55,6 +62,7 @@ final class ContentViewModel: Sendable {

// MARK: - Properties

let settingsTip = SettingsTip()
var alertError: Errors?
var apiKeyTotalAmount = 5
var apiKeyVersion = 1 {
Expand All @@ -75,7 +83,6 @@ final class ContentViewModel: Sendable {
}
var sensoryFeedback: SensoryFeedback?
var sensoryFeedbackBool = false
var settingsTip = SettingsTip()
var showAlert = false
var showConfirmationDialog = false
var stateSources: StateSources = .isLoading
Expand All @@ -95,11 +102,7 @@ final class ContentViewModel: Sendable {
self.deleteTopHeadlinesUseCase = deleteTopHeadlinesUseCase
self.fetchTopHeadlinesUseCase = fetchTopHeadlinesUseCase
self.readTopHeadlinesUseCase = readTopHeadlinesUseCase
#if DEBUG
return
#else
configureTipKit()
#endif
}

func onAppear(selectedCountry: String) {
Expand Down Expand Up @@ -163,6 +166,10 @@ final class ContentViewModel: Sendable {
}
}

func showSettingsTip() async throws {
SettingsTip.show = true
}

private func configureTipKit() {
Task {
try? Tips.configure([.displayFrequency(.immediate),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,9 @@
//

import CoreData
import Combine

public final class PersistenceController {

// MARK: - Private Properties

private let container: NSPersistentContainer

// MARK: - Properties

public static let shared = PersistenceController()
Expand All @@ -27,13 +22,8 @@ public final class PersistenceController {
let managedObjectModel = NSManagedObjectModel(contentsOf: moduleUrl) else {
fatalError("Error initializing managed object model with module url!")
}
#if DEBUG
container = NSPersistentContainer(name: "BobbysNews",
managedObjectModel: managedObjectModel)
#else
NSPersistentCloudKitContainer(name: "BobbysNews",
managedObjectModel: managedObjectModel)
#endif
let container = NSPersistentCloudKitContainer(name: "BobbysNews",
managedObjectModel: managedObjectModel)
container.loadPersistentStores { _, error in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
Expand Down
19 changes: 19 additions & 0 deletions BobbysNewsTests/Presentation/ContentViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@testable import BobbysNews
import BobbysNewsData
import BobbysNewsDomain
import TipKit
import XCTest

class ContentViewModelTests: XCTestCase {
Expand Down Expand Up @@ -88,6 +89,15 @@ class ContentViewModelTests: XCTestCase {
XCTAssertEqual(sut.articles?.count, 1)
}

func testInvalidateSettingsTip() {
// Given
let tipsStatus = Tips.Status.invalidated(.actionPerformed)
// When
sut.invalidateSettingsTip()
// Then
XCTAssertEqual(sut.settingsTip.status, tipsStatus)

Check failure on line 98 in BobbysNewsTests/Presentation/ContentViewModelTests.swift

View workflow job for this annotation

GitHub Actions / tests

-[BobbysNewsTests.ContentViewModelTests testInvalidateSettingsTip] : XCTAssertEqual failed: ("available") is not equal to ("invalidated(TipKit.Tips.InvalidationReason.actionPerformed)")
}

func testReset() {
// Given
sut.apiKeyVersion = 2
Expand All @@ -106,4 +116,13 @@ class ContentViewModelTests: XCTestCase {
XCTAssertEqual(sut.stateSources, .emptyRead)
XCTAssertEqual(sut.stateTopHeadlines, .emptyRead)
}

func testShowSettingsTip() async throws {
// Given
ContentViewModel.SettingsTip.show = false
// When
try await sut.showSettingsTip()
// Then
XCTAssertTrue(ContentViewModel.SettingsTip.show)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class DateExtensionTests: XCTestCase {
func testToRelativeIsToday() {
// Given
let date = Date.now
let relative = Locale.current.language.languageCode == "en" ? "Today" : ""
let relative = "Today"
// When
let relativeDate = date.toRelative
// Then
Expand All @@ -26,7 +26,7 @@ class DateExtensionTests: XCTestCase {
// Given
let date = Calendar.current.date(byAdding: DateComponents(day: -1),
to: .now)
let relative = Locale.current.language.languageCode == "en" ? "Yesterday" : ""
let relative = "Yesterday"
// When
let relativeDate = date?.toRelative ?? relative
// Then
Expand Down
14 changes: 12 additions & 2 deletions BobbysNewsUITests/Extension/XCUIApplication+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,18 @@ extension XCUIApplication {

// MARK: - Properties

/// Identifies if limited request alert is visible
/// Detects if limited request alert is visible
var isLimitedRequestAlertVisible: Bool {
self.alerts[Locale.current.language.languageCode == "en" ? "Limited requests" : ""].waitForExistence(timeout: 5)
self.alerts["Limited requests"].waitForExistence(timeout: 5)
}

// MARK: - Actions

/// Detects if settings tip is visible and closes it
func closeSettingsTip() {
let closeSettingsTipButton = self.popovers.buttons["Close"]
if closeSettingsTipButton.waitForExistence(timeout: 5) {
closeSettingsTipButton.tap()
}
}
}
43 changes: 32 additions & 11 deletions BobbysNewsUITests/Presentation/ContentViewTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,51 @@ final class ContentViewTests: XCTestCase {
continueAfterFailure = false
}

/// Test navigation link item to open detail view
/// Test navigation link item to open detail view steps:
/// 1) Close settings tip
/// 2) Open detail view
@MainActor
func testNavigationLinkItem() {
let app = XCUIApplication()
app.launch()
app.closeSettingsTip()
if !app.isLimitedRequestAlertVisible {
let navigationLink = app.buttons["NavigationLinkItem"]
XCTAssertTrue(navigationLink.waitForExistence(timeout: 5))
navigationLink.tap()
}
}

/// Test settings button to open settings menu
/// Test settings button to open settings menu steps:
/// 1) Close settings tip
/// 2) Open settings menu
@MainActor
func testSettingsButton() {
let app = XCUIApplication()
app.launch()
app.closeSettingsTip()
if !app.isLimitedRequestAlertVisible {
let settingsImage = app.navigationBars[Locale.current.language.languageCode == "en" ? "Top headlines" : ""].images["SettingsImage"]
let settingsImage = app.navigationBars["Top headlines"].images["SettingsImage"]
XCTAssertTrue(settingsImage.waitForExistence(timeout: 5))
settingsImage.tap()
}
}

/// Test country picker item to change country while first opening settings menu
/// Test country picker item to change country steps:
/// 1) Close settings tip
/// 2) Open settings menu
/// 3) Open country picker
/// 4) Set selected country to DE
@MainActor
func testCountryPickerItem() {
let app = XCUIApplication()
app.launch()
app.closeSettingsTip()
if !app.isLimitedRequestAlertVisible {
let settingsImage = app.navigationBars[Locale.current.language.languageCode == "en" ? "Top headlines" : ""].images["SettingsImage"]
let settingsImage = app.navigationBars["Top headlines"].images["SettingsImage"]
XCTAssertTrue(settingsImage.waitForExistence(timeout: 5))
settingsImage.tap()
let countryPicker = app.collectionViews.buttons[Locale.current.language.languageCode == "en" ? "Country selection" : ""]
let countryPicker = app.collectionViews.buttons["Country selection"]
XCTAssertTrue(countryPicker.waitForExistence(timeout: 5))
countryPicker.tap()
let countryPickerItemDE = app.buttons["CountryPickerItem" + "de"]
Expand All @@ -57,16 +68,21 @@ final class ContentViewTests: XCTestCase {
}
}

/// Test api key picker item to change api key while first opening settings menu
/// Test api key picker item to change api key steps:
/// 1) Close settings tip
/// 2) Open settings menu
/// 3) Open api key picker
/// 4) Set selected api key to 2
@MainActor
func testApiKeyPickerItem() {
let app = XCUIApplication()
app.launch()
app.closeSettingsTip()
if !app.isLimitedRequestAlertVisible {
let settingsImage = app.navigationBars[Locale.current.language.languageCode == "en" ? "Top headlines" : ""].images["SettingsImage"]
let settingsImage = app.navigationBars["Top headlines"].images["SettingsImage"]
XCTAssertTrue(settingsImage.waitForExistence(timeout: 5))
settingsImage.tap()
let apiKeyPicker = app.collectionViews.buttons[Locale.current.language.languageCode == "en" ? "API key selection" : ""]
let apiKeyPicker = app.collectionViews.buttons["API key selection"]
XCTAssertTrue(apiKeyPicker.waitForExistence(timeout: 5))
apiKeyPicker.tap()
let apiKeyPickerItem2 = app.buttons["ApiKeyPickerItem2"]
Expand All @@ -75,13 +91,18 @@ final class ContentViewTests: XCTestCase {
}
}

/// Test reset and confirm reset while first opening settings view
/// Test reset and confirm reset steps:
/// 1) Close settings tip
/// 2) Open settings menu
/// 3) Press reset
/// 4) Check if `ResetConfirmationDialogButton` exists
@MainActor
func testResetButton() {
let app = XCUIApplication()
app.launch()
app.closeSettingsTip()
if !app.isLimitedRequestAlertVisible {
let settingsImage = app.navigationBars[Locale.current.language.languageCode == "en" ? "Top headlines" : ""].images["SettingsImage"]
let settingsImage = app.navigationBars["Top headlines"].images["SettingsImage"]
XCTAssertTrue(settingsImage.waitForExistence(timeout: 5))
settingsImage.tap()
let resetButton = app.buttons["ResetButton"]
Expand Down
19 changes: 16 additions & 3 deletions BobbysNewsUITests/Presentation/DetailViewTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ final class DetailViewTests: XCTestCase {
continueAfterFailure = false
}

/// Test share link to open share view while first opening detail view
/// Test share link to open share view steps:
/// 1) Close settings tip
/// 2) Open detail view
/// 3) Press share
@MainActor
func testShareLink() {
let app = XCUIApplication()
app.launch()
app.closeSettingsTip()
if !app.isLimitedRequestAlertVisible {
let navigationLink = app.scrollViews.otherElements.buttons["NavigationLinkItem"]
if navigationLink.waitForExistence(timeout: 5) {
Expand All @@ -31,11 +35,15 @@ final class DetailViewTests: XCTestCase {
}
}

/// Test read button to open web view while first opening detail view
/// Test read button to open web view steps:
/// 1) Close settings tip
/// 2) Open detail view
/// 3) Press read
@MainActor
func testReadButton() {
let app = XCUIApplication()
app.launch()
app.closeSettingsTip()
if !app.isLimitedRequestAlertVisible {
let navigationLink = app.scrollViews.otherElements.buttons["NavigationLinkItem"]
if navigationLink.waitForExistence(timeout: 5) {
Expand All @@ -47,11 +55,16 @@ final class DetailViewTests: XCTestCase {
}
}

/// Test close button of web view while first opening detail view
/// Test close button of web view steps:
/// 1) Close settings tip
/// 2) Open detail view
/// 3) Press read
/// 4) Close web view
@MainActor
func testCloseButton() {
let app = XCUIApplication()
app.launch()
app.closeSettingsTip()
if !app.isLimitedRequestAlertVisible {
let navigationLink = app.scrollViews.otherElements.buttons["NavigationLinkItem"]
if navigationLink.waitForExistence(timeout: 5) {
Expand Down

0 comments on commit 44698fc

Please sign in to comment.