Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions .agents/commands/pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,24 +125,28 @@ When the user provides custom instructions after `--`:
- Structure QA Notes according to user's specific manual testing instructions and automated coverage notes
- Custom instructions take priority over default generation rules for sections they address
- Preserve exact manual testing steps provided by the user (don't summarize or omit details)
- If custom instructions include automated checks or coverage notes, place them under `#### Automated Checks`
- If custom instructions include automated test coverage notes, place them under `#### Automated Tests`
- If custom instructions include commands that were run or validation checks, place them under `#### Checks`

**QA Notes / Validation:**
- QA Notes separate actionable human QA instructions from automated verification coverage.
- QA Notes separate actionable human QA instructions, automated test coverage, and command-based validation checks.
- Always use this structure:
```md
### QA Notes
#### Manual Tests
#### Automated Checks
#### Automated Tests
#### Checks
```
- Keep local verification commands, Gradle tasks, detekt, lint, unit tests, build passes, cargo test, cargo clippy, npm test, typecheck, CI coverage, or similar automated checks out of `#### Manual Tests`; summarize them under `#### Automated Checks` when they add useful context.
- Use `#### Automated Checks` to summarize automated verification evidence, prioritizing coverage added, modified, or removed with file paths and a short explanation.
- Keep local verification commands, Gradle tasks, detekt, lint, unit tests, build passes, cargo test, cargo clippy, npm test, typecheck, CI coverage, or similar automated checks out of `#### Manual Tests`.
- Use `#### Automated Tests` to summarize automated test coverage added, modified, or removed with the test file name and a short explanation.
- Use `#### Checks` to list raw commands only when they were run locally, are non-standard, use special flags or environment values, validate workflow behavior, or explain a meaningful verification gap.
- When referencing changed test files in QA notes, use the file name only by default, e.g. `SendInvoiceTest.kt`. If multiple changed files share the same file name, use the shortest unique path suffix, e.g. `wallets/send/SendInvoiceTest.kt`.
- For removed automated coverage, state why it was removed.
- Do not list standard CI or PR bot commands as checkbox items just because they run for every PR. If standard CI coverage is worth mentioning, summarize it in one sentence.
- List raw commands only when they were run locally, are non-standard, use special flags or environment values, validate workflow behavior, or explain a meaningful verification gap.
- For workflow behavior validation, include `(after merge)` in the automated check item because workflow changes only take effect for PRs opened after the workflow update merges.
- For workflow behavior validation, include `(after merge)` in the checks item because workflow changes only take effect for PRs opened after the workflow update merges.
- If no actionable manual validation exists, write `N/A` under `#### Manual Tests`.
- If no automated checks were run and no automated coverage changed, write `N/A` under `#### Automated Checks`.
- If no automated test coverage changed, write `N/A` under `#### Automated Tests`.
- If no commands or validation checks are worth listing, write `N/A` under `#### Checks`.
- Write manual tests using this template:
```md
- [ ] **{numbering}.** {optional_condition + →} {screen_action} → {next_screen_action}: expectation
Expand All @@ -157,16 +161,17 @@ When the user provides custom instructions after `--`:
- Use short-form wording like `in-sheet` for sheet screens, `nav` for navigation, `back` for back nav, and `LN` for Lightning Network.

**For library repos (has `bindings/` directory or `Cargo.toml`):**
Structure manual QA around integration validation only. Automated checks belong under `#### Automated Checks`.
Structure manual QA around integration validation only. Automated test coverage belongs under `#### Automated Tests`, and commands belong under `#### Checks`.

Example:
```
### QA Notes
#### Manual Tests
- [ ] **1.** Consumer app → exercise updated binding flow: behavior matches previous release.
- [ ] **2.** `regression:` Android integration screen → trigger changed API path: no crash or stale data.
#### Automated Checks
#### Automated Tests
- Binding tests added: cover updated Android API path in `bindings/android/...`.
#### Checks
- CI: standard cargo and binding checks run by the PR bot.
```

Expand All @@ -183,10 +188,11 @@ Concrete style target:
- [ ] **5a.** Settings → Lightning Connections → tap channel: still opens Channel Detail.
- [ ] **5b.** back: returns to Connections List.
- [ ] **6.** `regression:` Channel Detail → tap Close Connection: works.
#### Automated Checks
- Unit tests added: cover invoice timeout handling in `app/src/test/.../SendInvoiceTest.kt`.
- Unit tests modified: update channel navigation assertions in `app/src/test/.../ChannelDetailTest.kt`.
- Test coverage removed: delete stale mock-only assertions from `app/src/test/.../OldFlowTest.kt` because the flow no longer exists.
#### Automated Tests
- Unit tests added: cover invoice timeout handling in `SendInvoiceTest.kt`.
- Unit tests modified: update channel navigation assertions in `ChannelDetailTest.kt`.
- Test coverage removed: delete stale mock-only assertions from `OldFlowTest.kt` because the flow no longer exists.
#### Checks
- CI: standard compile, unit test, and detekt checks run by the PR bot.
```

Expand Down
60 changes: 60 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,33 @@ val bcp47Locales = listOf(
)
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
val coreServiceIntegrationTestAnnotation = "to.bitkit.test.annotations.CoreServiceIntegrationTest"
val composeUiTestAnnotation = "to.bitkit.test.annotations.ComposeUiTest"
val deviceIntegrationTestAnnotation = "to.bitkit.test.annotations.DeviceIntegrationTest"
val deviceStorageIntegrationTestAnnotation = "to.bitkit.test.annotations.DeviceStorageIntegrationTest"
val deviceUiIntegrationTestAnnotation = "to.bitkit.test.annotations.DeviceUiIntegrationTest"
val requestedTaskNames = gradle.startParameter.taskNames.map { it.substringAfterLast(":") }
val bitkitAndroidTestSuite = providers.gradleProperty("bitkitAndroidTestSuite").orNull
val bitkitAndroidTestAnnotation = when {
requestedTaskNames.any { it == "connectedDevDebugComposeAndroidTest" } -> composeUiTestAnnotation
requestedTaskNames.any { it == "connectedDevDebugCoreServiceIntegrationAndroidTest" } -> {
coreServiceIntegrationTestAnnotation
}
requestedTaskNames.any { it == "connectedDevDebugDeviceStorageIntegrationAndroidTest" } -> {
deviceStorageIntegrationTestAnnotation
}
requestedTaskNames.any { it == "connectedDevDebugDeviceUiIntegrationAndroidTest" } -> {
deviceUiIntegrationTestAnnotation
}
requestedTaskNames.any { it == "connectedDevDebugDeviceIntegrationAndroidTest" } -> deviceIntegrationTestAnnotation
bitkitAndroidTestSuite == "compose" -> composeUiTestAnnotation
bitkitAndroidTestSuite == "core-service" -> coreServiceIntegrationTestAnnotation
bitkitAndroidTestSuite == "device-storage" -> deviceStorageIntegrationTestAnnotation
bitkitAndroidTestSuite == "device-ui" -> deviceUiIntegrationTestAnnotation
bitkitAndroidTestSuite == "integration" -> deviceIntegrationTestAnnotation
bitkitAndroidTestSuite == null -> null
else -> error("Unsupported bitkitAndroidTestSuite '$bitkitAndroidTestSuite'")
}

android {
namespace = "to.bitkit"
Expand All @@ -59,6 +86,9 @@ android {
versionCode = 181
versionName = "2.2.0"
testInstrumentationRunner = "to.bitkit.test.HiltTestRunner"
bitkitAndroidTestAnnotation?.let {
testInstrumentationRunnerArguments["annotation"] = it
}
vectorDrawables {
useSupportLibrary = true
}
Expand Down Expand Up @@ -363,4 +393,34 @@ tasks.withType<Test>().configureEach {
jvmArgs("-XX:+EnableDynamicAgentLoading")
}

tasks.register("connectedDevDebugComposeAndroidTest") {
group = "verification"
description = "Runs devDebug Android tests annotated as Compose UI tests."
dependsOn("connectedDevDebugAndroidTest")
}

tasks.register("connectedDevDebugDeviceIntegrationAndroidTest") {
group = "verification"
description = "Runs devDebug Android tests annotated as device integration tests."
dependsOn("connectedDevDebugAndroidTest")
}

tasks.register("connectedDevDebugCoreServiceIntegrationAndroidTest") {
group = "verification"
description = "Runs devDebug Android tests annotated as core service integration tests."
dependsOn("connectedDevDebugAndroidTest")
}

tasks.register("connectedDevDebugDeviceStorageIntegrationAndroidTest") {
group = "verification"
description = "Runs devDebug Android tests annotated as device storage integration tests."
dependsOn("connectedDevDebugAndroidTest")
}

tasks.register("connectedDevDebugDeviceUiIntegrationAndroidTest") {
group = "verification"
description = "Runs devDebug Android tests annotated as device UI integration tests."
dependsOn("connectedDevDebugAndroidTest")
}

// endregion
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import to.bitkit.test.annotations.DeviceStorageIntegrationTest
import to.bitkit.test.annotations.DeviceIntegrationTest
import to.bitkit.data.AppDb
import to.bitkit.data.entities.ConfigEntity
import to.bitkit.test.BaseAndroidTest
Expand All @@ -20,6 +22,8 @@ import kotlin.test.assertNull
import kotlin.test.assertTrue

@RunWith(AndroidJUnit4::class)
@DeviceIntegrationTest
@DeviceStorageIntegrationTest
class KeychainTest : BaseAndroidTest() {

private val appContext by lazy { ApplicationProvider.getApplicationContext<Context>() }
Expand Down
4 changes: 4 additions & 0 deletions app/src/androidTest/java/to/bitkit/services/BlocktankTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import to.bitkit.test.annotations.CoreServiceIntegrationTest
import to.bitkit.test.annotations.DeviceIntegrationTest
import to.bitkit.env.Env
import javax.inject.Inject
import kotlin.test.assertEquals
Expand All @@ -22,6 +24,8 @@ import kotlin.test.assertNotNull
import kotlin.test.assertTrue

@HiltAndroidTest
@DeviceIntegrationTest
@CoreServiceIntegrationTest
class BlocktankTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.lightningdevkit.ldknode.Network
import to.bitkit.test.annotations.CoreServiceIntegrationTest
import to.bitkit.test.annotations.DeviceIntegrationTest
import to.bitkit.models.toDerivationPath
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

@RunWith(AndroidJUnit4::class)
@DeviceIntegrationTest
@CoreServiceIntegrationTest
class OnchainServiceTests {
private lateinit var onchainService: OnchainService

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.lightningdevkit.ldknode.Bolt11Invoice
import org.lightningdevkit.ldknode.NodeException
import to.bitkit.test.annotations.CoreServiceIntegrationTest
import to.bitkit.test.annotations.DeviceIntegrationTest
import to.bitkit.data.CacheStore
import to.bitkit.data.keychain.Keychain
import to.bitkit.env.Env
Expand All @@ -27,6 +29,8 @@ import kotlin.test.assertTrue

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
@DeviceIntegrationTest
@CoreServiceIntegrationTest
class RoutingFeeEstimationTest {

companion object {
Expand Down
4 changes: 4 additions & 0 deletions app/src/androidTest/java/to/bitkit/services/TxBumpingTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import to.bitkit.test.annotations.CoreServiceIntegrationTest
import to.bitkit.test.annotations.DeviceIntegrationTest
import to.bitkit.data.keychain.Keychain
import to.bitkit.env.Env
import to.bitkit.repositories.WalletRepo
Expand All @@ -23,6 +25,8 @@ import kotlin.test.assertTrue

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
@DeviceIntegrationTest
@CoreServiceIntegrationTest
class TxBumpingTests {

@get:Rule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.lightningdevkit.ldknode.CoinSelectionAlgorithm
import to.bitkit.test.annotations.CoreServiceIntegrationTest
import to.bitkit.test.annotations.DeviceIntegrationTest
import to.bitkit.data.keychain.Keychain
import to.bitkit.env.Env
import to.bitkit.repositories.WalletRepo
Expand All @@ -25,6 +27,8 @@ import kotlin.test.fail

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
@DeviceIntegrationTest
@CoreServiceIntegrationTest
class UtxoSelectionTests {

@get:Rule
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package to.bitkit.test.annotations

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class ComposeUiTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package to.bitkit.test.annotations

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class CoreServiceIntegrationTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package to.bitkit.test.annotations

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class DeviceIntegrationTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package to.bitkit.test.annotations

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class DeviceStorageIntegrationTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package to.bitkit.test.annotations

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class DeviceUiIntegrationTest
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import org.junit.Rule
import org.junit.Test
import to.bitkit.test.annotations.ComposeUiTest
import to.bitkit.models.NodeLifecycleState
import to.bitkit.viewmodels.SendMethod
import to.bitkit.viewmodels.SendUiState
import to.bitkit.viewmodels.previewAmountInputViewModel

@ComposeUiTest
class SendAmountContentTest {

@get:Rule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import org.junit.Rule
import org.junit.Test
import to.bitkit.test.annotations.ComposeUiTest
import to.bitkit.ui.theme.AppThemeSurface

@ComposeUiTest
class BlockCardTest {

@get:Rule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import org.junit.Rule
import org.junit.Test
import to.bitkit.test.annotations.ComposeUiTest
import to.bitkit.models.widget.BlockModel
import to.bitkit.models.widget.BlocksPreferences
import to.bitkit.ui.theme.AppThemeSurface

@ComposeUiTest
class BlocksEditScreenTest {

@get:Rule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import org.junit.Rule
import org.junit.Test
import to.bitkit.test.annotations.ComposeUiTest
import to.bitkit.models.widget.BlockModel
import to.bitkit.models.widget.BlocksPreferences
import to.bitkit.ui.theme.AppThemeSurface

@ComposeUiTest
class BlocksPreviewContentTest {

@get:Rule
Expand Down
Loading
Loading