원클릭으로
add-tests
Add missing test cases, targeting a specific file or all changed files on the branch
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Add missing test cases, targeting a specific file or all changed files on the branch
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Add a new screen to an existing feature module with Store, UI, factories, and tests
Thorough pre-merge audit — dependency graph, correctness, conventions, security, test coverage, and improvement suggestions
Quick review of the current diff for bugs, logic errors, convention violations, and test gaps
Scaffold a new feature module with the appropriate layers and MESA conventions
Scaffold a new Strata interactor with interface, implementation, fake, and test
Bump library version in VERSION file and prepare release notes
| name | add-tests |
| description | Add missing test cases, targeting a specific file or all changed files on the branch |
| disable-model-invocation | true |
| argument-hint | [@<filepath>] [--unit] [--ui] |
Add test coverage for a specific file or for all testable files changed on the branch. If test files already exist, analyze them for missing test cases and add them. If no test files exist, create them from scratch.
Input: $ARGUMENTS
If a file path is provided: Use that file as the single target.
If no file path is provided: Run git diff main --name-only to get all changed files on the branch. Filter to testable source files (Stores, Interactors, UseCases, Repositories). Exclude test files, build files, and configuration. Process each testable file.
For each target file, read it and understand:
Determine which test types apply:
--unit → Unit tests only--ui → UI tests only (XCTest UI)| Component | Test Type | Location |
|---|---|---|
| Store | Unit | <AppTarget>Tests/ |
| StrataInteractor | Unit | <AppTarget>Tests/ or MESA/Tests/ |
| StrataSubjectInteractor | Unit | <AppTarget>Tests/ or MESA/Tests/ |
| Protocol UseCase | Unit | <AppTarget>Tests/ |
| Repository Impl | Unit | <AppTarget>Tests/ |
| UI Composable | UI | <AppTarget>UITests/ |
Search for existing test files:
{Name}Store.swift → look for {Name}StoreTests.swift{Name}UseCase.swift → look for {Name}UseCaseTests.swift{Name}Ui.swift → look for corresponding UI testsAlso check for existing Fake files in Fakes/ subdirectories.
If test files exist: Read them and compare against the implementation to identify:
If test files do not exist: Create them from scratch following the patterns below.
MESA/Sources/): Swift Testing (@Suite, @Test, #expect)Counter/): XCTest (XCTestCase, XCTAssertEqual)import XCTest
import Trapezio
import TrapezioNavigation
@testable import <AppTarget>
@MainActor
final class <Name>StoreTests: XCTestCase {
var store: <Name>Store!
override func setUp() {
super.setUp()
let screen = <Name>Screen(/* params */)
store = <Name>Store(
screen: screen,
/* inject fakes */
navigator: nil
)
}
func test_<eventName>_<expectedBehavior>() {
store.handle(event: .<eventCase>)
XCTAssertEqual(store.state.<field>, <expectedValue>)
}
func test_<asyncEvent>_updatesState() async throws {
store.handle(event: .<asyncEvent>)
try await Task.sleep(nanoseconds: 10_000_000) // 10ms for strataLaunch
XCTAssertEqual(store.state.<field>, <expectedValue>)
}
}
import Foundation
import Testing
@testable import <Target>
@Suite("<Name>Store")
struct <Name>StoreTests {
@Test("initial state is correct")
@MainActor func initialState() {
let store = <Name>Store(screen: <Name>Screen(), navigator: nil)
#expect(store.state == <Name>State(/* expected */))
}
@Test("<eventName> mutates state correctly")
@MainActor func <eventName>() {
let store = <Name>Store(screen: <Name>Screen(), navigator: nil)
store.handle(event: .<eventCase>)
#expect(store.state.<field> == <expectedValue>)
}
}
import Foundation
import Testing
@testable import <AppTarget>
@Suite("<Name>UseCase")
struct <Name>UseCaseTests {
@Test("executes successfully")
func executeSuccess() async {
let useCase = <Name>UseCase(/* faked dependencies */)
let result = await useCase.execute(params: /* params */)
#expect(result.getOrNull() == /* expected */)
}
@Test("returns failure on error")
func executeFailure() async {
let useCase = <Name>UseCase(/* failing fakes */)
let result = await useCase.execute(params: /* params */)
#expect(result.getOrNull() == nil)
}
}
import XCTest
@testable import Counter
final class <Name>UseCaseTests: XCTestCase {
func test_execute_succeeds() async {
// Given
let useCase = <Name>UseCase(/* dependencies */)
// When
let result = await useCase.execute(params: /* params */)
// Then
XCTAssertEqual(result.getOrNull(), /* expected */)
}
}
@Test("emits values from createObservable")
func basicEmission() async {
let interactor = <Name>UseCase(/* dependencies */)
let task = Task { () -> [T] in
var collected: [T] = []
for await value in interactor.stream {
collected.append(value)
if collected.count >= 1 { break }
}
return collected
}
try? await Task.sleep(nanoseconds: 10_000_000)
interactor(/* params */)
let collected = await task.value
#expect(collected == [/* expected */])
}
When dependencies need faking, create Fake classes in a Fakes/ subdirectory:
stubResult property, sentEvents capture array)@unchecked Sendable where needed for concurrency testsTrapezioTest library utilities when available:
FakeTrapezioNavigator — records all navigation events (goTo, dismiss, popWithResult, etc.) for assertionTestEventSink<E> — records events via callAsFunction, provides .events, .last, .countTrapezioStore.test { state in } — headless state assertion without UITrapezioStore.awaitState(until:validate:) — waits for async state changes before assertingimport Foundation
@testable import <AppTarget>
struct Fake<Dependency>: <DependencyProtocol> {
func execute(<params>) async -> <ReturnType> {
return <stubValue> // No Task.sleep — instant for testing
}
}
import Foundation
import Trapezio
import TrapezioNavigation
@testable import <AppTarget>
class FakeInterop: TrapezioInterop {
var sentEvents: [any TrapezioInteropEvent] = []
func send(_ event: any TrapezioInteropEvent) {
sentEvents.append(event)
}
}
All generated files MUST include the Apache 2.0 license header:
/*
* Copyright 2026 Jason Jamieson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
After generating or updating tests, attempt to compile:
cd MESA && swift test --parallelxcodebuild test -scheme Counter -destination 'platform=iOS Simulator,name=iPhone 16'Fix any compilation issues before finishing.