Disable export until a system has components
The Overview share menu offered a wiring diagram and a full report even for an empty system. Gate it on loads, batteries or chargers being present (iOS + Android) and add UI tests for both states.
This commit is contained in:
@@ -56,6 +56,10 @@ struct LoadsView: View {
|
|||||||
allChargers.filter { $0.system == system }
|
allChargers.filter { $0.system == system }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var hasComponents: Bool {
|
||||||
|
!savedLoads.isEmpty || !savedBatteries.isEmpty || !savedChargers.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
TabView(selection: $selectedComponentTab) {
|
TabView(selection: $selectedComponentTab) {
|
||||||
@@ -174,6 +178,7 @@ struct LoadsView: View {
|
|||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "square.and.arrow.up")
|
Image(systemName: "square.and.arrow.up")
|
||||||
}
|
}
|
||||||
|
.disabled(!hasComponents)
|
||||||
.accessibilityIdentifier("system-overview-share-button")
|
.accessibilityIdentifier("system-overview-share-button")
|
||||||
}
|
}
|
||||||
} else if showPrimary || showEditLoads || showEditBatteries || showEditChargers {
|
} else if showPrimary || showEditLoads || showEditBatteries || showEditChargers {
|
||||||
|
|||||||
71
CableUITestsScreenshot/SystemExportButtonUITests.swift
Normal file
71
CableUITestsScreenshot/SystemExportButtonUITests.swift
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import XCTest
|
||||||
|
|
||||||
|
/// Verifies that the Overview export/share menu is only available once the
|
||||||
|
/// system actually contains something worth exporting.
|
||||||
|
final class SystemExportButtonUITests: XCTestCase {
|
||||||
|
|
||||||
|
override func setUpWithError() throws {
|
||||||
|
try super.setUpWithError()
|
||||||
|
continueAfterFailure = false
|
||||||
|
XCUIDevice.shared.orientation = .portrait
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func testExportIsDisabledForSystemWithoutComponents() throws {
|
||||||
|
let app = launch(arguments: ["--uitest-reset-data"])
|
||||||
|
|
||||||
|
let createSystemButton = app.buttons["create-system-button"]
|
||||||
|
XCTAssertTrue(createSystemButton.waitForExistence(timeout: 15))
|
||||||
|
createSystemButton.tap()
|
||||||
|
|
||||||
|
let shareButton = app.buttons["system-overview-share-button"]
|
||||||
|
XCTAssertTrue(shareButton.waitForExistence(timeout: 15))
|
||||||
|
XCTAssertFalse(
|
||||||
|
shareButton.isEnabled,
|
||||||
|
"Export must stay disabled while the system has no loads, batteries or chargers"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func testExportIsEnabledOnceComponentsExist() throws {
|
||||||
|
let app = launch(arguments: ["--uitest-reset-data", "--uitest-sample-data"])
|
||||||
|
|
||||||
|
openFirstSystem(in: app)
|
||||||
|
|
||||||
|
let shareButton = app.buttons["system-overview-share-button"]
|
||||||
|
XCTAssertTrue(shareButton.waitForExistence(timeout: 15))
|
||||||
|
XCTAssertTrue(
|
||||||
|
shareButton.isEnabled,
|
||||||
|
"Export must be available for a system that has components"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Helpers
|
||||||
|
|
||||||
|
private func launch(arguments: [String]) -> XCUIApplication {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launchArguments = arguments
|
||||||
|
app.launch()
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
private func openFirstSystem(in app: XCUIApplication) {
|
||||||
|
let list: XCUIElement
|
||||||
|
if app.collectionViews["systems-list"].waitForExistence(timeout: 15) {
|
||||||
|
list = app.collectionViews["systems-list"]
|
||||||
|
} else {
|
||||||
|
list = app.collectionViews.firstMatch
|
||||||
|
}
|
||||||
|
XCTAssertTrue(list.waitForExistence(timeout: 15))
|
||||||
|
|
||||||
|
let firstCell = list.cells.element(boundBy: 0)
|
||||||
|
XCTAssertTrue(firstCell.waitForExistence(timeout: 10))
|
||||||
|
|
||||||
|
let cellButton = firstCell.buttons.firstMatch
|
||||||
|
if cellButton.exists {
|
||||||
|
cellButton.tap()
|
||||||
|
} else {
|
||||||
|
firstCell.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -157,7 +157,7 @@ fun SystemDetailScreen(
|
|||||||
strokeWidth = 2.dp,
|
strokeWidth = 2.dp,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
IconButton(onClick = { showOverviewMenu = true }) {
|
IconButton(onClick = { showOverviewMenu = true }, enabled = state.hasComponents) {
|
||||||
Icon(Icons.Outlined.IosShare, contentDescription = stringResource(R.string.overview_share_pdf))
|
Icon(Icons.Outlined.IosShare, contentDescription = stringResource(R.string.overview_share_pdf))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ data class DetailState(
|
|||||||
val chargers: List<SavedCharger> = emptyList(),
|
val chargers: List<SavedCharger> = emptyList(),
|
||||||
) {
|
) {
|
||||||
val metrics: SystemMetrics get() = SystemMetrics(loads, batteries, chargers)
|
val metrics: SystemMetrics get() = SystemMetrics(loads, batteries, chargers)
|
||||||
|
|
||||||
|
val hasComponents: Boolean
|
||||||
|
get() = loads.isNotEmpty() || batteries.isNotEmpty() || chargers.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
class SystemDetailViewModel(
|
class SystemDetailViewModel(
|
||||||
|
|||||||
Reference in New Issue
Block a user