Shagen Ogandzhanian
3 years ago
38 changed files with 2743 additions and 164 deletions
@ -1 +1 @@
|
||||
Subproject commit 6f678c440ed61acda22918acfb84d7356d3895ca |
||||
Subproject commit 30f010967cd12643134a80269c7eb2de65b2332b |
@ -0,0 +1,74 @@
|
||||
/* |
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.web.attributes.builders |
||||
|
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.runtime.NonRestartableComposable |
||||
import org.jetbrains.compose.web.attributes.InputType |
||||
import org.jetbrains.compose.web.dom.ElementScope |
||||
import org.w3c.dom.HTMLElement |
||||
import org.w3c.dom.HTMLInputElement |
||||
import org.w3c.dom.HTMLTextAreaElement |
||||
|
||||
|
||||
private val controlledInputsValuesWeakMap: JsWeakMap = js("new WeakMap();").unsafeCast<JsWeakMap>() |
||||
|
||||
internal fun restoreControlledInputState(type: InputType<*>, inputElement: HTMLInputElement) { |
||||
if (controlledInputsValuesWeakMap.has(inputElement)) { |
||||
if (type == InputType.Radio) { |
||||
controlledRadioGroups[inputElement.name]?.forEach { radio -> |
||||
radio.checked = controlledInputsValuesWeakMap.get(radio).toString().toBoolean() |
||||
} |
||||
inputElement.checked = controlledInputsValuesWeakMap.get(inputElement).toString().toBoolean() |
||||
return |
||||
} |
||||
|
||||
if (type == InputType.Checkbox) { |
||||
inputElement.checked = controlledInputsValuesWeakMap.get(inputElement).toString().toBoolean() |
||||
} else { |
||||
inputElement.value = controlledInputsValuesWeakMap.get(inputElement).toString() |
||||
} |
||||
} |
||||
} |
||||
|
||||
internal fun restoreControlledTextAreaState(element: HTMLTextAreaElement) { |
||||
if (controlledInputsValuesWeakMap.has(element)) { |
||||
element.value = controlledInputsValuesWeakMap.get(element).toString() |
||||
} |
||||
} |
||||
|
||||
internal fun <V : Any> saveControlledInputState(element: HTMLElement, value: V) { |
||||
controlledInputsValuesWeakMap.set(element, value) |
||||
|
||||
if (element is HTMLInputElement) { |
||||
updateRadioGroupIfNeeded(element) |
||||
} |
||||
} |
||||
|
||||
// internal only for testing purposes. It actually should be private. |
||||
internal val controlledRadioGroups = mutableMapOf<String, MutableSet<HTMLInputElement>>() |
||||
|
||||
private fun updateRadioGroupIfNeeded(element: HTMLInputElement) { |
||||
if (element.type == "radio" && element.name.isNotEmpty()) { |
||||
if (!controlledRadioGroups.containsKey(element.name)) { |
||||
controlledRadioGroups[element.name] = mutableSetOf() |
||||
} |
||||
controlledRadioGroups[element.name]!!.add(element) |
||||
} |
||||
} |
||||
|
||||
@Composable |
||||
@NonRestartableComposable |
||||
internal fun ElementScope<HTMLInputElement>.DisposeRadioGroupEffect() { |
||||
DisposableRefEffect { ref -> |
||||
onDispose { |
||||
controlledRadioGroups[ref.name]?.remove(ref) |
||||
if (controlledRadioGroups[ref.name]?.isEmpty() == true) { |
||||
controlledRadioGroups.remove(ref.name) |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,107 @@
|
||||
/* |
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.web.css |
||||
|
||||
import org.jetbrains.compose.web.ExperimentalComposeWebApi |
||||
import org.w3c.dom.css.CSS |
||||
|
||||
fun interface FilterFunction { |
||||
fun apply(): String |
||||
} |
||||
|
||||
interface FilterBuilder { |
||||
fun blur(radius: CSSLengthValue) |
||||
|
||||
fun brightness(amount: Number) |
||||
fun brightness(amount: CSSPercentageValue) |
||||
|
||||
fun dropShadow(offsetX: CSSLengthValue, offsetY: CSSLengthValue) |
||||
fun dropShadow(offsetX: CSSLengthValue, offsetY: CSSLengthValue, blurRadius: CSSLengthValue) |
||||
fun dropShadow(offsetX: CSSLengthValue, offsetY: CSSLengthValue, color: CSSColorValue) |
||||
fun dropShadow(offsetX: CSSLengthValue, offsetY: CSSLengthValue, blurRadius: CSSLengthValue, color: CSSColorValue) |
||||
|
||||
fun contrast(amount: Number) |
||||
fun contrast(amount: CSSPercentageValue) |
||||
|
||||
fun grayscale(amount: Number) |
||||
fun grayscale(amount: CSSPercentageValue) |
||||
|
||||
fun hueRotate(angle: CSSAngleValue) |
||||
|
||||
fun invert(amount: Number) |
||||
fun invert(amount: CSSPercentageValue) |
||||
|
||||
fun opacity(amount: Number) |
||||
fun opacity(amount: CSSPercentageValue) |
||||
|
||||
fun saturate(amount: Number) |
||||
fun saturate(amount: CSSPercentageValue) |
||||
|
||||
fun sepia(amount: Number) |
||||
fun sepia(amount: CSSPercentageValue) |
||||
} |
||||
|
||||
private class FilterBuilderImplementation : FilterBuilder { |
||||
private val transformations = mutableListOf<FilterFunction>() |
||||
|
||||
override fun blur(radius: CSSLengthValue) { transformations.add { "blur($radius)" } } |
||||
|
||||
override fun brightness(amount: Number) { transformations.add { "brightness($amount)" } } |
||||
override fun brightness(amount: CSSPercentageValue) { transformations.add { "brightness($amount)" } } |
||||
|
||||
override fun contrast(amount: Number) { transformations.add { "contrast($amount)" } } |
||||
override fun contrast(amount: CSSPercentageValue) { transformations.add { "contrast($amount)" } } |
||||
|
||||
override fun grayscale(amount: Number) { transformations.add { "grayscale($amount)" } } |
||||
override fun grayscale(amount: CSSPercentageValue) { transformations.add { "grayscale($amount)" } } |
||||
|
||||
override fun hueRotate(angle: CSSAngleValue) { transformations.add { "hue-rotate($angle)" } } |
||||
|
||||
override fun toString(): String { |
||||
return transformations.joinToString(" ") { it.apply() } |
||||
} |
||||
|
||||
override fun invert(amount: Number) { transformations.add { "invert($amount)" } } |
||||
override fun invert(amount: CSSPercentageValue) { transformations.add { "invert($amount)" } } |
||||
|
||||
override fun opacity(amount: Number) { transformations.add { "opacity($amount)" } } |
||||
override fun opacity(amount: CSSPercentageValue) { transformations.add { "opacity($amount)" } } |
||||
|
||||
override fun saturate(amount: Number) { transformations.add { "saturate($amount)" } } |
||||
override fun saturate(amount: CSSPercentageValue) { transformations.add { "saturate($amount)" } } |
||||
|
||||
override fun sepia(amount: Number) { transformations.add { "sepia($amount)" } } |
||||
override fun sepia(amount: CSSPercentageValue) { transformations.add { "sepia($amount)" } } |
||||
|
||||
override fun dropShadow(offsetX: CSSLengthValue, offsetY: CSSLengthValue) { |
||||
transformations.add { "drop-shadow($offsetX $offsetY)" } |
||||
} |
||||
|
||||
override fun dropShadow(offsetX: CSSLengthValue, offsetY: CSSLengthValue, blurRadius: CSSLengthValue) { |
||||
transformations.add { "drop-shadow($offsetX $offsetY $blurRadius)" } |
||||
} |
||||
|
||||
override fun dropShadow(offsetX: CSSLengthValue, offsetY: CSSLengthValue, color: CSSColorValue) { |
||||
transformations.add { "drop-shadow($offsetX $offsetY $color)" } |
||||
} |
||||
|
||||
override fun dropShadow( |
||||
offsetX: CSSLengthValue, |
||||
offsetY: CSSLengthValue, |
||||
blurRadius: CSSLengthValue, |
||||
color: CSSColorValue |
||||
) { |
||||
transformations.add { "drop-shadow($offsetX $offsetY $blurRadius $color)" } |
||||
} |
||||
} |
||||
|
||||
@ExperimentalComposeWebApi |
||||
fun StyleBuilder.filter(filterContext: FilterBuilder.() -> Unit) { |
||||
val builder = FilterBuilderImplementation() |
||||
property("filter", builder.apply(filterContext).toString()) |
||||
} |
||||
|
||||
|
@ -0,0 +1,138 @@
|
||||
/* |
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.web.css |
||||
|
||||
import org.jetbrains.compose.web.ExperimentalComposeWebApi |
||||
|
||||
fun interface TransformFunction { |
||||
fun apply(): String |
||||
} |
||||
|
||||
interface TransformBuilder { |
||||
fun matrix(a: Number, b: Number, c: Number, d: Number, tx: Number, ty: Number): Boolean |
||||
fun matrix3d( |
||||
a1: Number, b1: Number, c1: Number, d1: Number, |
||||
a2: Number, b2: Number, c2: Number, d2: Number, |
||||
a3: Number, b3: Number, c3: Number, d3: Number, |
||||
a4: Number, b4: Number, c4: Number, d4: Number |
||||
): Boolean |
||||
|
||||
fun perspective(d: CSSLengthValue): Boolean |
||||
fun rotate(a: CSSAngleValue): Boolean |
||||
fun rotate3d(x: Number, y: Number, z: Number, a: CSSAngleValue): Boolean |
||||
fun rotateX(a: CSSAngleValue): Boolean |
||||
fun rotateY(a: CSSAngleValue): Boolean |
||||
fun rotateZ(a: CSSAngleValue): Boolean |
||||
fun scale(sx: Number): Boolean |
||||
fun scale(sx: Number, sy: Number): Boolean |
||||
fun scale3d(sx: Number, sy: Number, sz: Number): Boolean |
||||
fun scaleX(s: Number): Boolean |
||||
fun scaleY(s: Number): Boolean |
||||
fun scaleZ(s: Number): Boolean |
||||
fun skew(ax: CSSAngleValue): Boolean |
||||
fun skew(ax: CSSAngleValue, ay: CSSAngleValue): Boolean |
||||
fun skewX(a: CSSAngleValue): Boolean |
||||
fun skewY(a: CSSAngleValue): Boolean |
||||
fun translate(tx: CSSLengthValue): Boolean |
||||
fun translate(tx: CSSPercentageValue): Boolean |
||||
fun translate(tx: CSSLengthValue, ty: CSSLengthValue): Boolean |
||||
fun translate(tx: CSSLengthValue, ty: CSSPercentageValue): Boolean |
||||
fun translate(tx: CSSPercentageValue, ty: CSSLengthValue): Boolean |
||||
fun translate(tx: CSSPercentageValue, ty: CSSPercentageValue): Boolean |
||||
fun translate3d(tx: CSSLengthValue, ty: CSSLengthValue, tz: CSSLengthValue): Boolean |
||||
fun translate3d(tx: CSSLengthValue, ty: CSSPercentageValue, tz: CSSLengthValue): Boolean |
||||
fun translate3d(tx: CSSPercentageValue, ty: CSSLengthValue, tz: CSSLengthValue): Boolean |
||||
fun translate3d(tx: CSSPercentageValue, ty: CSSPercentageValue, tz: CSSLengthValue): Boolean |
||||
fun translateX(tx: CSSLengthValue): Boolean |
||||
fun translateX(tx: CSSPercentageValue): Boolean |
||||
fun translateY(ty: CSSLengthValue): Boolean |
||||
fun translateY(ty: CSSPercentageValue): Boolean |
||||
fun translateZ(tz: CSSLengthValue): Boolean |
||||
} |
||||
|
||||
private class TransformBuilderImplementation : TransformBuilder { |
||||
private val transformations = mutableListOf<TransformFunction>() |
||||
|
||||
override fun matrix(a: Number, b: Number, c: Number, d: Number, tx: Number, ty: Number) = |
||||
transformations.add { "matrix($a, $b, $c, $d, $tx, $ty)" } |
||||
|
||||
override fun matrix3d( |
||||
a1: Number, b1: Number, c1: Number, d1: Number, |
||||
a2: Number, b2: Number, c2: Number, d2: Number, |
||||
a3: Number, b3: Number, c3: Number, d3: Number, |
||||
a4: Number, b4: Number, c4: Number, d4: Number |
||||
) = |
||||
transformations.add { "matrix3d($a1, $b1, $c1, $d1, $a2, $b2, $c2, $d2, $a3, $b3, $c3, $d3, $a4, $b4, $c4, $d4)" } |
||||
|
||||
override fun perspective(d: CSSLengthValue) = transformations.add { "perspective($d)" } |
||||
|
||||
override fun rotate(a: CSSAngleValue) = transformations.add { "rotate($a)" } |
||||
override fun rotate3d(x: Number, y: Number, z: Number, a: CSSAngleValue) = |
||||
transformations.add({ "rotate3d($x, $y, $z, $a)" }) |
||||
|
||||
override fun rotateX(a: CSSAngleValue) = transformations.add { "rotateX($a)" } |
||||
override fun rotateY(a: CSSAngleValue) = transformations.add { "rotateY($a)" } |
||||
override fun rotateZ(a: CSSAngleValue) = transformations.add { "rotateZ($a)" } |
||||
|
||||
override fun scale(sx: Number) = transformations.add { "scale($sx)" } |
||||
override fun scale(sx: Number, sy: Number) = transformations.add { "scale($sx, $sy)" } |
||||
override fun scale3d(sx: Number, sy: Number, sz: Number) = |
||||
transformations.add { "scale3d($sx, $sy, $sz)" } |
||||
|
||||
override fun scaleX(s: Number) = transformations.add { "scaleX($s)" } |
||||
override fun scaleY(s: Number) = transformations.add { "scaleY($s)" } |
||||
override fun scaleZ(s: Number) = transformations.add { "scaleZ($s)" } |
||||
|
||||
override fun skew(ax: CSSAngleValue) = transformations.add { "skew($ax)" } |
||||
override fun skew(ax: CSSAngleValue, ay: CSSAngleValue) = transformations.add { "skew($ax, $ay)" } |
||||
override fun skewX(a: CSSAngleValue) = transformations.add { "skewX($a)" } |
||||
override fun skewY(a: CSSAngleValue) = transformations.add { "skewY($a)" } |
||||
|
||||
override fun translate(tx: CSSLengthValue) = transformations.add { "translate($tx)" } |
||||
override fun translate(tx: CSSPercentageValue) = transformations.add { "translate($tx)" } |
||||
|
||||
override fun translate(tx: CSSLengthValue, ty: CSSLengthValue) = |
||||
transformations.add { "translate($tx, $ty)" } |
||||
|
||||
override fun translate(tx: CSSLengthValue, ty: CSSPercentageValue) = |
||||
transformations.add { "translate($tx, $ty)" } |
||||
|
||||
override fun translate(tx: CSSPercentageValue, ty: CSSLengthValue) = |
||||
transformations.add { "translate($tx, $ty)" } |
||||
|
||||
override fun translate(tx: CSSPercentageValue, ty: CSSPercentageValue) = |
||||
transformations.add { "translate($tx, $ty)" } |
||||
|
||||
override fun translate3d(tx: CSSLengthValue, ty: CSSLengthValue, tz: CSSLengthValue) = |
||||
transformations.add { "translate3d($tx, $ty, $tz)" } |
||||
|
||||
override fun translate3d(tx: CSSLengthValue, ty: CSSPercentageValue, tz: CSSLengthValue) = |
||||
transformations.add { "translate3d($tx, $ty, $tz)" } |
||||
|
||||
override fun translate3d(tx: CSSPercentageValue, ty: CSSLengthValue, tz: CSSLengthValue) = |
||||
transformations.add { "translate3d($tx, $ty, $tz)" } |
||||
|
||||
override fun translate3d(tx: CSSPercentageValue, ty: CSSPercentageValue, tz: CSSLengthValue) = |
||||
transformations.add { "translate3d($tx, $ty, $tz)" } |
||||
|
||||
override fun translateX(tx: CSSLengthValue) = transformations.add { "translateX($tx)" } |
||||
override fun translateX(tx: CSSPercentageValue) = transformations.add { "translateX($tx)" } |
||||
|
||||
override fun translateY(ty: CSSLengthValue) = transformations.add { "translateY($ty)" } |
||||
override fun translateY(ty: CSSPercentageValue) = transformations.add { "translateY($ty)" } |
||||
|
||||
override fun translateZ(tz: CSSLengthValue) = transformations.add { "translateZ($tz)" } |
||||
|
||||
override fun toString(): String { |
||||
return transformations.joinToString(" ") { it.apply() } |
||||
} |
||||
} |
||||
|
||||
@ExperimentalComposeWebApi |
||||
fun StyleBuilder.transform(transformFunction: TransformBuilder.() -> Unit) { |
||||
val transformBuilder = TransformBuilderImplementation() |
||||
property("transform", transformBuilder.apply(transformFunction).toString()) |
||||
} |
@ -0,0 +1,108 @@
|
||||
package org.jetbrains.compose.web.core.tests |
||||
|
||||
import androidx.compose.runtime.* |
||||
import org.jetbrains.compose.web.dom.Div |
||||
import org.jetbrains.compose.web.attributes.builders.controlledRadioGroups |
||||
import org.jetbrains.compose.web.attributes.name |
||||
import org.jetbrains.compose.web.dom.RadioInput |
||||
import kotlin.test.Test |
||||
import kotlin.test.assertEquals |
||||
import kotlin.test.assertTrue |
||||
|
||||
class ControlledRadioGroupsTests { |
||||
|
||||
@Test |
||||
fun controlledRadioGroupGetsUpdated() = runTest { |
||||
var countOfRadio by mutableStateOf(0) |
||||
|
||||
composition { |
||||
repeat(countOfRadio) { |
||||
key (it) { |
||||
RadioInput(checked = false) { |
||||
id("r$it") |
||||
name("group1") |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
assertEquals(0, controlledRadioGroups.size) |
||||
|
||||
countOfRadio = 5 |
||||
waitForRecompositionComplete() |
||||
|
||||
assertEquals(1, controlledRadioGroups.size) |
||||
assertTrue(controlledRadioGroups.keys.first() == "group1") |
||||
assertEquals(5, controlledRadioGroups["group1"]!!.size) |
||||
|
||||
countOfRadio = 2 |
||||
waitForRecompositionComplete() |
||||
|
||||
assertEquals(1, controlledRadioGroups.size) |
||||
assertTrue(controlledRadioGroups.keys.first() == "group1") |
||||
assertEquals(2, controlledRadioGroups["group1"]!!.size) |
||||
|
||||
countOfRadio = 0 |
||||
waitForRecompositionComplete() |
||||
|
||||
assertEquals(0, controlledRadioGroups.size) |
||||
} |
||||
|
||||
@Test |
||||
fun multipleControlledRadioGroupsGetUpdated() = runTest { |
||||
var countOfRadioG1 by mutableStateOf(0) |
||||
var countOfRadioG2 by mutableStateOf(0) |
||||
|
||||
composition { |
||||
Div { |
||||
repeat(countOfRadioG1) { |
||||
key(it) { |
||||
RadioInput(checked = false) { |
||||
id("r1-$it") |
||||
name("group1") |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
Div { |
||||
repeat(countOfRadioG2) { |
||||
key(it) { |
||||
RadioInput(checked = false) { |
||||
id("r2-$it") |
||||
name("group2") |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
assertEquals(0, controlledRadioGroups.size) |
||||
|
||||
countOfRadioG1 = 5 |
||||
countOfRadioG2 = 10 |
||||
waitForRecompositionComplete() |
||||
|
||||
assertEquals(2, controlledRadioGroups.size) |
||||
assertEquals(5, controlledRadioGroups["group1"]!!.size) |
||||
assertEquals(10, controlledRadioGroups["group2"]!!.size) |
||||
|
||||
countOfRadioG2 = 2 |
||||
waitForRecompositionComplete() |
||||
|
||||
assertEquals(2, controlledRadioGroups.size) |
||||
assertEquals(5, controlledRadioGroups["group1"]!!.size) |
||||
assertEquals(2, controlledRadioGroups["group2"]!!.size) |
||||
|
||||
countOfRadioG1 = 0 |
||||
waitForRecompositionComplete() |
||||
|
||||
assertEquals(1, controlledRadioGroups.size) |
||||
assertEquals(2, controlledRadioGroups["group2"]!!.size) |
||||
|
||||
countOfRadioG2 = 0 |
||||
waitForRecompositionComplete() |
||||
|
||||
assertEquals(0, controlledRadioGroups.size) |
||||
} |
||||
} |
@ -0,0 +1,130 @@
|
||||
/* |
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.web.core.tests.css |
||||
|
||||
import org.jetbrains.compose.web.ExperimentalComposeWebApi |
||||
import org.jetbrains.compose.web.core.tests.runTest |
||||
import org.jetbrains.compose.web.css.* |
||||
import org.jetbrains.compose.web.dom.Div |
||||
import org.jetbrains.compose.web.dom.Img |
||||
import kotlin.test.Test |
||||
import kotlin.test.assertEquals |
||||
|
||||
@ExperimentalComposeWebApi |
||||
class FilterTests { |
||||
@Test |
||||
fun blur() = runTest { |
||||
composition { |
||||
Img(src = "icon.png", attrs = { style { filter { blur(10.px) } } }) |
||||
} |
||||
|
||||
assertEquals("blur(10px)", nextChild().style.filter) |
||||
} |
||||
|
||||
@Test |
||||
fun brightness() = runTest { |
||||
composition { |
||||
Div({ style { filter { brightness(1.75) } } }) |
||||
Div({ style { filter { brightness(200.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("brightness(1.75)", nextChild().style.filter) |
||||
assertEquals("brightness(200%)", nextChild().style.filter) |
||||
} |
||||
|
||||
@Test |
||||
fun contrast() = runTest { |
||||
composition { |
||||
Div({ style { filter { contrast(2.75) } } }) |
||||
Div({ style { filter { contrast(177.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("contrast(2.75)", nextChild().style.filter) |
||||
assertEquals("contrast(177%)", nextChild().style.filter) |
||||
} |
||||
|
||||
@Test |
||||
fun grayscale() = runTest { |
||||
composition { |
||||
Div({ style { filter { grayscale(0.15) } } }) |
||||
Div({ style { filter { grayscale(90.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("grayscale(0.15)", nextChild().style.filter) |
||||
assertEquals("grayscale(90%)", nextChild().style.filter) |
||||
} |
||||
|
||||
@Test |
||||
fun hueRotate() = runTest { |
||||
composition { |
||||
Div({ style { filter { hueRotate(90.deg) } } }) |
||||
Div({ style { filter { hueRotate(0.5.turn) } } }) |
||||
} |
||||
|
||||
assertEquals("hue-rotate(90deg)", nextChild().style.filter) |
||||
assertEquals("hue-rotate(0.5turn)", nextChild().style.filter) |
||||
} |
||||
|
||||
@Test |
||||
fun invert() = runTest { |
||||
composition { |
||||
Div({ style { filter { invert(0.75) } } }) |
||||
Div({ style { filter { invert(30.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("invert(0.75)", nextChild().style.filter) |
||||
assertEquals("invert(30%)", nextChild().style.filter) |
||||
} |
||||
|
||||
@Test |
||||
fun opacity() = runTest { |
||||
composition { |
||||
Div({ style { filter { opacity(.25) } } }) |
||||
Div({ style { filter { opacity(30.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("opacity(0.25)", nextChild().style.filter) |
||||
assertEquals("opacity(30%)", nextChild().style.filter) |
||||
} |
||||
|
||||
@Test |
||||
fun saturate() = runTest { |
||||
composition { |
||||
Div({ style { filter { saturate(.25) } } }) |
||||
Div({ style { filter { saturate(20.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("saturate(0.25)", nextChild().style.filter) |
||||
assertEquals("saturate(20%)", nextChild().style.filter) |
||||
} |
||||
|
||||
@Test |
||||
fun sepia() = runTest { |
||||
composition { |
||||
Div({ style { filter { sepia(.95) } } }) |
||||
Div({ style { filter { sepia(80.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("sepia(0.95)", nextChild().style.filter) |
||||
assertEquals("sepia(80%)", nextChild().style.filter) |
||||
} |
||||
|
||||
@Test |
||||
fun dropShadow() = runTest { |
||||
composition { |
||||
Div({ style { filter { dropShadow(10.em, 5.px) } } }) |
||||
Div({ style { filter { dropShadow(7.px, 2.px, 20.px) } } }) |
||||
Div({ style { filter { dropShadow(7.px, 2.px, Color.yellow) } } }) |
||||
Div({ style { filter { dropShadow(16.px, 16.px, 10.px, Color.black) } } }) |
||||
} |
||||
|
||||
assertEquals("drop-shadow(10em 5px)", nextChild().style.filter) |
||||
assertEquals("drop-shadow(7px 2px 20px)", nextChild().style.filter) |
||||
assertEquals("drop-shadow(yellow 7px 2px)", nextChild().style.filter) |
||||
assertEquals("drop-shadow(black 16px 16px 10px)", nextChild().style.filter) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,258 @@
|
||||
/* |
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
package org.jetbrains.compose.web.core.tests.css |
||||
|
||||
import org.jetbrains.compose.web.ExperimentalComposeWebApi |
||||
import org.jetbrains.compose.web.core.tests.runTest |
||||
import org.jetbrains.compose.web.css.* |
||||
import org.jetbrains.compose.web.dom.Div |
||||
import kotlin.test.Test |
||||
import kotlin.test.assertEquals |
||||
|
||||
@ExperimentalComposeWebApi |
||||
class TransformTests { |
||||
@Test |
||||
fun matrix() = runTest { |
||||
composition { |
||||
Div({ style { transform { matrix(1, 2, -1, 1, 80, 80) } } }) |
||||
} |
||||
|
||||
assertEquals("matrix(1, 2, -1, 1, 80, 80)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun matrix3d() = runTest { |
||||
composition { |
||||
Div({ style { transform { matrix3d(1, 0, 0, 0, 0, 1, 6, 0, 0, 0, 1, 0, 50, 100, 0, 1.1) } } }) |
||||
} |
||||
|
||||
assertEquals("matrix3d(1, 0, 0, 0, 0, 1, 6, 0, 0, 0, 1, 0, 50, 100, 0, 1.1)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun perspective() = runTest { |
||||
composition { |
||||
Div({ style { transform { perspective(3.cm) } } }) |
||||
} |
||||
|
||||
assertEquals("perspective(3cm)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun rotate() = runTest { |
||||
composition { |
||||
Div({ style { transform { rotate(3.deg) } } }) |
||||
} |
||||
|
||||
assertEquals("rotate(3deg)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun rotate3d() = runTest { |
||||
composition { |
||||
Div({ style { transform { rotate3d(1, 1, 0, 2.deg) } } }) |
||||
} |
||||
|
||||
assertEquals("rotate3d(1, 1, 0, 2deg)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun rotateX() = runTest { |
||||
composition { |
||||
Div({ style { transform { rotateX(60.deg) } } }) |
||||
Div({ style { transform { rotateX(-0.25.turn) } } }) |
||||
Div({ style { transform { rotateX(3.14.rad) } } }) |
||||
} |
||||
|
||||
assertEquals("rotateX(60deg)", nextChild().style.transform) |
||||
assertEquals("rotateX(-0.25turn)", nextChild().style.transform) |
||||
assertEquals("rotateX(3.14rad)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun rotateY() = runTest { |
||||
composition { |
||||
Div({ style { transform { rotateY(60.deg) } } }) |
||||
Div({ style { transform { rotateY(-0.25.turn) } } }) |
||||
Div({ style { transform { rotateY(3.14.rad) } } }) |
||||
} |
||||
|
||||
assertEquals("rotateY(60deg)", nextChild().style.transform) |
||||
assertEquals("rotateY(-0.25turn)", nextChild().style.transform) |
||||
assertEquals("rotateY(3.14rad)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun rotateZ() = runTest { |
||||
composition { |
||||
Div({ style { transform { rotateZ(60.deg) } } }) |
||||
Div({ style { transform { rotateZ(-0.25.turn) } } }) |
||||
Div({ style { transform { rotateZ(3.14.rad) } } }) |
||||
} |
||||
|
||||
assertEquals("rotateZ(60deg)", nextChild().style.transform) |
||||
assertEquals("rotateZ(-0.25turn)", nextChild().style.transform) |
||||
assertEquals("rotateZ(3.14rad)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun scale() = runTest { |
||||
composition { |
||||
Div({ style { transform { scale(0.6) } } }) |
||||
Div({ style { transform { scale(0.2, 0.3) } } }) |
||||
} |
||||
|
||||
assertEquals("scale(0.6)", nextChild().style.transform) |
||||
assertEquals("scale(0.2, 0.3)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun scale3d() = runTest { |
||||
composition { |
||||
Div({ style { transform { scale3d(0.2, 0.3, 0.1) } } }) |
||||
} |
||||
|
||||
assertEquals("scale3d(0.2, 0.3, 0.1)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun scaleX() = runTest { |
||||
composition { |
||||
Div({ style { transform { scaleX(0.5) } } }) |
||||
} |
||||
|
||||
assertEquals("scaleX(0.5)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun scaleY() = runTest { |
||||
composition { |
||||
Div({ style { transform { scaleY(0.7) } } }) |
||||
} |
||||
|
||||
assertEquals("scaleY(0.7)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun scaleZ() = runTest { |
||||
composition { |
||||
Div({ style { transform { scaleZ(0.12) } } }) |
||||
} |
||||
|
||||
assertEquals("scaleZ(0.12)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun skew() = runTest { |
||||
composition { |
||||
Div({ style { transform { skew(2.deg) } } }) |
||||
Div({ style { transform { skew(1.rad, 2.deg) } } }) |
||||
} |
||||
|
||||
assertEquals("skew(2deg)", nextChild().style.transform) |
||||
assertEquals("skew(1rad, 2deg)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun skewX() = runTest { |
||||
composition { |
||||
Div({ style { transform { skewX(2.deg) } } }) |
||||
} |
||||
|
||||
assertEquals("skewX(2deg)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun skewY() = runTest { |
||||
composition { |
||||
Div({ style { transform { skewY(2.rad) } } }) |
||||
} |
||||
|
||||
assertEquals("skewY(2rad)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun translate() = runTest { |
||||
composition { |
||||
Div({ style { transform { translate(10.px) } } }) |
||||
Div({ style { transform { translate(4.percent) } } }) |
||||
Div({ style { transform { translate(2.percent, 10.px) } } }) |
||||
Div({ style { transform { translate(10.px, 3.percent) } } }) |
||||
Div({ style { transform { translate(20.px, 10.px) } } }) |
||||
Div({ style { transform { translate(5.percent, 8.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("translate(10px)", nextChild().style.transform) |
||||
assertEquals("translate(4%)", nextChild().style.transform) |
||||
assertEquals("translate(2%, 10px)", nextChild().style.transform) |
||||
assertEquals("translate(10px, 3%)", nextChild().style.transform) |
||||
assertEquals("translate(20px, 10px)", nextChild().style.transform) |
||||
assertEquals("translate(5%, 8%)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun translate3d() = runTest { |
||||
composition { |
||||
Div({ style { transform { translate3d(2.percent, 10.px, 1.em) } } }) |
||||
Div({ style { transform { translate3d(10.px, 3.percent, 2.em) } } }) |
||||
Div({ style { transform { translate3d(20.px, 10.px, 3.em) } } }) |
||||
Div({ style { transform { translate3d(5.percent, 8.percent, 4.em) } } }) |
||||
} |
||||
|
||||
assertEquals("translate3d(2%, 10px, 1em)", nextChild().style.transform) |
||||
assertEquals("translate3d(10px, 3%, 2em)", nextChild().style.transform) |
||||
assertEquals("translate3d(20px, 10px, 3em)", nextChild().style.transform) |
||||
assertEquals("translate3d(5%, 8%, 4em)", nextChild().style.transform) |
||||
} |
||||
|
||||
|
||||
@Test |
||||
fun translateX() = runTest { |
||||
composition { |
||||
Div({ style { transform { translateX(10.px) } } }) |
||||
Div({ style { transform { translateX(4.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("translateX(10px)", nextChild().style.transform) |
||||
assertEquals("translateX(4%)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun translateY() = runTest { |
||||
composition { |
||||
Div({ style { transform { translateY(12.px) } } }) |
||||
Div({ style { transform { translateY(3.percent) } } }) |
||||
} |
||||
|
||||
assertEquals("translateY(12px)", nextChild().style.transform) |
||||
assertEquals("translateY(3%)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun translateZ() = runTest { |
||||
composition { |
||||
Div({ style { transform { translateZ(7.px) } } }) |
||||
} |
||||
|
||||
assertEquals("translateZ(7px)", nextChild().style.transform) |
||||
} |
||||
|
||||
@Test |
||||
fun mutliples() = runTest { |
||||
composition { |
||||
Div({ |
||||
style { |
||||
transform { |
||||
perspective(3.cm) |
||||
translate(10.px, 3.px) |
||||
rotateY(3.deg) |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
|
||||
assertEquals("perspective(3cm) translate(10px, 3px) rotateY(3deg)", nextChild().style.transform) |
||||
} |
||||
} |
@ -0,0 +1,412 @@
|
||||
/* |
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package androidx.compose.web.sample.tests |
||||
|
||||
import androidx.compose.runtime.getValue |
||||
import androidx.compose.runtime.mutableStateOf |
||||
import androidx.compose.runtime.remember |
||||
import androidx.compose.runtime.setValue |
||||
import org.jetbrains.compose.web.attributes.InputType |
||||
import org.jetbrains.compose.web.attributes.name |
||||
import org.jetbrains.compose.web.dom.* |
||||
import org.jetbrains.compose.web.sample.tests.TestText |
||||
import org.jetbrains.compose.web.sample.tests.testCase |
||||
|
||||
class ControlledInputsTests { |
||||
|
||||
val textInputHardcodedValueShouldNotChange by testCase { |
||||
var onInputText by remember { mutableStateOf("None") } |
||||
|
||||
P { TestText(onInputText) } |
||||
|
||||
Div { |
||||
TextInput(value = "hardcoded", attrs = { |
||||
id("textInput") |
||||
onInput { |
||||
onInputText = it.value |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
val textInputMutableValueShouldGetOverridden by testCase { |
||||
var onInputText by remember { mutableStateOf("InitialValue") } |
||||
|
||||
P { TestText(onInputText) } |
||||
|
||||
Div { |
||||
TextInput(value = onInputText, attrs = { |
||||
id("textInput") |
||||
onInput { |
||||
onInputText = "OVERRIDDEN VALUE" |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
val textInputMutableValueShouldChange by testCase { |
||||
var onInputText by remember { mutableStateOf("InitialValue") } |
||||
|
||||
P { TestText(onInputText) } |
||||
|
||||
Div { |
||||
TextInput(value = onInputText, attrs = { |
||||
id("textInput") |
||||
onInput { |
||||
onInputText = it.value |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
val textAreaHardcodedValueShouldNotChange by testCase { |
||||
var onInputText by remember { mutableStateOf("None") } |
||||
|
||||
P { TestText(onInputText) } |
||||
|
||||
Div { |
||||
TextArea(value = "hardcoded", attrs = { |
||||
id("textArea") |
||||
onInput { |
||||
onInputText = it.value |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
val textAreaMutableValueShouldGetOverridden by testCase { |
||||
var onInputText by remember { mutableStateOf("InitialValue") } |
||||
|
||||
P { TestText(onInputText) } |
||||
|
||||
Div { |
||||
TextArea(value = onInputText, attrs = { |
||||
id("textArea") |
||||
onInput { |
||||
onInputText = "OVERRIDDEN VALUE" |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
val textAreaMutableValueShouldChange by testCase { |
||||
var onInputText by remember { mutableStateOf("InitialValue") } |
||||
|
||||
P { TestText(onInputText) } |
||||
|
||||
Div { |
||||
TextArea(value = onInputText, attrs = { |
||||
id("textArea") |
||||
onInput { |
||||
onInputText = it.value |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
val checkBoxHardcodedNeverChanges by testCase { |
||||
var checkClicked by remember { mutableStateOf(false) } |
||||
|
||||
P { TestText(checkClicked.toString()) } |
||||
|
||||
Div { |
||||
CheckboxInput(checked = false) { |
||||
id("checkbox") |
||||
onInput { |
||||
checkClicked = it.value |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
val checkBoxMutableValueChanges by testCase { |
||||
var checked by remember { mutableStateOf(false) } |
||||
|
||||
P { TestText(checked.toString()) } |
||||
|
||||
Div { |
||||
CheckboxInput(checked = checked) { |
||||
id("checkbox") |
||||
onInput { |
||||
checked = it.value |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
val checkBoxDefaultCheckedChangesDoesntAffectState by testCase { |
||||
var checked by remember { mutableStateOf(true) } |
||||
|
||||
P { TestText(checked.toString()) } |
||||
|
||||
Div { |
||||
Input(type = InputType.Checkbox) { |
||||
id("checkboxMirror") |
||||
if (checked) defaultChecked() |
||||
} |
||||
|
||||
Input(type = InputType.Checkbox) { |
||||
id("checkboxMain") |
||||
checked(checked) |
||||
onInput { checked = it.value } |
||||
} |
||||
} |
||||
} |
||||
|
||||
val radioHardcodedNeverChanges by testCase { |
||||
Div { |
||||
RadioInput(checked = true) { |
||||
id("radio1") |
||||
name("group1") |
||||
} |
||||
RadioInput(checked = false) { |
||||
id("radio2") |
||||
name("group1") |
||||
} |
||||
} |
||||
} |
||||
|
||||
val radioMutableCheckedChanges by testCase { |
||||
var checked by remember { mutableStateOf(0) } |
||||
|
||||
TestText("Checked - $checked") |
||||
|
||||
Div { |
||||
RadioInput(checked = checked == 1) { |
||||
id("radio1") |
||||
name("group1") |
||||
onInput { checked = 1 } |
||||
} |
||||
RadioInput(checked = checked == 2) { |
||||
id("radio2") |
||||
name("group1") |
||||
onInput { checked = 2 } |
||||
} |
||||
} |
||||
} |
||||
|
||||
val numberHardcodedNeverChanges by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
TestText(value = typedValue) |
||||
|
||||
NumberInput(value = 5, min = 0, max = 100) { |
||||
id("numberInput") |
||||
onInput { |
||||
typedValue = it.value.toString() |
||||
} |
||||
} |
||||
} |
||||
|
||||
val numberMutableChanges by testCase { |
||||
var value by remember { mutableStateOf(5) } |
||||
TestText(value = value.toString()) |
||||
|
||||
NumberInput(value = value, min = 0, max = 100) { |
||||
id("numberInput") |
||||
onInput { |
||||
value = it.value!!.toInt() |
||||
} |
||||
} |
||||
} |
||||
|
||||
val rangeHardcodedNeverChanges by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
|
||||
TestText(value = typedValue) |
||||
|
||||
RangeInput(value = 21) { |
||||
id("rangeInput") |
||||
onInput { |
||||
typedValue = it.value.toString() |
||||
} |
||||
} |
||||
} |
||||
|
||||
val rangeMutableChanges by testCase { |
||||
var value by remember { mutableStateOf(10) } |
||||
|
||||
TestText(value = value.toString()) |
||||
|
||||
RangeInput(value = value) { |
||||
id("rangeInput") |
||||
onInput { |
||||
value = it.value!!.toInt() |
||||
} |
||||
} |
||||
} |
||||
|
||||
val emailHardcodedNeverChanges by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
TestText(value = typedValue) |
||||
|
||||
EmailInput(value = "a@a.abc") { |
||||
id("emailInput") |
||||
onInput { |
||||
typedValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val emailMutableChanges by testCase { |
||||
var value by remember { mutableStateOf("") } |
||||
TestText(value = value) |
||||
|
||||
EmailInput(value = value) { |
||||
id("emailInput") |
||||
onInput { |
||||
value = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val passwordHardcodedNeverChanges by testCase { |
||||
var typeValue by remember { mutableStateOf("None") } |
||||
TestText(value = typeValue) |
||||
|
||||
PasswordInput(value = "123456") { |
||||
id("passwordInput") |
||||
onInput { |
||||
typeValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val passwordMutableChanges by testCase { |
||||
var value by remember { mutableStateOf("") } |
||||
TestText(value = value) |
||||
|
||||
EmailInput(value = value) { |
||||
id("passwordInput") |
||||
onInput { |
||||
value = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val searchHardcodedNeverChanges by testCase { |
||||
var typeValue by remember { mutableStateOf("None") } |
||||
TestText(value = typeValue) |
||||
|
||||
SearchInput(value = "hardcoded") { |
||||
id("searchInput") |
||||
onInput { |
||||
typeValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val searchMutableChanges by testCase { |
||||
var typeValue by remember { mutableStateOf("") } |
||||
TestText(value = typeValue) |
||||
|
||||
SearchInput(value = typeValue) { |
||||
id("searchInput") |
||||
onInput { |
||||
typeValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val telHardcodedNeverChanges by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
TestText(value = typedValue) |
||||
|
||||
TelInput(value = "123456") { |
||||
id("telInput") |
||||
onInput { |
||||
typedValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val telMutableChanges by testCase { |
||||
var value by remember { mutableStateOf("") } |
||||
TestText(value = value) |
||||
|
||||
TelInput(value = value) { |
||||
id("telInput") |
||||
onInput { |
||||
value = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val urlHardcodedNeverChanges by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
TestText(value = typedValue) |
||||
|
||||
UrlInput(value = "www.site.com") { |
||||
id("urlInput") |
||||
onInput { |
||||
typedValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val urlMutableChanges by testCase { |
||||
var value by remember { mutableStateOf("") } |
||||
TestText(value = value) |
||||
|
||||
UrlInput(value = value) { |
||||
id("urlInput") |
||||
onInput { |
||||
value = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val hardcodedDateInputNeverChanges by testCase { |
||||
var inputValue by remember { mutableStateOf("None") } |
||||
|
||||
TestText(inputValue) |
||||
|
||||
DateInput(value = "") { |
||||
id("dateInput") |
||||
onInput { |
||||
inputValue = "onInput Caught" |
||||
} |
||||
} |
||||
} |
||||
|
||||
val mutableDateInputChanges by testCase { |
||||
var inputValue by remember { mutableStateOf("") } |
||||
|
||||
TestText(inputValue) |
||||
|
||||
DateInput(value = inputValue) { |
||||
id("dateInput") |
||||
onInput { |
||||
inputValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val hardcodedTimeNeverChanges by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
|
||||
TestText(typedValue) |
||||
|
||||
TimeInput(value = "14:00") { |
||||
id("time") |
||||
onInput { |
||||
typedValue = "onInput Caught" |
||||
} |
||||
} |
||||
} |
||||
|
||||
val mutableTimeChanges by testCase { |
||||
var value by remember { mutableStateOf("") } |
||||
|
||||
TestText(value) |
||||
|
||||
TimeInput(value = value) { |
||||
id("time") |
||||
onInput { |
||||
value = it.value |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,190 @@
|
||||
/* |
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package androidx.compose.web.sample.tests |
||||
|
||||
import androidx.compose.runtime.getValue |
||||
import androidx.compose.runtime.mutableStateOf |
||||
import androidx.compose.runtime.remember |
||||
import androidx.compose.runtime.setValue |
||||
import org.jetbrains.compose.web.attributes.InputType |
||||
import org.jetbrains.compose.web.attributes.name |
||||
import org.jetbrains.compose.web.dom.* |
||||
import org.jetbrains.compose.web.sample.tests.TestText |
||||
import org.jetbrains.compose.web.sample.tests.testCase |
||||
|
||||
class UncontrolledInputsTests { |
||||
|
||||
val textInputDefaultValueRemainsTheSameButValueCanBeChanged by testCase { |
||||
var inputValue by remember { mutableStateOf("") } |
||||
|
||||
Input(type = InputType.Text) { |
||||
|
||||
id("textInput") |
||||
defaultValue("defaultInputValue") |
||||
|
||||
attr("data-input-value", inputValue) |
||||
|
||||
onInput { |
||||
inputValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val textAreaDefaultValueRemainsTheSameButValueCanBeChanged by testCase { |
||||
var inputValue by remember { mutableStateOf("") } |
||||
|
||||
TextArea { |
||||
|
||||
id("textArea") |
||||
defaultValue("defaultTextAreaValue") |
||||
|
||||
attr("data-text-area-value", inputValue) |
||||
|
||||
onInput { |
||||
inputValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val checkBoxDefaultCheckedRemainsTheSameButCheckedCanBeChanged by testCase { |
||||
var checkedValue by remember { mutableStateOf(true) } |
||||
|
||||
Input(type = InputType.Checkbox) { |
||||
id("checkbox") |
||||
defaultChecked() |
||||
value("checkbox-value") |
||||
|
||||
attr("data-checkbox", checkedValue.toString()) |
||||
|
||||
onInput { |
||||
checkedValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val radioDefaultCheckedRemainsTheSameButCheckedCanBeChanged by testCase { |
||||
var checkedValue by remember { mutableStateOf("") } |
||||
|
||||
Input(type = InputType.Radio) { |
||||
id("radio1") |
||||
defaultChecked() |
||||
value("radio-value1") |
||||
name("radiogroup") |
||||
|
||||
attr("data-radio", checkedValue) |
||||
|
||||
onInput { |
||||
checkedValue = "radio-value1" |
||||
} |
||||
} |
||||
|
||||
Input(type = InputType.Radio) { |
||||
id("radio2") |
||||
value("radio-value2") |
||||
name("radiogroup") |
||||
|
||||
attr("data-radio", checkedValue) |
||||
|
||||
onInput { |
||||
checkedValue = "radio-value2" |
||||
} |
||||
} |
||||
} |
||||
|
||||
val numberDefaultValueRemainsTheSameButValueCanBeChanged by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
|
||||
TestText(value = "Value = $typedValue") |
||||
|
||||
Input(type = InputType.Number) { |
||||
id("numberInput") |
||||
defaultValue(11) |
||||
onInput { |
||||
typedValue = it.value.toString() |
||||
} |
||||
} |
||||
} |
||||
|
||||
val rangeDefaultValueRemainsTheSameButValueCanBeChanged by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
|
||||
TestText(value = "Value = $typedValue") |
||||
|
||||
Input(type = InputType.Range) { |
||||
id("rangeInput") |
||||
defaultValue(7) |
||||
onInput { |
||||
typedValue = it.value.toString() |
||||
} |
||||
} |
||||
} |
||||
|
||||
val emailDefaultValueRemainsTheSameButValueCanBeChanged by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
TestText(value = "Value = $typedValue") |
||||
|
||||
Input(type = InputType.Email) { |
||||
id("emailInput") |
||||
defaultValue("a@a.abc") |
||||
onInput { |
||||
typedValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val passwordDefaultValueRemainsTheSameButValueCanBeChanged by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
TestText(value = "Value = $typedValue") |
||||
|
||||
Input(type = InputType.Password) { |
||||
id("passwordInput") |
||||
defaultValue("1111") |
||||
onInput { |
||||
typedValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val searchDefaultValueRemainsTheSameButValueCanBeChanged by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
TestText(value = "Value = $typedValue") |
||||
|
||||
Input(type = InputType.Search) { |
||||
id("searchInput") |
||||
defaultValue("kotlin") |
||||
onInput { |
||||
typedValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val telDefaultValueRemainsTheSameButValueCanBeChanged by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
TestText(value = typedValue) |
||||
|
||||
Input(type = InputType.Tel) { |
||||
id("telInput") |
||||
defaultValue("123123") |
||||
onInput { |
||||
typedValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
val urlDefaultValueRemainsTheSameButValueCanBeChanged by testCase { |
||||
var typedValue by remember { mutableStateOf("None") } |
||||
TestText(value = typedValue) |
||||
|
||||
Input(type = InputType.Url) { |
||||
id("urlInput") |
||||
defaultValue("www.site.com") |
||||
onInput { |
||||
typedValue = it.value |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,507 @@
|
||||
/* |
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.web.tests.integration |
||||
|
||||
import org.jetbrains.compose.web.tests.integration.common.BaseIntegrationTests |
||||
import org.jetbrains.compose.web.tests.integration.common.ResolveDrivers |
||||
import org.jetbrains.compose.web.tests.integration.common.openTestPage |
||||
import org.jetbrains.compose.web.tests.integration.common.waitTextToBe |
||||
import org.junit.jupiter.api.Assumptions |
||||
import org.openqa.selenium.By |
||||
import org.openqa.selenium.Keys |
||||
import org.openqa.selenium.WebDriver |
||||
import org.openqa.selenium.chrome.ChromeDriver |
||||
|
||||
class ControlledInputsTests : BaseIntegrationTests() { |
||||
|
||||
@ResolveDrivers |
||||
fun textInputHardcodedValueShouldNotChange(driver: WebDriver) { |
||||
driver.openTestPage("textInputHardcodedValueShouldNotChange") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val controlledTextInput = driver.findElement(By.id("textInput")) |
||||
|
||||
controlledTextInput.sendKeys("A") |
||||
driver.waitTextToBe(value = "hardcodedA") |
||||
|
||||
controlledTextInput.sendKeys("B") |
||||
driver.waitTextToBe(value = "hardcodedB") |
||||
|
||||
controlledTextInput.sendKeys("C") |
||||
driver.waitTextToBe(value = "hardcodedC") |
||||
|
||||
check(controlledTextInput.getAttribute("value") == "hardcoded") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun textInputMutableValueShouldGetOverridden(driver: WebDriver) { |
||||
driver.openTestPage("textInputMutableValueShouldGetOverridden") |
||||
driver.waitTextToBe(value = "InitialValue") |
||||
|
||||
val controlledTextInput = driver.findElement(By.id("textInput")) |
||||
controlledTextInput.sendKeys("ABC") |
||||
|
||||
driver.waitTextToBe(value = "OVERRIDDEN VALUE") |
||||
check(controlledTextInput.getAttribute("value") == "OVERRIDDEN VALUE") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun textInputMutableValueShouldChange(driver: WebDriver) { |
||||
driver.openTestPage("textInputMutableValueShouldChange") |
||||
driver.waitTextToBe(value = "InitialValue") |
||||
|
||||
val controlledTextInput = driver.findElement(By.id("textInput")) |
||||
|
||||
controlledTextInput.sendKeys("A") |
||||
driver.waitTextToBe(value = "InitialValueA") |
||||
|
||||
controlledTextInput.sendKeys("B") |
||||
driver.waitTextToBe(value = "InitialValueAB") |
||||
|
||||
controlledTextInput.sendKeys("C") |
||||
driver.waitTextToBe(value = "InitialValueABC") |
||||
|
||||
check(controlledTextInput.getAttribute("value") == "InitialValueABC") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun textAreaHardcodedValueShouldNotChange(driver: WebDriver) { |
||||
driver.openTestPage("textAreaHardcodedValueShouldNotChange") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val controlledTextArea = driver.findElement(By.id("textArea")) |
||||
|
||||
controlledTextArea.sendKeys("A") |
||||
driver.waitTextToBe(value = "hardcodedA") |
||||
|
||||
controlledTextArea.sendKeys("B") |
||||
driver.waitTextToBe(value = "hardcodedB") |
||||
|
||||
controlledTextArea.sendKeys("C") |
||||
driver.waitTextToBe(value = "hardcodedC") |
||||
|
||||
check(controlledTextArea.getAttribute("value") == "hardcoded") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun textAreaMutableValueShouldGetOverridden(driver: WebDriver) { |
||||
driver.openTestPage("textAreaMutableValueShouldGetOverridden") |
||||
driver.waitTextToBe(value = "InitialValue") |
||||
|
||||
val controlledTextArea = driver.findElement(By.id("textArea")) |
||||
controlledTextArea.sendKeys("ABC") |
||||
|
||||
driver.waitTextToBe(value = "OVERRIDDEN VALUE") |
||||
check(controlledTextArea.getAttribute("value") == "OVERRIDDEN VALUE") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun textAreaMutableValueShouldChange(driver: WebDriver) { |
||||
driver.openTestPage("textAreaMutableValueShouldChange") |
||||
driver.waitTextToBe(value = "InitialValue") |
||||
|
||||
val controlledTextArea = driver.findElement(By.id("textArea")) |
||||
|
||||
controlledTextArea.sendKeys("A") |
||||
driver.waitTextToBe(value = "InitialValueA") |
||||
|
||||
controlledTextArea.sendKeys("B") |
||||
driver.waitTextToBe(value = "InitialValueAB") |
||||
|
||||
controlledTextArea.sendKeys("C") |
||||
driver.waitTextToBe(value = "InitialValueABC") |
||||
|
||||
check(controlledTextArea.getAttribute("value") == "InitialValueABC") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun checkBoxHardcodedNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("checkBoxHardcodedNeverChanges") |
||||
driver.waitTextToBe(value = "false") |
||||
|
||||
val checkbox = driver.findElement(By.id("checkbox")) |
||||
check(!checkbox.isSelected) |
||||
|
||||
checkbox.click() |
||||
|
||||
driver.waitTextToBe(value = "true") // input received but ignored |
||||
check(!checkbox.isSelected) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun checkBoxMutableValueChanges(driver: WebDriver) { |
||||
driver.openTestPage("checkBoxMutableValueChanges") |
||||
driver.waitTextToBe(value = "false") |
||||
|
||||
val checkbox = driver.findElement(By.id("checkbox")) |
||||
check(!checkbox.isSelected) |
||||
|
||||
checkbox.click() |
||||
|
||||
driver.waitTextToBe(value = "true") |
||||
check(checkbox.isSelected) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun checkBoxDefaultCheckedChangesDoesntAffectState(driver: WebDriver) { |
||||
driver.openTestPage("checkBoxDefaultCheckedChangesDoesntAffectState") |
||||
driver.waitTextToBe(value = "true") |
||||
|
||||
val mainCheckbox = driver.findElement(By.id("checkboxMain")) |
||||
val mirrorCheckbox = driver.findElement(By.id("checkboxMirror")) |
||||
|
||||
check(mainCheckbox.isSelected) |
||||
check(mirrorCheckbox.isSelected) |
||||
|
||||
mirrorCheckbox.click() |
||||
driver.waitTextToBe(value = "true") |
||||
check(!mirrorCheckbox.isSelected) |
||||
check(mainCheckbox.isSelected) |
||||
|
||||
mainCheckbox.click() |
||||
driver.waitTextToBe(value = "false") |
||||
check(!mainCheckbox.isSelected) |
||||
check(!mirrorCheckbox.isSelected) |
||||
|
||||
mainCheckbox.click() |
||||
driver.waitTextToBe(value = "true") |
||||
check(mainCheckbox.isSelected) |
||||
check(!mirrorCheckbox.isSelected) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun radioHardcodedNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("radioHardcodedNeverChanges") |
||||
|
||||
val radio1 = driver.findElement(By.id("radio1")) |
||||
val radio2 = driver.findElement(By.id("radio2")) |
||||
|
||||
check(radio1.isSelected) |
||||
check(!radio2.isSelected) |
||||
|
||||
check(radio1.getAttribute("name") == radio2.getAttribute("name")) |
||||
check(radio1.getAttribute("name") == "group1") |
||||
check(radio2.getAttribute("name") == "group1") |
||||
|
||||
radio2.click() |
||||
|
||||
check(radio1.isSelected) |
||||
check(!radio2.isSelected) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun radioMutableCheckedChanges(driver: WebDriver) { |
||||
driver.openTestPage("radioMutableCheckedChanges") |
||||
driver.waitTextToBe(value = "Checked - 0") |
||||
|
||||
val radio1 = driver.findElement(By.id("radio1")) |
||||
val radio2 = driver.findElement(By.id("radio2")) |
||||
|
||||
check(!radio1.isSelected) |
||||
check(!radio2.isSelected) |
||||
|
||||
radio2.click() |
||||
driver.waitTextToBe(value = "Checked - 2") |
||||
|
||||
check(!radio1.isSelected) |
||||
check(radio2.isSelected) |
||||
|
||||
radio1.click() |
||||
driver.waitTextToBe(value = "Checked - 1") |
||||
|
||||
check(radio1.isSelected) |
||||
check(!radio2.isSelected) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun numberHardcodedNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("numberHardcodedNeverChanges") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val numberInput = driver.findElement(By.id("numberInput")) |
||||
|
||||
check(numberInput.getAttribute("value") == "5") |
||||
|
||||
numberInput.sendKeys("1") |
||||
driver.waitTextToBe(value = "51") |
||||
|
||||
check(numberInput.getAttribute("value") == "5") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun numberMutableChanges(driver: WebDriver) { |
||||
driver.openTestPage("numberMutableChanges") |
||||
driver.waitTextToBe(value = "5") |
||||
|
||||
val numberInput = driver.findElement(By.id("numberInput")) |
||||
|
||||
check(numberInput.getAttribute("value") == "5") |
||||
|
||||
numberInput.sendKeys("1") |
||||
driver.waitTextToBe(value = "51") |
||||
|
||||
check(numberInput.getAttribute("value") == "51") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun rangeHardcodedNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("rangeHardcodedNeverChanges") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val numberInput = driver.findElement(By.id("rangeInput")) |
||||
|
||||
check(numberInput.getAttribute("value") == "21") |
||||
|
||||
numberInput.sendKeys(Keys.ARROW_RIGHT) |
||||
driver.waitTextToBe(value = "22") |
||||
check(numberInput.getAttribute("value") == "21") |
||||
|
||||
numberInput.sendKeys(Keys.ARROW_RIGHT) |
||||
driver.waitTextToBe(value = "22") |
||||
check(numberInput.getAttribute("value") == "21") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun rangeMutableChanges(driver: WebDriver) { |
||||
driver.openTestPage("rangeMutableChanges") |
||||
driver.waitTextToBe(value = "10") |
||||
|
||||
val numberInput = driver.findElement(By.id("rangeInput")) |
||||
|
||||
check(numberInput.getAttribute("value") == "10") |
||||
|
||||
numberInput.sendKeys(Keys.ARROW_RIGHT) |
||||
driver.waitTextToBe(value = "11") |
||||
check(numberInput.getAttribute("value") == "11") |
||||
|
||||
numberInput.sendKeys(Keys.ARROW_RIGHT) |
||||
driver.waitTextToBe(value = "12") |
||||
check(numberInput.getAttribute("value") == "12") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun emailHardcodedNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("emailHardcodedNeverChanges") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val emailInput = driver.findElement(By.id("emailInput")) |
||||
check(emailInput.getAttribute("value") == "a@a.abc") |
||||
|
||||
emailInput.sendKeys("@") |
||||
driver.waitTextToBe(value = "a@a.abc@") |
||||
|
||||
check(emailInput.getAttribute("value") == "a@a.abc") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun emailMutableChanges(driver: WebDriver) { |
||||
driver.openTestPage("emailMutableChanges") |
||||
driver.waitTextToBe(value = "") |
||||
|
||||
val emailInput = driver.findElement(By.id("emailInput")) |
||||
check(emailInput.getAttribute("value") == "") |
||||
|
||||
emailInput.sendKeys("a") |
||||
driver.waitTextToBe(value = "a") |
||||
|
||||
check(emailInput.getAttribute("value") == "a") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun passwordHardcodedNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("passwordHardcodedNeverChanges") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val passwordInput = driver.findElement(By.id("passwordInput")) |
||||
check(passwordInput.getAttribute("value") == "123456") |
||||
|
||||
passwordInput.sendKeys("a") |
||||
driver.waitTextToBe(value = "123456a") |
||||
|
||||
check(passwordInput.getAttribute("value") == "123456") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun passwordMutableChanges(driver: WebDriver) { |
||||
driver.openTestPage("passwordMutableChanges") |
||||
driver.waitTextToBe(value = "") |
||||
|
||||
val passwordInput = driver.findElement(By.id("passwordInput")) |
||||
check(passwordInput.getAttribute("value") == "") |
||||
|
||||
passwordInput.sendKeys("a") |
||||
driver.waitTextToBe(value = "a") |
||||
|
||||
check(passwordInput.getAttribute("value") == "a") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun searchHardcodedNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("searchHardcodedNeverChanges") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val searchInput = driver.findElement(By.id("searchInput")) |
||||
check(searchInput.getAttribute("value") == "hardcoded") |
||||
|
||||
searchInput.sendKeys("a") |
||||
driver.waitTextToBe(value = "hardcodeda") |
||||
|
||||
check(searchInput.getAttribute("value") == "hardcoded") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun searchMutableChanges(driver: WebDriver) { |
||||
driver.openTestPage("searchMutableChanges") |
||||
driver.waitTextToBe(value = "") |
||||
|
||||
val searchInput = driver.findElement(By.id("searchInput")) |
||||
check(searchInput.getAttribute("value") == "") |
||||
|
||||
searchInput.sendKeys("a") |
||||
driver.waitTextToBe(value = "a") |
||||
|
||||
check(searchInput.getAttribute("value") == "a") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun telHardcodedNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("telHardcodedNeverChanges") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val telInput = driver.findElement(By.id("telInput")) |
||||
check(telInput.getAttribute("value") == "123456") |
||||
|
||||
telInput.sendKeys("7") |
||||
driver.waitTextToBe(value = "1234567") |
||||
|
||||
check(telInput.getAttribute("value") == "123456") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun telMutableChanges(driver: WebDriver) { |
||||
driver.openTestPage("telMutableChanges") |
||||
driver.waitTextToBe(value = "") |
||||
|
||||
val telInput = driver.findElement(By.id("telInput")) |
||||
check(telInput.getAttribute("value") == "") |
||||
|
||||
telInput.sendKeys("1") |
||||
driver.waitTextToBe(value = "1") |
||||
|
||||
check(telInput.getAttribute("value") == "1") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun urlHardcodedNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("urlHardcodedNeverChanges") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val urlInput = driver.findElement(By.id("urlInput")) |
||||
check(urlInput.getAttribute("value") == "www.site.com") |
||||
|
||||
urlInput.sendKeys("a") |
||||
driver.waitTextToBe(value = "www.site.coma") |
||||
|
||||
check(urlInput.getAttribute("value") == "www.site.com") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun urlMutableChanges(driver: WebDriver) { |
||||
driver.openTestPage("urlMutableChanges") |
||||
driver.waitTextToBe(value = "") |
||||
|
||||
val urlInput = driver.findElement(By.id("urlInput")) |
||||
check(urlInput.getAttribute("value") == "") |
||||
|
||||
urlInput.sendKeys("w") |
||||
driver.waitTextToBe(value = "w") |
||||
|
||||
check(urlInput.getAttribute("value") == "w") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun hardcodedDateInputNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("hardcodedDateInputNeverChanges") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val dateInput = driver.findElement(By.id("dateInput")) |
||||
check(dateInput.getAttribute("value") == "") |
||||
|
||||
driver.sendKeysForDateInput(dateInput, 2021, 10, 22) |
||||
|
||||
driver.waitTextToBe(value = "onInput Caught") |
||||
check(dateInput.getAttribute("value") == "") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun mutableDateInputChanges(driver: WebDriver) { |
||||
// We skip chrome, since for some reason `sendKeys` doesn't work as expected when used for Controlled Input in Chrome |
||||
Assumptions.assumeTrue( |
||||
driver !is ChromeDriver, |
||||
"chrome driver doesn't work properly when using sendKeys on Controlled Input" |
||||
) |
||||
|
||||
driver.openTestPage("mutableDateInputChanges") |
||||
driver.waitTextToBe(value = "") |
||||
|
||||
val dateInput = driver.findElement(By.id("dateInput")) |
||||
check(dateInput.getAttribute("value") == "") |
||||
|
||||
driver.sendKeysForDateInput(dateInput, 2021, 10, 22) |
||||
|
||||
driver.waitTextToBe(value = "2021-10-22") |
||||
check(dateInput.getAttribute("value") == "2021-10-22") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun hardcodedTimeNeverChanges(driver: WebDriver) { |
||||
driver.openTestPage("hardcodedTimeNeverChanges") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val timeInput = driver.findElement(By.id("time")) |
||||
check(timeInput.getAttribute("value") == "14:00") |
||||
|
||||
timeInput.sendKeys("18:31") |
||||
|
||||
driver.waitTextToBe(value = "onInput Caught") |
||||
check(timeInput.getAttribute("value") == "14:00") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun mutableTimeChanges(driver: WebDriver) { |
||||
// We skip chrome, since for some reason `sendKeys` doesn't work as expected when used for Controlled Input in Chrome |
||||
Assumptions.assumeTrue( |
||||
driver !is ChromeDriver, |
||||
"chrome driver doesn't work properly when using sendKeys on Controlled Input" |
||||
) |
||||
|
||||
driver.openTestPage("mutableTimeChanges") |
||||
driver.waitTextToBe(value = "") |
||||
|
||||
val timeInput = driver.findElement(By.id("time")) |
||||
check(timeInput.getAttribute("value") == "") |
||||
|
||||
timeInput.sendKeys("18:31") |
||||
|
||||
driver.waitTextToBe(value = "18:31") |
||||
check(timeInput.getAttribute("value") == "18:31") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun timeInputSendKeysOnChromeFailingTest(driver: WebDriver) { |
||||
Assumptions.assumeTrue( |
||||
driver is ChromeDriver, |
||||
"this a `failing test for Chrome only` to catch when issue with sendKeys is resolved" |
||||
) |
||||
driver.openTestPage("mutableTimeChanges") |
||||
driver.waitTextToBe(value = "") |
||||
|
||||
val timeInput = driver.findElement(By.id("time")) |
||||
|
||||
timeInput.sendKeys("18:31") |
||||
driver.waitTextToBe(value = "18:03") // it should be 18:31, but this is a failing test, so wrong value is expected |
||||
} |
||||
} |
@ -0,0 +1,208 @@
|
||||
/* |
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. |
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. |
||||
*/ |
||||
|
||||
package org.jetbrains.compose.web.tests.integration |
||||
|
||||
import org.jetbrains.compose.web.tests.integration.common.BaseIntegrationTests |
||||
import org.jetbrains.compose.web.tests.integration.common.ResolveDrivers |
||||
import org.jetbrains.compose.web.tests.integration.common.openTestPage |
||||
import org.jetbrains.compose.web.tests.integration.common.waitTextToBe |
||||
import org.openqa.selenium.By |
||||
import org.openqa.selenium.Keys |
||||
import org.openqa.selenium.WebDriver |
||||
|
||||
class UncontrolledInputsTests : BaseIntegrationTests() { |
||||
|
||||
@ResolveDrivers |
||||
fun textInputDefaultValueRemainsTheSameButValueCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("textInputDefaultValueRemainsTheSameButValueCanBeChanged") |
||||
|
||||
val input = driver.findElement(By.id("textInput")) |
||||
check(input.getAttribute("value") == "defaultInputValue") |
||||
|
||||
input.sendKeys("-TypedText") |
||||
|
||||
val inputHtml = driver.outerHtmlOfElementWithId("textInput") |
||||
|
||||
check(inputHtml.contains("value=\"defaultInputValue\"")) |
||||
check(input.getAttribute("value") == "defaultInputValue-TypedText") // this checks the `value` property of the input |
||||
check(input.getAttribute("data-input-value") == "defaultInputValue-TypedText") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun textAreaDefaultValueRemainsTheSameButValueCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("textAreaDefaultValueRemainsTheSameButValueCanBeChanged") |
||||
|
||||
val textArea = driver.findElement(By.id("textArea")) |
||||
check(textArea.getAttribute("value") == "defaultTextAreaValue") |
||||
|
||||
textArea.sendKeys("-TypedText") |
||||
|
||||
val innerTextOfTextArea = driver.outerHtmlOfElementWithId("textArea") |
||||
|
||||
check(innerTextOfTextArea.contains(">defaultTextAreaValue</")) // inner text keeps default value |
||||
check(textArea.getAttribute("value") == "defaultTextAreaValue-TypedText") // this checks the `value` property of the textarea |
||||
check(textArea.getAttribute("data-text-area-value") == "defaultTextAreaValue-TypedText") |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun checkBoxDefaultCheckedRemainsTheSameButCheckedCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("checkBoxDefaultCheckedRemainsTheSameButCheckedCanBeChanged") |
||||
|
||||
val checkbox = driver.findElement(By.id("checkbox")) |
||||
|
||||
val innerTextOfCheckbox1 = driver.outerHtmlOfElementWithId("checkbox") |
||||
check(innerTextOfCheckbox1.contains("checked")) |
||||
check(checkbox.getAttribute("value") == "checkbox-value") |
||||
check(checkbox.getAttribute("data-checkbox") == "true") |
||||
check(checkbox.isSelected) |
||||
|
||||
checkbox.click() |
||||
|
||||
val innerTextOfCheckbox2 = driver.outerHtmlOfElementWithId("checkbox") |
||||
check(innerTextOfCheckbox2.contains("checked")) |
||||
check(checkbox.getAttribute("value") == "checkbox-value") |
||||
check(checkbox.getAttribute("data-checkbox") == "false") |
||||
check(!checkbox.isSelected) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun radioDefaultCheckedRemainsTheSameButCheckedCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("radioDefaultCheckedRemainsTheSameButCheckedCanBeChanged") |
||||
|
||||
val radio1 = driver.findElement(By.id("radio1")) |
||||
val radio2 = driver.findElement(By.id("radio2")) |
||||
|
||||
check(radio1.isSelected) |
||||
check(!radio2.isSelected) |
||||
|
||||
check(driver.outerHtmlOfElementWithId("radio1").contains("checked")) |
||||
check(!driver.outerHtmlOfElementWithId("radio2").contains("checked")) |
||||
|
||||
radio2.click() |
||||
|
||||
check(!radio1.isSelected) |
||||
check(radio2.isSelected) |
||||
|
||||
check(driver.outerHtmlOfElementWithId("radio1").contains("checked")) |
||||
check(!driver.outerHtmlOfElementWithId("radio2").contains("checked")) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun numberDefaultValueRemainsTheSameButValueCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("numberDefaultValueRemainsTheSameButValueCanBeChanged") |
||||
driver.waitTextToBe(value = "Value = None") |
||||
|
||||
val numberInput = driver.findElement(By.id("numberInput")) |
||||
check(numberInput.getAttribute("value") == "11") |
||||
|
||||
numberInput.sendKeys("5") |
||||
driver.waitTextToBe(value = "Value = 511") |
||||
|
||||
check(numberInput.getAttribute("value") == "511") |
||||
check(driver.outerHtmlOfElementWithId("numberInput").contains("value=\"11\"")) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun rangeDefaultValueRemainsTheSameButValueCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("rangeDefaultValueRemainsTheSameButValueCanBeChanged") |
||||
driver.waitTextToBe(value = "Value = None") |
||||
|
||||
val numberInput = driver.findElement(By.id("rangeInput")) |
||||
check(numberInput.getAttribute("value") == "7") |
||||
|
||||
numberInput.sendKeys(Keys.ARROW_RIGHT) |
||||
driver.waitTextToBe(value = "Value = 8") |
||||
|
||||
numberInput.sendKeys(Keys.ARROW_RIGHT) |
||||
driver.waitTextToBe(value = "Value = 9") |
||||
|
||||
check(numberInput.getAttribute("value") == "9") |
||||
check(driver.outerHtmlOfElementWithId("rangeInput").contains("value=\"7\"")) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun emailDefaultValueRemainsTheSameButValueCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("emailDefaultValueRemainsTheSameButValueCanBeChanged") |
||||
driver.waitTextToBe(value = "Value = None") |
||||
|
||||
val emailInput = driver.findElement(By.id("emailInput")) |
||||
check(emailInput.getAttribute("value") == "a@a.abc") |
||||
|
||||
emailInput.clear() |
||||
emailInput.sendKeys("u@u.com") |
||||
|
||||
driver.waitTextToBe(value = "Value = u@u.com") |
||||
check(emailInput.getAttribute("value") == "u@u.com") |
||||
|
||||
check(driver.outerHtmlOfElementWithId("emailInput").contains("value=\"a@a.abc\"")) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun passwordDefaultValueRemainsTheSameButValueCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("passwordDefaultValueRemainsTheSameButValueCanBeChanged") |
||||
driver.waitTextToBe(value = "Value = None") |
||||
|
||||
val passwordInput = driver.findElement(By.id("passwordInput")) |
||||
check(passwordInput.getAttribute("value") == "1111") |
||||
|
||||
passwordInput.clear() |
||||
passwordInput.sendKeys("a") |
||||
|
||||
driver.waitTextToBe(value = "Value = a") |
||||
check(passwordInput.getAttribute("value") == "a") |
||||
|
||||
check(driver.outerHtmlOfElementWithId("passwordInput").contains("value=\"1111\"")) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun searchDefaultValueRemainsTheSameButValueCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("searchDefaultValueRemainsTheSameButValueCanBeChanged") |
||||
driver.waitTextToBe(value = "Value = None") |
||||
|
||||
val searchInput = driver.findElement(By.id("searchInput")) |
||||
check(searchInput.getAttribute("value") == "kotlin") |
||||
|
||||
searchInput.clear() |
||||
searchInput.sendKeys("j") |
||||
driver.waitTextToBe(value = "Value = j") |
||||
|
||||
check(searchInput.getAttribute("value") == "j") |
||||
|
||||
check(driver.outerHtmlOfElementWithId("searchInput").contains("value=\"kotlin\"")) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun telDefaultValueRemainsTheSameButValueCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("telDefaultValueRemainsTheSameButValueCanBeChanged") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val telInput = driver.findElement(By.id("telInput")) |
||||
check(telInput.getAttribute("value") == "123123") |
||||
|
||||
telInput.clear() |
||||
telInput.sendKeys("987654321") |
||||
|
||||
driver.waitTextToBe(value = "987654321") |
||||
check(telInput.getAttribute("value") == "987654321") |
||||
check(driver.outerHtmlOfElementWithId("telInput").contains("value=\"123123\"")) |
||||
} |
||||
|
||||
@ResolveDrivers |
||||
fun urlDefaultValueRemainsTheSameButValueCanBeChanged(driver: WebDriver) { |
||||
driver.openTestPage("urlDefaultValueRemainsTheSameButValueCanBeChanged") |
||||
driver.waitTextToBe(value = "None") |
||||
|
||||
val urlInput = driver.findElement(By.id("urlInput")) |
||||
check(urlInput.getAttribute("value") == "www.site.com") |
||||
|
||||
urlInput.clear() |
||||
urlInput.sendKeys("google.com") |
||||
|
||||
driver.waitTextToBe(value = "google.com") |
||||
check(urlInput.getAttribute("value") == "google.com") |
||||
check(driver.outerHtmlOfElementWithId("urlInput").contains("value=\"www.site.com\"")) |
||||
} |
||||
} |
Loading…
Reference in new issue