Browse Source
Co-authored-by: Oleksandr Karpovich <oleksandr.karpovich@jetbrains.com>pull/1499/head
Oleksandr Karpovich
3 years ago
committed by
GitHub
2 changed files with 101 additions and 0 deletions
@ -0,0 +1,99 @@
|
||||
# Using test-utils for DOM DSL unit testing |
||||
|
||||
### Dependencies |
||||
|
||||
It's necessary to add `compose.web.testUtils` to jsTest dependencies: |
||||
|
||||
``` kotlin |
||||
sourceSets { |
||||
val jsMain by getting { |
||||
dependencies { |
||||
implementation(compose.web.core) |
||||
implementation(compose.runtime) |
||||
//.... |
||||
} |
||||
} |
||||
val jsTest by getting { |
||||
implementation(kotlin("test-js")) |
||||
implementation(compose.web.testUtils) |
||||
//... |
||||
} |
||||
} |
||||
``` |
||||
|
||||
|
||||
### Example |
||||
|
||||
``` kotlin |
||||
// This is a function that we want to test |
||||
@Composable |
||||
fun TestButton(text: String, onButtonClick: () -> Unit) { |
||||
Button(attrs = { |
||||
onClick { onButtonClick() } |
||||
}) { |
||||
Text(text) |
||||
} |
||||
} |
||||
``` |
||||
|
||||
Let's add a test to ensure that button has correct text, and it's onClick works properly. |
||||
``` kotlin |
||||
import org.jetbrains.compose.web.testutils.ComposeWebExperimentalTestsApi |
||||
import org.jetbrains.compose.web.testutils.runTest |
||||
import androidx.compose.runtime.getValue |
||||
import androidx.compose.runtime.mutableStateOf |
||||
import androidx.compose.runtime.setValue |
||||
import org.w3c.dom.HTMLButtonElement |
||||
import kotlin.test.Test |
||||
import kotlin.test.assertEquals |
||||
|
||||
@OptIn(ComposeWebExperimentalTestsApi::class) |
||||
class TestsForButton { |
||||
|
||||
@Test |
||||
fun testButton() = runTest { |
||||
var counter by mutableStateOf(1) |
||||
|
||||
composition { |
||||
TestButton(text = "$counter") { |
||||
counter++ |
||||
} |
||||
} |
||||
|
||||
assertEquals("<button>1</button>", root.innerHTML) |
||||
|
||||
(root.firstChild!! as HTMLButtonElement).click() |
||||
waitForRecompositionComplete() |
||||
assertEquals("<button>2</button>", root.innerHTML) |
||||
|
||||
counter = 10 |
||||
waitForRecompositionComplete() |
||||
assertEquals("<button>10</button>", root.innerHTML) |
||||
} |
||||
} |
||||
``` |
||||
|
||||
### Let's break it down: |
||||
|
||||
### `runTest { ... }` |
||||
Provides the TestScope with useful functions to configure the test. |
||||
|
||||
### `composition { ... }` |
||||
Takes a @Composable block with a content that we want to test. |
||||
It will automatically build and mount DOM into `root` element. |
||||
|
||||
### `root` |
||||
It's not supposed to be used for elements manipulation. |
||||
It's mostly useful to make assertions on the html content (e.g. `root.innerHtml`) |
||||
|
||||
### `nextChild() and currentChild()` |
||||
Under the hood `nextChild()` iterates over `root` children, providing convenient access to them. |
||||
|
||||
`currentChild()` doesn't move the iterator and returns the same element every time until `nextChild()` called. |
||||
|
||||
### `waitForRecompositionComplete()` |
||||
It suspends until recomposition completes. It's useful when state changes, and we want to test that content updates as well. `waitForRecompositionComplete` needs to be called after state change and before assertions. |
||||
|
||||
### `waitForChanges(id: String)` |
||||
It suspends until any change occur in the element with `id`. |
||||
It's also useful to ensure that state changes make corresponding updates to the content. |
Loading…
Reference in new issue