reis-mobile 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -2
- package/CHANGELOG.md +33 -0
- package/README.md +52 -19
- package/agents/android-architect.md +14 -70
- package/agents/android-performance-engineer.md +14 -73
- package/agents/android-test-engineer.md +23 -76
- package/agents/flutter-architect.md +17 -73
- package/agents/flutter-performance-engineer.md +14 -83
- package/agents/flutter-test-engineer.md +18 -82
- package/agents/ios-architect.md +14 -74
- package/agents/ios-performance-engineer.md +14 -73
- package/agents/ios-test-engineer.md +18 -75
- package/agents/lead-mobile.md +40 -67
- package/agents/mobile-accessibility-auditor.md +31 -0
- package/agents/mobile-code-reviewer.md +19 -48
- package/agents/mobile-release-engineer.md +33 -0
- package/agents/mobile-staff-engineer.md +19 -66
- package/agents/plugin-native-expert.md +14 -78
- package/agents/rn-architect.md +13 -76
- package/agents/rn-performance-engineer.md +14 -74
- package/agents/rn-test-engineer.md +16 -77
- package/bin/reis-mobile.mjs +30 -5
- package/commands/reis-mobile.md +7 -2
- package/commands/test.md +71 -0
- package/core/install/claude-plugin.mjs +9 -2
- package/docs/agent-context.md +57 -0
- package/package.json +2 -1
- package/skills/mobile-accessibility/SKILL.md +69 -0
- package/skills/mobile-accessibility/references/android.md +54 -0
- package/skills/mobile-accessibility/references/flutter.md +59 -0
- package/skills/mobile-accessibility/references/ios.md +50 -0
- package/skills/mobile-accessibility/references/react-native.md +38 -0
- package/skills/mobile-debug/SKILL.md +2 -1
- package/skills/mobile-debug/references/android/anr.md +59 -0
- package/skills/mobile-debug/references/android/memory-leaks.md +43 -0
- package/skills/mobile-debug/references/android.md +6 -0
- package/skills/mobile-debug/references/deep-links.md +60 -0
- package/skills/mobile-release/SKILL.md +70 -0
- package/skills/mobile-release/references/android.md +47 -0
- package/skills/mobile-release/references/ci-cd.md +94 -0
- package/skills/mobile-release/references/flutter.md +37 -0
- package/skills/mobile-release/references/ios.md +48 -0
- package/skills/mobile-release/references/react-native.md +36 -0
- package/skills/mobile-release/references/store-copy.md +52 -0
- package/skills/mobile-test/SKILL.md +21 -6
- package/skills/mobile-test/references/android.md +67 -55
- package/skills/mobile-test/references/ios.md +76 -53
|
@@ -1,79 +1,102 @@
|
|
|
1
1
|
# Testing native iOS apps
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use this reference for Swift/Objective-C tests and native iOS modules inside Flutter or React Native apps. Keep XCTest, Swift Testing and XCUITest in the roles already established by the target.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- Test targets, test plans and schemes in the Xcode project, or test targets in `Package.swift`.
|
|
7
|
-
- Whether unit tests run inside a host app (the app target launches) or as a logic test bundle.
|
|
8
|
-
- Existing doubles and fixtures; snapshot testing only if the project already has a library for it.
|
|
5
|
+
## Resolve the container, target and destination
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
1. Find the owning `.xcworkspace`, `.xcodeproj` or `Package.swift`, and read CI's test invocation. Use the app's workspace when that is how its dependencies are integrated; do not select a dependency's internal project/workspace.
|
|
8
|
+
2. Inspect the scheme's Test action and `.xctestplan` files. Identify the unit/UI test target, test host, source membership, exclusions and configurations. A new file outside the test target or a target excluded by the plan contributes no tests.
|
|
9
|
+
3. Inspect `import XCTest` / `XCTestCase` versus `import Testing` / `@Test`, the toolchain version and existing helpers. Preserve the framework used by the nearest tests. Swift Testing is available with Xcode 16 and later; it can coexist with XCTest in a test target. See [adding tests to Xcode projects](https://developer.apple.com/documentation/xcode/adding-tests-to-your-xcode-project).
|
|
10
|
+
4. Map the real source symbol to its protocol dependencies, actor isolation, input and observable result. Read the existing fixture builders rather than inventing application entities.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
import Testing
|
|
14
|
-
@testable import App
|
|
12
|
+
These are command templates: replace every `<...>` from repository or tool output. Use `-project '<path>.xcodeproj'` instead of `-workspace '<path>.xcworkspace'` throughout when the project has no relevant workspace.
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
```bash
|
|
15
|
+
xcodebuild -list -workspace '<workspace-path>.xcworkspace'
|
|
16
|
+
xcodebuild -workspace '<workspace-path>.xcworkspace' -scheme '<scheme>' -showTestPlans
|
|
17
|
+
xcodebuild -workspace '<workspace-path>.xcworkspace' -scheme '<scheme>' -showdestinations
|
|
18
|
+
xcrun simctl list devices available
|
|
19
|
+
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Choose a compatible destination listed for that scheme, using its simulator ID to avoid ambiguous device names. A listed simulator may still need to boot. Preserve the project's destination policy and avoid selecting a physical device implicitly. If there is no compatible runtime, record the blocker. See [Xcode command-line discovery](https://developer.apple.com/library/archive/technotes/tn2339/_index.html) and [test plans](https://developer.apple.com/documentation/xcode/organizing-tests-to-improve-feedback).
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
## XCTest: choose the async mechanism that matches the subject
|
|
24
|
+
|
|
25
|
+
- Synchronous function: invoke it and assert its returned value or observable state with `XCTAssert...`; use `try XCTUnwrap` for values required by subsequent steps.
|
|
26
|
+
- `async` function: use a `test...` method marked `async` or `async throws`, await the operation, then assert. Apply `@MainActor` when the subject requires it; do not add an unawaited `Task` inside a synchronous test.
|
|
27
|
+
- Callback, delegate or publisher: create an expectation before triggering work, assert the callback's result, fulfill it, and wait for completion. For an async XCTest method use `await fulfillment(of:timeout:)` when supported by the project's toolchain; a synchronous method can use `wait(for:timeout:)`. Avoid a blocking wait inside an async test.
|
|
28
|
+
- If the method only starts background work, awaiting that method alone may not prove completion. Observe the completion callback/state transition rather than immediately asserting a value that races.
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
See [asynchronous XCTest tests](https://developer.apple.com/documentation/xctest/asynchronous-tests-and-expectations) and [async expectation fulfillment](https://developer.apple.com/documentation/xctest/xctestcase/fulfillment%28of%3Atimeout%3Aenforceorder%3A%29).
|
|
31
|
+
|
|
32
|
+
The following method illustrates a callback test. `repository`, `cachedOrder` and `loadCachedOrder` stand for an inspected project fixture and API, not generated application types. Arrange an isolated repository fixture that contains the expected order before invoking it:
|
|
33
|
+
|
|
34
|
+
```swift
|
|
35
|
+
func testLoadsPreviouslySavedOrder() async {
|
|
36
|
+
let loaded = expectation(description: "Cached order is delivered")
|
|
37
|
+
|
|
38
|
+
repository.loadCachedOrder { result in
|
|
39
|
+
switch result {
|
|
40
|
+
case .success(let order):
|
|
41
|
+
XCTAssertEqual(order, cachedOrder)
|
|
42
|
+
case .failure(let error):
|
|
43
|
+
XCTFail("Expected the saved order, received \(error)")
|
|
44
|
+
}
|
|
45
|
+
loaded.fulfill()
|
|
29
46
|
}
|
|
47
|
+
|
|
48
|
+
await fulfillment(of: [loaded], timeout: 1.0)
|
|
30
49
|
}
|
|
31
50
|
```
|
|
32
51
|
|
|
33
|
-
|
|
34
|
-
- `#expect(throws: SomeError.self) { try parser.parse(data) }` checks thrown errors.
|
|
35
|
-
- Parameterized tests (`arguments:`) replace copy-pasted test methods.
|
|
36
|
-
- Suites are plain types; setup goes in `init`, teardown in `deinit`.
|
|
52
|
+
Choose a bounded timeout appropriate to the isolated operation. Keep captured values compatible with the API's actor/Sendable requirements. Fulfill on both success and failure so assertion failures do not become unexplained timeouts; clean subscriptions and tasks during teardown.
|
|
37
53
|
|
|
38
|
-
##
|
|
54
|
+
## Swift Testing and dependency isolation
|
|
39
55
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
func testEmitsSuccessWhenCredentialsAreValid() async {
|
|
44
|
-
let viewModel = LoginViewModel(authService: FakeAuthService(result: .success(.fixture)))
|
|
56
|
+
- Follow the target's current `@Test`, `#expect` and `#require` conventions. Parameterize genuinely identical behavior with different inputs instead of duplicating bodies. Preserve the suite's isolation and parallelization assumptions; do not migrate XCTest UI tests to Swift Testing.
|
|
57
|
+
- Inject the app's existing protocol-based services, clock and persistence boundary. When testing URL loading, a custom `URLProtocol` belongs on an isolated `URLSessionConfiguration`, with a deterministic handler scoped to that test.
|
|
58
|
+
- Use a dedicated `UserDefaults` suite or temporary persistence store with cleanup. Keep real Keychain/network access out of unit tests unless those integrations are explicitly the subject and have an isolated test setup. Reset fixtures in setup/teardown; avoid global state shared by parallel tests.
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
## XCUITest: launch state, interaction, observable result
|
|
47
61
|
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
```
|
|
62
|
+
Use the UI test target with `XCTestCase` and `XCUIApplication`. It runs separately from the app, so an in-process fake in the test does not replace the app's services. Reuse launch arguments/environment that the app actually reads to select a deterministic fixture; do not invent flags such as `--uitesting` and assume they work.
|
|
52
63
|
|
|
53
|
-
|
|
54
|
-
- Methods must start with `test`; `setUp`/`tearDown` (or their `async throws` variants) reset state.
|
|
64
|
+
Locate elements through identifiers found in SwiftUI's `.accessibilityIdentifier(...)` or UIKit's `accessibilityIdentifier`. Wait for the relevant state using `waitForExistence(timeout:)` rather than sleeping. Element existence alone does not guarantee it is enabled or hittable; inspect those states when the action requires them. See [XCUIElement](https://developer.apple.com/documentation/xcuiautomation/xcuielement).
|
|
55
65
|
|
|
56
|
-
|
|
66
|
+
Illustrative method: replace the identifiers and expected error with the inspected screen's values. This scenario assumes an empty form is submitted and the app shows a required-field error:
|
|
57
67
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
```swift
|
|
69
|
+
func testSubmittingEmptyFormShowsRequiredEmailError() {
|
|
70
|
+
let app = XCUIApplication()
|
|
71
|
+
app.launch()
|
|
72
|
+
defer { app.terminate() }
|
|
73
|
+
|
|
74
|
+
let submit = app.buttons["signIn.submit"]
|
|
75
|
+
XCTAssertTrue(submit.waitForExistence(timeout: 5))
|
|
76
|
+
XCTAssertTrue(submit.isEnabled)
|
|
77
|
+
XCTAssertTrue(submit.isHittable)
|
|
78
|
+
submit.tap()
|
|
79
|
+
|
|
80
|
+
let error = app.staticTexts["signIn.emailError"]
|
|
81
|
+
XCTAssertTrue(error.waitForExistence(timeout: 5))
|
|
82
|
+
XCTAssertEqual(error.label, "Email is required")
|
|
83
|
+
}
|
|
84
|
+
```
|
|
62
85
|
|
|
63
|
-
|
|
86
|
+
Set the app's existing fixture arguments/environment before `launch()` when needed to reach a fresh form. The post-tap assertion proves the behavior; a launch-only smoke test does not. For network-driven flows, make the app consume a controlled response and assert the resulting screen/state.
|
|
64
87
|
|
|
65
|
-
|
|
66
|
-
- Launch into a known state with `app.launchArguments` / `app.launchEnvironment` read by the app (for example to use fake services or skip onboarding).
|
|
67
|
-
- Wait with `waitForExistence(timeout:)` on the element, never with `sleep`.
|
|
68
|
-
- Keep UI tests to critical flows; they are slow and the first to go flaky.
|
|
88
|
+
## Run the selected tests and inspect the result
|
|
69
89
|
|
|
70
|
-
|
|
90
|
+
Use actual names found above. The `-only-testing` identifier uses the test target name, then the XCTest class and optionally method. Select a plan only when the scheme has that plan; omit `-testPlan` for schemes without one:
|
|
71
91
|
|
|
72
92
|
```bash
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
swift test # Swift packages
|
|
93
|
+
xcodebuild test -workspace '<workspace-path>.xcworkspace' \
|
|
94
|
+
-scheme '<scheme>' -testPlan '<test-plan>' \
|
|
95
|
+
-destination 'platform=iOS Simulator,id=<simulator-id>' \
|
|
96
|
+
'-only-testing:<test-target>/<test-class>' \
|
|
97
|
+
-resultBundlePath '<new-result-path>.xcresult'
|
|
79
98
|
```
|
|
99
|
+
|
|
100
|
+
Use a new result-bundle path per run, then inspect executed tests, failures and skips. A successful build or zero matching tests is not a passing suite. Preserve the `.xcresult` path in the report. For coverage, add `-enableCodeCoverage YES` when requested and inspect the bundle with `xcrun xccov view --report '<result-path>.xcresult'`; verify command support with the installed Xcode. See [running tests and interpreting results](https://developer.apple.com/documentation/xcode/running-tests-and-interpreting-results).
|
|
101
|
+
|
|
102
|
+
For a Swift package whose tests support the host platform, run `swift test` from the package directory, using its supported filter when narrowing scope. iOS-only package tests still need the app/Xcode scheme and compatible simulator; `swift test` on macOS does not supply an iOS runtime.
|