Nice and simple DSL for Espresso Compose UI testing in Kotlin

Overview

Kakao Compose

Kotlin version badge Telegram Telegram

Nice and simple DSL for Espresso Compose in Kotlin

coco

Benefits

  • Readability
  • Reusability
  • Extensible DSL

How to use it

Create Screen

Create your entity ComposeScreen where you will add the views involved in the interactions of the tests:

class MainActivityScreen(composeTestRule: AndroidComposeTestRule<*, *>):
      ComposeScreen<MainActivityScreen>(composeTestRule)

ComposeScreen can represent the whole user interface or a portion of UI. If you are using Page Object pattern you can put the interactions of Kakao inside the Page Objects.

Create KNode

ComposeScreen contains KNode, these are the Android Framework views where you want to do the interactions:

class MainActivityScreen(composeTestRule: AndroidComposeTestRule<*, *>) :
    ComposeScreen<MainActivityScreen>(composeTestRule) {
    val myButton = KNode(this) {
        hasTestTag("myTestButton")
    }
}

Every KNode contains many matches. Some examples of matchers provided by Kakao Compose:

  • hasText
  • hasTestTag
  • and more

Like in Espresso you can combine different matchers:

val myButton = KNode(this) {
      hasTestTag("myTestButton")
      hasText("Button 1")
 }

Write the interaction.

The syntax of the test with Kakao is very easy, once you have the ComposeScreen and the KNode defined, you only have to apply the actions or assertions like in Espresso:

class ExampleInstrumentedTest {
    @Rule
    @JvmField
    val composeTestRule = createAndroidComposeRule<MainActivity>()

    @Test
    fun simpleTest() {
        onComposeScreen<MainActivityScreen>(composeTestRule) {
            myButton {
                assertIsDisplayed()
                assertTextContains("Button 1")
            }

            onNode {
                hasTestTag("doesNotExist")
            }.invoke {
                assertDoesNotExist()
            }
        }
    }
}

Setup

Maven

<dependency>
  <groupId>io.github.kakaocup</groupId>
  <artifactId>compose</artifactId>
  <version><latest version></version>
  <type>pom</type>
</dependency>

or Gradle:

dependencies {
    androidTestImplementation 'io.github.kakaocup:compose:<latest version>'
}

Contribution Policy

Kakao Compose is an open source project, and depends on its users to improve it. We are more than happy to find you interested in taking the project forward.

Kindly refer to the Contribution Guidelines for detailed information.

Code of Conduct

Please refer to Code of Conduct document.

License

Kakao Compose is open source and available under the Apache License, Version 2.0.

