oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

1import XCTest
2
3@MainActor final class NativeUITests: XCTestCase {
4 func testCreateAndEditFormula() {
5 continueAfterFailure = false
6 let app = XCUIApplication()
7 app.launch()
8 defer { app.terminate() }
9 let create = app.buttons["New spreadsheet"]
10 XCTAssertTrue(create.waitForExistence(timeout: 15))
11 create.tap()
12 let formula = app.textFields["Cell contents or formula"]
13 XCTAssertTrue(formula.waitForExistence(timeout: 10), "Creating a sheet must navigate to its native editor")
14 formula.tap()
15 formula.typeText("=2+3")
16 app.buttons["Save"].tap()
17 XCTAssertTrue(app.buttons["A1, 5"].waitForExistence(timeout: 10), "The server-calculated value must appear")
18 let saved = NSPredicate(format: "exists == false")
19 XCTAssertEqual(XCTWaiter.wait(for: [XCTNSPredicateExpectation(predicate: saved, object: app.buttons["Save"])], timeout: 5), .completed)
20 app.buttons["A1, 5"].tap()
21 let rawFormula = NSPredicate(format: "value == %@", "=2+3")
22 XCTAssertEqual(XCTWaiter.wait(for: [XCTNSPredicateExpectation(predicate: rawFormula, object: formula)], timeout: 5), .completed, "Selecting a cell must expose its formula rather than its display value")
23 formula.coordinate(withNormalizedOffset: CGVector(dx: 0.95, dy: 0.5)).tap()
24 formula.typeText(String(repeating: XCUIKeyboardKey.delete.rawValue, count: 4))
25 formula.typeText("=7*6")
26 app.buttons["Save"].tap()
27 XCTAssertTrue(app.buttons["A1, 42"].waitForExistence(timeout: 10))
28 XCTAssertEqual(XCTWaiter.wait(for: [XCTNSPredicateExpectation(predicate: saved, object: app.buttons["Save"])], timeout: 5), .completed)
29 app.buttons["A1, 42"].tap()
30 let finalFormula = NSPredicate(format: "value == %@", "=7*6")
31 XCTAssertEqual(XCTWaiter.wait(for: [XCTNSPredicateExpectation(predicate: finalFormula, object: formula)], timeout: 5), .completed)
32
33 // Exercise commands through the actual native menus, preserving A1 as the
34 // fixture's independent server-persistence sentinel.
35 menu(app, "Edit", command: "Fill down")
36 XCTAssertTrue(app.buttons["A2, 42"].waitForExistence(timeout: 10))
37 select(app, "A1:A2")
38 menu(app, "Edit", command: "Copy")
39 select(app, "B1")
40 menu(app, "Edit", command: "Paste")
41 XCTAssertTrue(app.buttons["B1, 42"].waitForExistence(timeout: 10))
42 XCTAssertTrue(app.buttons["B2, 42"].waitForExistence(timeout: 10))
43 select(app, "B1:B2")
44 openMenu(app, "Format")
45 app.buttons["Number format"].tap()
46 app.buttons["Number"].tap()
47 XCTAssertTrue(app.buttons["B1, 42.00"].waitForExistence(timeout: 10))
48 XCTAssertTrue(app.buttons["B2, 42.00"].waitForExistence(timeout: 10))
49 menu(app, "Edit", command: "Undo my last value edit")
50 XCTAssertTrue(app.buttons["B2, Empty"].waitForExistence(timeout: 10))
51 select(app, "B2")
52 XCTAssertEqual(XCTWaiter.wait(for: [XCTNSPredicateExpectation(predicate: NSPredicate(format: "value == %@ OR value == %@", "", "Cell contents or formula"), object: formula)], timeout: 10), .completed)
53 menu(app, "File", command: "Version history")
54 let restore = app.buttons["Restore before this edit"].firstMatch
55 XCTAssertTrue(restore.waitForExistence(timeout: 10))
56 restore.tap()
57 app.buttons["Done"].tap()
58 // Canonical value undo clears the sparse cell row, including its format;
59 // restoring the input therefore returns the default number display.
60 XCTAssertTrue(app.buttons["B2, 42"].waitForExistence(timeout: 10), "History Restore must restore the pasted formula")
61 select(app, "A1")
62 let screenshot = XCTAttachment(screenshot: app.screenshot())
63 screenshot.name = "Sheets native formula editing"
64 screenshot.lifetime = .keepAlways
65 add(screenshot)
66 }
67
68 private func select(_ app: XCUIApplication, _ reference: String) {
69 let field = app.textFields["Cell or range, for example A1:B5"]
70 XCTAssertTrue(field.waitForExistence(timeout: 5))
71 field.coordinate(withNormalizedOffset: CGVector(dx: 0.95, dy: 0.5)).tap()
72 field.typeText(String(repeating: XCUIKeyboardKey.delete.rawValue, count: (field.value as? String ?? "").count))
73 field.typeText(reference + "\n")
74 }
75
76 func testFailedCellEditCanBeRetriedWithoutLosingDraft() {
77 continueAfterFailure = false
78 let app = XCUIApplication()
79 app.launch()
80 defer { app.terminate() }
81 XCTAssertTrue(app.buttons["New spreadsheet"].waitForExistence(timeout: 15))
82 app.buttons["New spreadsheet"].tap()
83 let formula = app.textFields["Cell contents or formula"]
84 XCTAssertTrue(formula.waitForExistence(timeout: 10))
85 formula.tap()
86 // Only this exact synthetic input triggers one refusal in the fixture.
87 formula.typeText("=6*7")
88 app.buttons["Save"].tap()
89 let retry = app.buttons["Retry pending edits"]
90 XCTAssertTrue(retry.waitForExistence(timeout: 10))
91 XCTAssertEqual(formula.value as? String, "=6*7")
92 XCTAssertFalse(formula.isEnabled)
93 app.buttons["A2, Empty"].tap()
94 XCTAssertEqual(app.textFields["Cell or range, for example A1:B5"].value as? String, "A1")
95 retry.tap()
96 XCTAssertTrue(app.buttons["A1, 42"].waitForExistence(timeout: 10))
97 XCTAssertEqual(XCTWaiter.wait(for: [XCTNSPredicateExpectation(predicate: NSPredicate(format: "exists == false"), object: retry)], timeout: 10), .completed)
98 let screenshot = XCTAttachment(screenshot: app.screenshot())
99 screenshot.name = "Sheets native retried edit"; screenshot.lifetime = .keepAlways; add(screenshot)
100 }
101
102 func testExportWorkbookOpensNativeDestinationAndCancels() {
103 continueAfterFailure = false
104 let app = XCUIApplication()
105 app.launch()
106 defer { app.terminate() }
107 let workbook = app.buttons["Native review workbook"]
108 XCTAssertTrue(workbook.waitForExistence(timeout: 15))
109 workbook.tap()
110 XCTAssertTrue(app.textFields["Cell contents or formula"].waitForExistence(timeout: 10))
111 menu(app, "File", command: "Export workbook")
112 let export = app.buttons["Save workbook…"]
113 XCTAssertTrue(export.waitForExistence(timeout: 10))
114 export.tap()
115 let cancel = app.buttons["Cancel"]
116 XCTAssertTrue(cancel.waitForExistence(timeout: 15), "A native file destination picker must open after download")
117 let screenshot = XCTAttachment(screenshot: app.screenshot())
118 screenshot.name = "Sheets native export destination"
119 screenshot.lifetime = .keepAlways
120 add(screenshot)
121 cancel.tap()
122 XCTAssertTrue(export.waitForExistence(timeout: 10))
123 app.buttons["Done"].tap()
124 }
125
126 private func openMenu(_ app: XCUIApplication, _ name: String) {
127 if app.buttons["Sheet actions"].exists { app.buttons["Sheet actions"].tap() }
128 let menu = app.buttons[name]
129 XCTAssertTrue(menu.waitForExistence(timeout: 5), "Missing native menu: \(name)")
130 menu.tap()
131 }
132
133 private func menu(_ app: XCUIApplication, _ name: String, command: String) {
134 openMenu(app, name)
135 let action = app.buttons[command]
136 XCTAssertTrue(action.waitForExistence(timeout: 5), "Missing native command: \(command)")
137 action.tap()
138 }
139}
140