mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 03:50:08 +02:00
✅ Test improvements
This commit is contained in:
@ -161,6 +161,7 @@
|
||||
C44CCD4127AFE2FC00CE40E5 /* AlertableError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */; };
|
||||
C44CCD4927AFF3B700CE40E5 /* MainMenu+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */; };
|
||||
C44CCD4A27AFF3BC00CE40E5 /* MainMenu+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */; };
|
||||
C44E985F29B23EBF0059F773 /* UpdateCheckTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44E985E29B23EBF0059F773 /* UpdateCheckTest.swift */; };
|
||||
C44F868E2835BD8D005C353A /* phpmon-config.json in Resources */ = {isa = PBXBuildFile; fileRef = C44F868D2835BD8D005C353A /* phpmon-config.json */; };
|
||||
C450C8C628C919EC002A2B4B /* PreferenceName.swift in Sources */ = {isa = PBXBuildFile; fileRef = C450C8C528C919EC002A2B4B /* PreferenceName.swift */; };
|
||||
C450C8C728C919EC002A2B4B /* PreferenceName.swift in Sources */ = {isa = PBXBuildFile; fileRef = C450C8C528C919EC002A2B4B /* PreferenceName.swift */; };
|
||||
@ -860,6 +861,7 @@
|
||||
C44C1990276E44CB0072762D /* ProgressWindow.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ProgressWindow.storyboard; sourceTree = "<group>"; };
|
||||
C44CCD3F27AFE2FC00CE40E5 /* AlertableError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertableError.swift; sourceTree = "<group>"; };
|
||||
C44CCD4827AFF3B700CE40E5 /* MainMenu+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainMenu+Async.swift"; sourceTree = "<group>"; };
|
||||
C44E985E29B23EBF0059F773 /* UpdateCheckTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCheckTest.swift; sourceTree = "<group>"; };
|
||||
C44F868D2835BD8D005C353A /* phpmon-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "phpmon-config.json"; sourceTree = "<group>"; };
|
||||
C450C8C528C919EC002A2B4B /* PreferenceName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceName.swift; sourceTree = "<group>"; };
|
||||
C451AFF52969E40F0078E617 /* HelpButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpButton.swift; sourceTree = "<group>"; };
|
||||
@ -1480,6 +1482,7 @@
|
||||
children = (
|
||||
C471E7BE28F9B90F0021E251 /* StartupTest.swift */,
|
||||
C469E702294CFDF700A82AB2 /* DomainsListTest.swift */,
|
||||
C44E985E29B23EBF0059F773 /* UpdateCheckTest.swift */,
|
||||
C4181F1028FAF9330042EA28 /* UITestCase.swift */,
|
||||
);
|
||||
path = ui;
|
||||
@ -2603,6 +2606,7 @@
|
||||
C471E82C28F9BB340021E251 /* ValetListable.swift in Sources */,
|
||||
C471E82828F9BB310021E251 /* HomebrewDiagnostics.swift in Sources */,
|
||||
C471E81E28F9BB260021E251 /* BetterAlert.swift in Sources */,
|
||||
C44E985F29B23EBF0059F773 /* UpdateCheckTest.swift in Sources */,
|
||||
C471E7D228F9BA630021E251 /* ActiveFileSystem.swift in Sources */,
|
||||
C471E80028F9BAD10021E251 /* Xdebug.swift in Sources */,
|
||||
C471E7F528F9BAC80021E251 /* PhpEnv.swift in Sources */,
|
||||
|
@ -95,7 +95,7 @@
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "--configuration:~/.phpmon_fconf_working.json"
|
||||
isEnabled = "NO">
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "--configuration:~/.phpmon_fconf_working_no_valet.json"
|
||||
|
@ -12,7 +12,7 @@ class Homebrew {
|
||||
struct Formulae {
|
||||
static var php: HomebrewFormula {
|
||||
if PhpEnv.shared.homebrewPackage == nil {
|
||||
fatalError("You must either load the HomebrewPackage object or call `fake` on the Homebrew class.")
|
||||
return HomebrewFormula("php", elevated: true)
|
||||
}
|
||||
|
||||
guard let install = PhpEnv.phpInstall else {
|
||||
|
@ -13,6 +13,7 @@ public struct TestableConfiguration: Codable {
|
||||
var filesystem: [String: FakeFile]
|
||||
var shellOutput: [String: BatchFakeShellOutput]
|
||||
var commandOutput: [String: String]
|
||||
var preferenceOverrides: [PreferenceName: Bool]
|
||||
|
||||
func apply() {
|
||||
Log.separator()
|
||||
@ -24,6 +25,10 @@ public struct TestableConfiguration: Codable {
|
||||
ActiveFileSystem.useTestable(filesystem)
|
||||
Log.info("Applying fake commands...")
|
||||
ActiveCommand.useTestable(commandOutput)
|
||||
Log.info("Applying temporary preference overrides...")
|
||||
preferenceOverrides.forEach { (key: PreferenceName, value: Any?) in
|
||||
Preferences.shared.cachedPreferences[key] = value
|
||||
}
|
||||
|
||||
if Valet.shared.installed {
|
||||
Log.info("Applying fake scanner...")
|
||||
|
@ -9,7 +9,7 @@
|
||||
/**
|
||||
These are the keys used for every preference in the app.
|
||||
*/
|
||||
enum PreferenceName: String {
|
||||
enum PreferenceName: String, Codable {
|
||||
// FIRST-TIME LAUNCH
|
||||
case wasLaunchedBefore = "launched_before"
|
||||
|
||||
|
@ -22,6 +22,8 @@ class TestableConfigurations {
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/bin/php"
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/bin/php-config"
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/bin/valet"
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/opt/php"
|
||||
@ -139,7 +141,21 @@ class TestableConfigurations {
|
||||
"/opt/homebrew/bin/brew services info --all --json"
|
||||
: .instant(ShellStrings.shared.brewServicesAsUser),
|
||||
"curl -s --max-time 10 '\(Constants.Urls.DevBuildCaskFile.absoluteString)'"
|
||||
: .instant("version '5.6.2_976'"),
|
||||
: .delayed(0.5, """
|
||||
cask 'phpmon-dev' do
|
||||
depends_on formula: 'gnu-sed'
|
||||
|
||||
version '\(App.shortVersion)_\(App.bundleVersion)'
|
||||
sha256 '1cb147bd1b1fbd52971d90dff577465b644aee7c878f15ede57f46e8f217067a'
|
||||
|
||||
url 'https://github.com/nicoverbruggen/phpmon/releases/download/v\(App.shortVersion)/phpmon-dev.zip'
|
||||
appcast 'https://github.com/nicoverbruggen/phpmon/releases.atom'
|
||||
name 'PHP Monitor DEV'
|
||||
homepage 'https://phpmon.app'
|
||||
|
||||
app 'PHP Monitor DEV.app', target: "PHP Monitor DEV.app"
|
||||
end
|
||||
"""),
|
||||
"/opt/homebrew/bin/brew unlink php"
|
||||
: .delayed(0.2, "OK"),
|
||||
"/opt/homebrew/bin/brew unlink php@8.2"
|
||||
@ -170,7 +186,8 @@ class TestableConfigurations {
|
||||
: """
|
||||
/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini,
|
||||
"""
|
||||
]
|
||||
],
|
||||
preferenceOverrides: [:]
|
||||
)
|
||||
}
|
||||
|
||||
@ -180,27 +197,29 @@ class TestableConfigurations {
|
||||
architecture: "arm64",
|
||||
filesystem: [
|
||||
"/usr/local/bin/"
|
||||
: .fake(.directory, readOnly: true),
|
||||
: .fake(.directory, readOnly: true),
|
||||
"/usr/local/bin/composer"
|
||||
: .fake(.binary),
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/bin/brew"
|
||||
: .fake(.binary),
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/bin/php"
|
||||
: .fake(.binary),
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/bin/php-config"
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/opt/php"
|
||||
: .fake(.symlink, "/opt/homebrew/Cellar/php/8.2.0"),
|
||||
: .fake(.symlink, "/opt/homebrew/Cellar/php/8.2.0"),
|
||||
"/opt/homebrew/opt/php@8.2/bin/php"
|
||||
: .fake(.symlink, "/opt/homebrew/Cellar/php/8.2.0/bin/php"),
|
||||
: .fake(.symlink, "/opt/homebrew/Cellar/php/8.2.0/bin/php"),
|
||||
"/opt/homebrew/Cellar/php/8.2.0/bin/php"
|
||||
: .fake(.binary),
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/Cellar/php/8.2.0/bin/php-config"
|
||||
: .fake(.binary),
|
||||
: .fake(.binary),
|
||||
"/opt/homebrew/etc/php/8.2/php-fpm.d/www.conf"
|
||||
: .fake(.text),
|
||||
: .fake(.text),
|
||||
"/opt/homebrew/etc/php/8.2/php.ini"
|
||||
: .fake(.text),
|
||||
: .fake(.text),
|
||||
"/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini"
|
||||
: .fake(.text)
|
||||
: .fake(.text)
|
||||
],
|
||||
shellOutput: [
|
||||
"sysctl -n sysctl.proc_translated"
|
||||
@ -306,6 +325,9 @@ class TestableConfigurations {
|
||||
: """
|
||||
/opt/homebrew/etc/php/8.2/conf.d/php-memory-limits.ini,
|
||||
"""
|
||||
],
|
||||
preferenceOverrides: [
|
||||
: // TODO: Add default preferences that are relevant for tests
|
||||
]
|
||||
)
|
||||
}
|
||||
|
@ -16,26 +16,14 @@ final class DomainsListTest: UITestCase {
|
||||
|
||||
override func tearDownWithError() throws {}
|
||||
|
||||
private func openMenu() -> XCPMApplication {
|
||||
let app = XCPMApplication()
|
||||
app.withConfiguration(TestableConfigurations.working)
|
||||
app.launch()
|
||||
|
||||
// Note: If this fails here, make sure the menu bar item can be displayed
|
||||
// If you use Bartender or something like this, this item may be hidden and tests will fail
|
||||
app.statusItems.firstMatch.click()
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
final func test_can_always_open_domains_list() throws {
|
||||
let app = openMenu()
|
||||
let app = launch(openMenu: true)
|
||||
|
||||
app.menuItems["mi_domain_list".localized].click()
|
||||
}
|
||||
|
||||
final func test_can_filter_domains_list() throws {
|
||||
let app = openMenu()
|
||||
let app = launch(openMenu: true)
|
||||
|
||||
app.menuItems["mi_domain_list".localized].click()
|
||||
|
||||
@ -58,7 +46,7 @@ final class DomainsListTest: UITestCase {
|
||||
}
|
||||
|
||||
final func test_can_tap_add_domain_button() throws {
|
||||
let app = openMenu()
|
||||
let app = launch(openMenu: true)
|
||||
|
||||
app.menuItems["mi_domain_list".localized].click()
|
||||
|
||||
|
@ -10,9 +10,33 @@ import XCTest
|
||||
|
||||
class UITestCase: XCTestCase {
|
||||
|
||||
/** Launches the app and opens the menu. */
|
||||
public func launch(
|
||||
openMenu: Bool = false,
|
||||
with configuration: TestableConfiguration? = nil
|
||||
) -> XCPMApplication {
|
||||
let app = XCPMApplication()
|
||||
let config = configuration ?? TestableConfigurations.working
|
||||
app.withConfiguration(config)
|
||||
app.launch()
|
||||
|
||||
// Note: If this fails here, make sure the menu bar item can be displayed
|
||||
// If you use Bartender or something like this, this item may be hidden and tests will fail
|
||||
if openMenu {
|
||||
app.statusItems.firstMatch.click()
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
/** Checks if a single element exists. */
|
||||
public func assertExists(_ element: XCUIElement, _ timeout: TimeInterval = 0.05) {
|
||||
XCTAssert(element.waitForExistence(timeout: timeout))
|
||||
XCTAssertTrue(element.waitForExistence(timeout: timeout))
|
||||
}
|
||||
|
||||
/** Checks if a single element fails to exist. */
|
||||
public func assertNotExists(_ element: XCUIElement, _ timeout: TimeInterval = 0.05) {
|
||||
XCTAssertFalse(element.waitForExistence(timeout: timeout))
|
||||
}
|
||||
|
||||
/** Checks if all elements exist. */
|
||||
|
121
tests/ui/UpdateCheckTest.swift
Normal file
121
tests/ui/UpdateCheckTest.swift
Normal file
@ -0,0 +1,121 @@
|
||||
//
|
||||
// UpdateCheckTest.swift
|
||||
// UI Tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 13/03/2023.
|
||||
// Copyright © 2023 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class UpdateCheckTest: UITestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
continueAfterFailure = false
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {}
|
||||
|
||||
final func test_can_check_for_updates_with_no_new_update() throws {
|
||||
let app = launch(openMenu: true)
|
||||
app.menuItems["mi_check_for_updates".localized].click()
|
||||
|
||||
assertExists(app.staticTexts["updater.alerts.is_latest_version.title".localized], 1.0)
|
||||
assertExists(app.buttons["generic.ok".localized])
|
||||
}
|
||||
|
||||
final func test_will_prompt_at_launch_new_version_available() throws {
|
||||
var configuration = TestableConfigurations.working
|
||||
|
||||
// Ensure automatic check is enabled
|
||||
configuration.preferenceOverrides[.automaticBackgroundUpdateCheck] = true
|
||||
|
||||
// Ensure an update is available
|
||||
configuration.shellOutput[
|
||||
"curl -s --max-time 10 '\(Constants.Urls.DevBuildCaskFile.absoluteString)'"
|
||||
] = .delayed(0.5, """
|
||||
cask 'phpmon-dev' do
|
||||
depends_on formula: 'gnu-sed'
|
||||
|
||||
version '99.0.0_9999'
|
||||
sha256 '1cb147bd1b1fbd52971d90dff577465b644aee7c878f15ede57f46e8f217067a'
|
||||
|
||||
url 'https://github.com/nicoverbruggen/phpmon/releases/download/v99.0/phpmon-dev.zip'
|
||||
appcast 'https://github.com/nicoverbruggen/phpmon/releases.atom'
|
||||
name 'PHP Monitor DEV'
|
||||
homepage 'https://phpmon.app'
|
||||
|
||||
app 'PHP Monitor DEV.app', target: "PHP Monitor DEV.app"
|
||||
end
|
||||
""")
|
||||
|
||||
let app = launch(openMenu: false, with: configuration)
|
||||
|
||||
// Expect to see the content of the appropriate alert box
|
||||
assertExists(app.staticTexts["updater.alerts.newer_version_available.title".localized("99.0.0 (9999)")], 2)
|
||||
assertExists(app.buttons["updater.alerts.buttons.install".localized])
|
||||
assertExists(app.buttons["updater.alerts.buttons.dismiss".localized])
|
||||
}
|
||||
|
||||
final func test_will_require_manual_search_for_update() throws {
|
||||
var configuration = TestableConfigurations.working
|
||||
|
||||
// Ensure automatic check is disabled
|
||||
configuration.preferenceOverrides[.automaticBackgroundUpdateCheck] = false
|
||||
|
||||
// Ensure an update is available
|
||||
configuration.shellOutput[
|
||||
"curl -s --max-time 10 '\(Constants.Urls.DevBuildCaskFile.absoluteString)'"
|
||||
] = .delayed(0.5, """
|
||||
cask 'phpmon-dev' do
|
||||
depends_on formula: 'gnu-sed'
|
||||
|
||||
version '99.0.0_9999'
|
||||
sha256 '1cb147bd1b1fbd52971d90dff577465b644aee7c878f15ede57f46e8f217067a'
|
||||
|
||||
url 'https://github.com/nicoverbruggen/phpmon/releases/download/v99.0/phpmon-dev.zip'
|
||||
appcast 'https://github.com/nicoverbruggen/phpmon/releases.atom'
|
||||
name 'PHP Monitor DEV'
|
||||
homepage 'https://phpmon.app'
|
||||
|
||||
app 'PHP Monitor DEV.app', target: "PHP Monitor DEV.app"
|
||||
end
|
||||
""")
|
||||
|
||||
// Wait for the menu to open and search for updates
|
||||
let app = launch(openMenu: false, with: configuration)
|
||||
|
||||
// The check should not happen if the preference is disabled
|
||||
assertNotExists(app.staticTexts["updater.alerts.newer_version_available.title".localized("99.0.0 (9999)")], 2)
|
||||
|
||||
// Open the menu and check manually
|
||||
app.statusItems.firstMatch.click()
|
||||
app.menuItems["mi_check_for_updates".localized].click()
|
||||
|
||||
// Expect to see the content of the appropriate alert box
|
||||
assertExists(app.staticTexts["updater.alerts.newer_version_available.title".localized("99.0.0 (9999)")], 2)
|
||||
assertExists(app.buttons["updater.alerts.buttons.install".localized])
|
||||
assertExists(app.buttons["updater.alerts.buttons.dismiss".localized])
|
||||
}
|
||||
|
||||
final func test_could_not_parse_version() throws {
|
||||
var configuration = TestableConfigurations.working
|
||||
|
||||
// Ensure automatic check is disabled
|
||||
configuration.preferenceOverrides[.automaticBackgroundUpdateCheck] = false
|
||||
|
||||
// Ensure an update is available
|
||||
configuration.shellOutput[
|
||||
"curl -s --max-time 10 '\(Constants.Urls.DevBuildCaskFile.absoluteString)'"
|
||||
] = .delayed(0.5, "404 PAGE NOT FOUND")
|
||||
|
||||
// Wait for the menu to open and search for updates
|
||||
let app = launch(openMenu: true, with: configuration)
|
||||
app.menuItems["mi_check_for_updates".localized].click()
|
||||
|
||||
// Expect to see the content of the appropriate alert box
|
||||
assertExists(app.staticTexts["updater.alerts.cannot_check_for_update.title".localized], 2)
|
||||
assertExists(app.buttons["generic.ok".localized])
|
||||
assertExists(app.buttons["updater.alerts.buttons.releases_on_github".localized])
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user