Comments
  • Modify ViewBuilder node collection to take into account nested children and useUnmergedTree param

    Modify ViewBuilder node collection to take into account nested children and useUnmergedTree param

    Resolves #14

    This PR includes support for useUnmergedTree over the nodes inside the ComposeTestRule. I have made some minor changes over the constructors of KNode, and ViewBuilder to include this parameter. However the current implementation using composeTestRule.onRoot(useUnmergedTree).onChildren() was only returning the children of the root and not the nested ones. No matter if useUnmergedTree was used or not.

    I think that the onChildren() method from Compose should take this into account but it's not doing it. The fix I have included makes use of the onAllNodes() method with a custom SemanticMatcher that takes any node inside it. I have looked into the onChildren() implementation together with how the framework looks for the children on the nodes, but I have not found a better solution. If you find other way to do it, please let me know or suggest a change on the PR!

    Thank you so much!

    opened by FrangSierra 6
  • Deprecated `performGesture` and added `performTouchInput`

    Deprecated `performGesture` and added `performTouchInput`

    I've added a new node action, performTouchInput, similar to other actions, and deprecated performGesture. Also, I've added 2 tests for the both actions, just in case.

    Unfortunately, I ran into issues trying to run tests and ensure that everything works, so I did some changes locally to run them. Please try running tests yourself before merging. I can fire up another PR with the fixes for the build.

    Closes #35

    opened by fobo66 3
  • Problems with matching child nodes for the Compose Screen

    Problems with matching child nodes for the Compose Screen

    Hi, I have a problem with matching child nodes for the ComposeScreen. It works in simple cases but for the current screen it won’t work:

    fun SimpleScreen() {
       Scaffold(Modifier.testTag(TestTag.SimpleScreen.Tag)) {
           Card {
               Text(
                   "TestTitle",
                   Modifier
                       .padding(16.dp)
                       .testTag(TestTag.SimpleScreen.Title)
               )
           }
       }
    }
    

    The following PageObject can’t find our title at this screen:

    class KSimpleScreen(semanticsProvider: SemanticsNodeInteractionsProvider) : ComposeScreen<KSimpleScreen>(
       semanticsProvider = semanticsProvider,
       viewBuilderAction = { hasTestTag(TestTag.SimpleScreen.Tag) }
    ) {
       val title: KNode = child {
           hasTestTag(TestTag.SimpleScreen.Title)
       }
    }
    

    It can be fixed by deleting child and using hasAnyAncestor matcher:

    val title: KNode = KNode(semanticsProvider) {
       hasAnyAncestor((androidx.compose.ui.test.hasTestTag(TestTag.SimpleScreen.Tag)))
       hasTestTag(TestTag.SimpleScreen.Title)
    }
    

    But it’s not convenient and it would be great if BaseNode had this matcher by default for the parent node or allowed to change this behavior.

    opened by AJIEKCX 3
  • Failed to perform isDisplayed check

    Failed to perform isDisplayed check

    Thanks for releasing this feature, I have been experimenting with Kakao and have successfully used it for Espresso and Espresso web views, and now I'm testing the Compose views. The app I'm testing contains all these components.

    The problem I'm having is that I cannot get a testTag to match, even though it works fine with raw Compose [ like this: composeTestRule.onNode(androidx.compose.ui.test.hasTestTag(“MyStatusArea")).assertIsDisplayed() ]

    I was hoping that you might spot some issue in my tree log. I'm a newbie to Compose, but have been successful in using the raw Compose functions.

    Kind Regards,

    Pentti

    This is the Exception I get when using Kakao Compose:

    java.lang.AssertionError: Failed to perform isDisplayed check. Can't retrieve node at index '0' of '((isRoot).children).filter(TestTag = 'MyStatusArea')' There are no existing nodes for that selector.

    at androidx.compose.ui.test.SemanticsNodeInteraction.fetchOneOrDie(SemanticsNodeInteraction.kt:169) at androidx.compose.ui.test.SemanticsNodeInteraction.fetchSemanticsNode(SemanticsNodeInteraction.kt:106) at androidx.compose.ui.test.AndroidAssertions_androidKt.checkIsDisplayed(AndroidAssertions.android.kt:29) at androidx.compose.ui.test.AssertionsKt.assertIsDisplayed(Assertions.kt:33) at io.github.kakaocup.compose.node.NodeAssertions$DefaultImpls.assertIsDisplayed(NodeAssertions.kt:11) at io.github.kakaocup.compose.node.KNode.assertIsDisplayed(KNode.kt:7)

    I've followed the sample and have this in my page object:

    val statusArea = KNode(this) { hasTestTag(“MyStatusArea") }

    And my test scenario contains:

    onComposeScreen(composeTestRule) { statusArea { assertIsDisplayed() } }

    I've logged the tree using this command:

    composeTestRule.onRoot(useUnmergedTree = true).printToLog("COMPOSE_LOG")

    10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: printToLog: 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: Printing with useUnmergedTree = 'true' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: Node #1 at (l=0.0, t=171.0, r=1080.0, b=2148.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: |-Node #2 at (l=0.0, t=171.0, r=1080.0, b=2148.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: VerticalScrollAxisRange = 'androidx.compose.ui.semantics.ScrollAxisRange@db65b2a' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: Actions = [ScrollBy] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: |-Node #3 at (l=0.0, t=699.0, r=1080.0, b=699.0)px, Tag: 'MyCircleProgress' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: |-Node #4 at (l=342.0, t=501.0, r=738.0, b=897.0)px, Tag: 'MyButton' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Role = 'Button' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | [Disabled] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Actions = [OnClick] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | MergeDescendants = 'true' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | |-Node #6 at (l=447.0, t=626.0, r=633.0, b=685.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Text = ‘[Waiting]’ 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Actions = [GetTextLayoutResult] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | |-Node #8 at (l=471.0, t=685.0, r=610.0, b=773.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Text = '[1.9%]' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Actions = [GetTextLayoutResult] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | |-Node #1000000004 at (l=0.0, t=0.0, r=0.0, b=0.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Role = 'Button' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: |-Node #10 at (l=427.0, t=985.0, r=654.0, b=1084.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Role = 'Button' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Actions = [OnClick] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | MergeDescendants = 'true' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | |-Node #11 at (l=471.0, t=1009.0, r=610.0, b=1061.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Text = '[Cancel]' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Actions = [GetTextLayoutResult] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | |-Node #1000000010 at (l=0.0, t=0.0, r=0.0, b=0.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Role = 'Button' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: |-Node #13 at (l=0.0, t=1128.0, r=1080.0, b=1386.0)px, Tag: 'MyStatusArea' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | |-Node #14 at (l=0.0, t=1128.0, r=540.0, b=1386.0)px, Tag: 'MyStatsNumberWithTitleBox' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | |-Node #15 at (l=254.0, t=1172.0, r=287.0, b=1246.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | | Text = '[4]' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | | Actions = [GetTextLayoutResult] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | |-Node #17 at (l=151.0, t=1290.0, r=389.0, b=1342.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Text = '[Files checked]' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Actions = [GetTextLayoutResult] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | |-Node #19 at (l=540.0, t=1128.0, r=1080.0, b=1386.0)px, Tag: 'MyStatsNumberWithTitleBox' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | |-Node #20 at (l=794.0, t=1172.0, r=827.0, b=1246.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Text = '[0]' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | | Actions = [GetTextLayoutResult] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | |-Node #22 at (l=687.0, t=1290.0, r=933.0, b=1342.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Text = '[Apps checked]' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Actions = [GetTextLayoutResult] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: |-Node #24 at (l=0.0, t=1386.0, r=1080.0, b=1562.0)px, Tag: 'MyHistoryCard' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: Actions = [OnClick] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: MergeDescendants = 'true' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: |-Node #27 at (l=55.0, t=1430.0, r=143.0, b=1518.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | ContentDescription = '[]' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Role = 'Image' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: |-Node #28 at (l=198.0, t=1445.0, r=445.0, b=1504.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Text = ‘[My history]' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: | Actions = [GetTextLayoutResult] 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: |-Node #30 at (l=992.0, t=1455.0, r=1014.0, b=1494.0)px 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: ContentDescription = '[]' 10-16 19:04:10.055 1595 1730 D COMPOSE_LOG: Role = 'Image'

    opened by braindonor 3
  • NodeActions.performTouchInput

    NodeActions.performTouchInput

    Something like this has to be present in NodeActions, since performGesture is deprecated in compose

    fun performTouchInput(
            block: TouchInjectionScope.() -> Unit
    ) {
        delegate.perform(object : ComposeOperationType {
            override val name: String = "performTouchInputAction"
        }) { performTouchInput(block) }
    }
    
    opened by Forcharc 2
  • Add API to test Lazy lists

    Add API to test Lazy lists

    We don’t have any possibility to test Lazy lists (LazyColumn/LazyRow). Even if we use compose testing API to get all semantic nodes it gets only visible items:

    val semanticNodes = provider
       .onNode(matcher)
       .onChildren()
       .fetchSemanticsNodes() // Gets only visible items in LazyColumn/LazyRow
    

    It would be great if Kakao Compose added a similar API like in KRecyclerView to get item by index and scroll to specific list’s item.

    opened by AJIEKCX 2
  • Add support for wait operation

    Add support for wait operation

    ComposeTestRule can provide functionality for awaiting views what can be useful for many test cases. However code below don't looks great to me.

    fun BaseNode<*>.waitFor(composeTestRule: ComposeTestRule, timeoutMillis: Long = 1_000) {
        composeTestRule.waitUntil(timeoutMillis) {
            try {
                this.delegate.interaction.semanticsNodeInteraction.assertExists()
                true
            } catch (e: AssertionError) {
                false
            }
        }
    }
    

    Want to find a way how to do the same way but without composeTestRule reinjection to the function

    At the end wanna have something like

    ComposeScreen.onComposeScreen<MyScreen>(composeTestRule) {
      waitFor()
          heading {
            waitFor()
            hasText(it)
          }
    }
    
    opened by Vacxe 1
  • performGesture is deprecated

    performGesture is deprecated

    When I use performGesture on the KNode, I get deprecation warnings for any method from the GestureScope like this:

    Replaced by TouchInjectionScope. Use `performTouchInput` instead of `performGesture`
    

    It seems to originate from compose-junit

    opened by fobo66 0
  • Add API to get children from specific node

    Add API to get children from specific node

    I want to get all items from Row or Column and cast them to specific PageObject. But now you can use only the Compose testing API to get all semantic nodes:

    private val semanticItems = semanticsProvider
      .onAllNodes(hasTestTag(TestTag.MoneyItem.Title), useUnmergedTree = true)
       .fetchSemanticsNodes()
    
    val items: List<KDashboardMoneyItemNode> = semanticItems.mapIndexed { index, _ ->
       child {
           useUnmergedTree = true
           hasTestTag(TestTag.MoneyItem.Tag)
           hasPosition(index)
       }
    }
    

    This solution has many disadvantages. It would be better if Kakao added children function to get all children nodes to hide low level api.

    opened by AJIEKCX 0
  • Question on how I can retrieve the actual value of a field for some custom assertions

    Question on how I can retrieve the actual value of a field for some custom assertions

    Hi,`

    I'd like to perform some custom assertions on a field such as the one in the example code below. I'm sorry if this is an obvious question, but I've been unsuccessful in my attempts to assign a variable to the contents of the "testNumber" field.

         private val testNumber: KNode = onNode {
               hasTestTag("test_number")
               hasPosition(0)
               useUnmergedTree = true
          }
    
          testNumber {
                assertIsDisplayed()
                assertTextEquals(number)
          }
    

    Many thanks,

    Pentti

    `

    opened by braindonor 0
  • viewBuilderAction doesn't see ancestor nodes

    viewBuilderAction doesn't see ancestor nodes

    In my testing if I provide ComposeScreen with viewBuilderAction = { hasTestTag(C.Screen.main_screen) } it doesn't work. I tested a bit, and I suspect that it uses wrong hierarchy matchers. If I do

    composeTestRule.onNode(
        hasTestTag(C.Tag.profile_auth_button).and(
            hasParent(
                hasTestTag(C.Screen.profile_screen)
            )
        )
    ).performClick()
    ``` then it also doesn't work, but if I change hasParent for hasAnyAncestors it does work.
    
    Maybe I am doing something wrong? My initial attempt was like this
    

    onComposeScreen(composeTestRule) { authButton { assertIsDisplayed() performClick() } }

    opened by vrnvorona 0
Releases(0.2.1)
  • 0.2.1(Dec 12, 2022)

    What's Changed

    • Deprecated performGesture and added performTouchInput by @fobo66 in https://github.com/KakaoCup/Compose/pull/36

    New Contributors

    • @fobo66 made their first contribution in https://github.com/KakaoCup/Compose/pull/36

    Full Changelog: https://github.com/KakaoCup/Compose/compare/0.2.0...0.2.1

    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Nov 17, 2022)

    What's Changed

    • Update espresso by @Vacxe in https://github.com/KakaoCup/Compose/pull/41

    Full Changelog: https://github.com/KakaoCup/Compose/compare/0.1.1...0.2.0

    Source code(tar.gz)
    Source code(zip)
  • 0.1.1(Oct 9, 2022)

    What's Changed

    • Add toml version handling by @Vacxe in https://github.com/KakaoCup/Compose/pull/37
    • Shift emulators api +3 by @Vacxe in https://github.com/KakaoCup/Compose/pull/38
    • Update versions by @Vacxe in https://github.com/KakaoCup/Compose/pull/39

    Full Changelog: https://github.com/KakaoCup/Compose/compare/0.1.0...0.1.1

    Source code(tar.gz)
    Source code(zip)
  • 0.1.0(Aug 22, 2022)

    What's Changed

    • Update lazy list readme by @AJIEKCX in https://github.com/KakaoCup/Compose/pull/32
    • Add childWith function to LazyList testing api by @AJIEKCX in https://github.com/KakaoCup/Compose/pull/33
    • Bump versions by @Vacxe in https://github.com/KakaoCup/Compose/pull/34

    Full Changelog: https://github.com/KakaoCup/Compose/compare/0.0.8...0.1.0

    Source code(tar.gz)
    Source code(zip)
  • 0.0.8(Jul 20, 2022)

    What's Changed

    • Add api to test lazy lists by @AJIEKCX in https://github.com/KakaoCup/Compose/pull/29

    Full Changelog: https://github.com/KakaoCup/Compose/compare/0.0.7...0.0.8

    Source code(tar.gz)
    Source code(zip)
  • 0.0.6(Nov 22, 2021)

  • 0.0.3(Nov 6, 2021)

  • 0.0.2(Oct 24, 2021)

  • 0.0.1(Oct 13, 2021)

Integration Testing Kotlin Multiplatform Kata for Kotlin Developers. The main goal is to practice integration testing using Ktor and Ktor Client Mock

This kata is a Kotlin multiplatform version of the kata KataTODOApiClientKotlin of Karumi. We are here to practice integration testing using HTTP stub

Jorge Sánchez Fernández 29 Oct 3, 2022
Xoxo is a simple wrapper around org.w3c.dom to parse XML using nice Kotlin APIs

Xoxo ?? Xoxo is a simple wrapper around org.w3c.dom to parse XML using nice Kotlin APIs. No more NodeList, .item(), etc... just use .children, .filter

Martin Bonnin 51 Sep 1, 2022
Nice String in Kotlin

Nice String We'll say a string is nice if at least two of the following conditio

Bunyod Rafikov 0 Dec 28, 2021
Flexible switch is a responsive switch with some nice features which developers can use for making awesome switches on android platform.

flexible-switch It is a responsive switch in android, it can resize itself according to its size. It's recommended to use it with ConstraintLayout to

Coders Route 5 Dec 20, 2022
Modular Android architecture which showcase Kotlin, MVVM, Navigation, Hilt, Coroutines, Jetpack compose, Retrofit, Unit test and Kotlin Gradle DSL.

SampleCompose Modular Android architecture which showcase Kotlin, MVVM, Navigation, Hilt, Coroutines, Jetpack compose, Retrofit, Unit test and Kotlin

Mohammadali Rezaei 7 Nov 28, 2022
An Android template you can use to build your project with gradle kotlin dsl

Android Gradle KTS An Android template you can use to build your project with gradle kotlin dsl Build.gradle.kts You can use your project's build.grad

Deep 17 Sep 12, 2022
An idiomatic Kotlin DSL for creating regular expressions.

Ketex An idiomatic Kotlin DSL for creating regular expressions. For documentation and usage instructions, please take a look at the docs. Here's the m

TheOnlyTails 24 Nov 8, 2022
Restler is a beautiful and powerful Android app for quickly testing REST API anywhere and anytime.

Restler Restler has been built with simplicity and ease of use in mind. It allows you send custom HTTP/HTTPS requests and test your REST API anywhere

Tiago 10 Dec 20, 2022
DSL for JPA Criteria API without generated metamodel and reflection.

Kotlin JDSL Kotlin JDSL is DSL for JPA Criteria API without generated metamodel and reflection. It helps you write a JPA query like writing an SQL sta

LINE 379 Jan 7, 2023
Maxibon kata for Kotlin Developers. The main goal is to practice property based testing.

Kata Maxibon for Kotlin. We are here to practice property based testing. We are going to use KotlinTest to write our tests. We are going to practice p

Karumi 44 Oct 3, 2022
TODO API Client Kata for Kotlin Developers. The main goal is to practice integration testing using MockWebServer

KataTODOApiClient for Kotlin We are here to practice integration testsing using HTTP stubbing. We are going to use MockWebServer to simulate a HTTP se

Karumi 61 Nov 20, 2022
Screenshot Kata for Android Developers with Kotlin. The main goal is to practice UI Screenshot Testing.

KataScreenshot in Kotlin We are here to practice UI testing using screenshot tests for Android. We are going to use Espresso to interact with the Appl

Karumi 76 Nov 20, 2022
Super Heroes Kata for Android Developers in Kotlin. The main goal is to practice UI Testing.

KataSuperHeroes in Kotlin We are here to practice UI Testing. We are going to use Espresso to interact with the Application UI. We are going to use Ko

Karumi 86 Nov 20, 2022
Kotlin Unit Testing Examples

Kotlin Unit Testing Examples Table of Contents Application Gradle, Kotlin & Groovy Junit4 Junit5 KotlinTest Spek Mockito Mockito-Kotlin Mockk Strikt T

Jarosław 110 Dec 11, 2022
Code for the Advanced Android Kotlin Testing Codelab 5.1-5.3

TO-DO Notes - Code for 5.1-5.3 Testing Codelab Code for the Advanced Android Kotlin Testing Codelab 5.1-5.3 Introduction TO-DO Notes is an app where y

Jorge M 1 Jun 7, 2022
A seed and demo about how to do end-to-end testing of a Dataflow pipeline

dataflow-e2e-demo This is a demo and a seed project to show how you can end-to-end test a Dataflow pipeline. You can find more about by follwing this

null 0 Dec 18, 2021
Gradle plugin which allows to use typed DSL for generating kubernetes/openshift YAML files

gr8s Gradle plugin which allows using typed DSL for generating kubernetes/openshift YAML files. Based on kuberig Usage import io.github.guai.gr8s.Gene

null 0 Jan 3, 2022
Simple Login using firebase and compose views

SimpleLogin Project name: SimpleLogin Android Develop in android over MVVM, Kotlin, Compose. Package Structure com.anelcc.SimpleLogin # Root Pack

Anel CC 5 Oct 25, 2022
Jetpack Compose for Desktop and Web, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.

Jetpack Compose for Desktop and Web, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.

JetBrains 10k Jan 7, 2023