Skip to content

Commit

Permalink
Implement _setValue() which pretends that the value came from the client
Browse files Browse the repository at this point in the history
  • Loading branch information
mvysny committed Apr 15, 2024
1 parent 98a9bcc commit 404364f
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 5 deletions.
Expand Up @@ -35,6 +35,18 @@ class HasValueUtils {
HasValueUtilsKt.set_value(self, value)
}

/**
* Sets the value of given component, but only if it is actually possible to do so by the user.
* If the component is read-only or disabled, an exception is thrown.
* <p></p>
* The function fires the value change event; the {@link HasValue.ValueChangeEvent#isFromClient()} will
* mirror the <code>fromClient</code> parameter which defaults to `true` indicating that the event came from the client.
* @throws IllegalStateException if the field was not visible, not enabled or was read-only.
*/
static <V> void _setValue(@NotNull HasValue<?, V> self, @Nullable V value, boolean fromClient = true) {
HasValueUtilsKt._setValue(self, value, fromClient)
}

/**
* Fires a value change event which "comes from the client".
* <p></p>
Expand Down
8 changes: 5 additions & 3 deletions karibu-testing-v10/README.md
Expand Up @@ -952,11 +952,13 @@ all the above items prior setting the new value:
* Java: `LocatorJ._setValue(textField, "42");`

Changing the value fires the ValueChangeEvent with `isFromClient` set to false.
However, sometimes you need to fire a "client-side"/"isfromuser" value-change event,
However, sometimes you need to fire a "client-side"/"isfromuser"/"userOriginated" value-change event,
to test a code reacting to such events. In such case please use:

* Kotlin, Groovy: `textField._fireValueChange()`
* Java: `LocatorJ._fireValueChange(textField)`
* Kotlin, Groovy: `textField._fireValueChange()` is able to fire value change event with `isFromClient` set to true.
* Java: `LocatorJ._fireValueChange(textField)`
* Better: `textField._setValue("foo")` sets the value as if changed by the client.
* Java: `LocatorJ._setValue(textField, "foo", true);`

### Firing DOM Events

Expand Down
Expand Up @@ -86,5 +86,29 @@ internal fun DynaNodeGroup.hasValueTestbatch() {
tf._fireValueChange()
expect(true) { called }
}
group("from client") {
test("TextField") {
val tf = TextField()
var called = false
tf.addValueChangeListener {
expect(false) { called }
expect(true) { it.isFromClient }
called = true
}
tf._setValue("foo")
expect(true) { called }
}
test("CheckBox") {
val tf = Checkbox()
var called = false
tf.addValueChangeListener {
expect(false) { called }
expect(true) { it.isFromClient }
called = true
}
tf._setValue(true)
expect(true) { called }
}
}
}
}
Expand Up @@ -112,6 +112,18 @@ public static <V> void _setValue(@NotNull HasValue<?, V> receiver, @Nullable V v
HasValueUtilsKt.set_value(receiver, value);
}

/**
* Sets the value of given component, but only if it is actually possible to do so by the user.
* If the component is read-only or disabled, an exception is thrown.
* <p></p>
* The function fires the value change event; the {@link HasValue.ValueChangeEvent#isFromClient()} will
* mirror the <code>fromClient</code> parameter.
* @throws IllegalStateException if the field was not visible, not enabled or was read-only.
*/
static <V> void _setValue(@NotNull HasValue<?, V> self, @Nullable V value, boolean fromClient) {
HasValueUtilsKt._setValue(self, value, fromClient);
}

/**
* Fires a value change event which "comes from the client".
* <p></p>
Expand Down
Expand Up @@ -3,14 +3,15 @@ package com.github.mvysny.kaributesting.v10
import com.vaadin.flow.component.AbstractField
import com.vaadin.flow.component.Component
import com.vaadin.flow.component.HasValue
import com.vaadin.flow.component.internal.AbstractFieldSupport

/**
* Sets the value of given component, but only if it is actually possible to do so by the user.
* If the component is read-only or disabled, an exception is thrown.
*
* Modification of this property fires the value change event; the [HasValue.ValueChangeEvent.isFromClient] will
* return `false` indicating that the event came from the server. If this is not desired,
* depending on your code, it may be
* return `false` indicating that the event came from the server. If this is not desired, use [_setValue];
* alternatively it may be
* possible to call [_fireValueChange] with `fromClient=true` instead.
* @throws IllegalStateException if the field was not visible, not enabled or was read-only.
*/
Expand All @@ -21,6 +22,30 @@ public var <V> HasValue<*, V>._value: V?
value = v
}

public val <T> AbstractField<*, T>._fieldSupport: AbstractFieldSupport<*, T> get() {
val f = AbstractField::class.java.getDeclaredField("fieldSupport")
f.isAccessible = true
@Suppress("UNCHECKED_CAST")
return f.get(this) as AbstractFieldSupport<*, T>
}

/**
* Sets the value of given component, but only if it is actually possible to do so by the user.
* If the component is read-only or disabled, an exception is thrown.
*
* Modification of this property fires the value change event; the [HasValue.ValueChangeEvent.isFromClient] will
* mirror the [fromClient] parameter which defaults to `true` indicating that the event came from the client.
* @throws IllegalStateException if the field was not visible, not enabled or was read-only.
*/
@JvmOverloads
public fun <V> HasValue<*, V>._setValue(value: V?, fromClient: Boolean = true) {
(this as Component)._expectEditableByUser()
val fs = (this as AbstractField<*, V>)._fieldSupport
val m = AbstractFieldSupport::class.java.getDeclaredMethod("setValue", Any::class.java, Boolean::class.java, Boolean::class.java)
m.isAccessible = true
m.invoke(fs, value, false, fromClient)
}

/**
* Fires a value change event which "comes from the client".
*
Expand Down

0 comments on commit 404364f

Please sign in to comment.