-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Fixes: vaadin/vaadin-select#265 Warranty: Fixes client-side select overriding validation state from server Co-authored-by: Tulio Garcia <[email protected]> Co-authored-by: Tulio Garcia <[email protected]> (cherry picked from commit 14676de)
- Loading branch information
1 parent
7f5ef29
commit 69923d1
Showing
7 changed files
with
330 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
...src/main/java/com/vaadin/flow/component/select/examples/OverrideClientValidationPage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* Copyright 2000-2021 Vaadin Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. | ||
* | ||
*/ | ||
|
||
package com.vaadin.flow.component.select.examples; | ||
|
||
import com.vaadin.flow.component.grid.Grid; | ||
import com.vaadin.flow.component.html.Div; | ||
import com.vaadin.flow.component.html.H1; | ||
import com.vaadin.flow.component.html.NativeButton; | ||
import com.vaadin.flow.component.html.Span; | ||
import com.vaadin.flow.component.select.Select; | ||
import com.vaadin.flow.data.renderer.ComponentRenderer; | ||
import com.vaadin.flow.router.Route; | ||
|
||
@Route("vaadin-select/override-client-validation") | ||
public class OverrideClientValidationPage extends Div { | ||
|
||
public static final String ID_BASIC_SELECT = "basic-select"; | ||
public static final String ID_BASIC_SELECT_RESULT_SPAN = "basic-select-result-span"; | ||
public static final String ID_SET_INVALID_BUTTON = "set-invalid-button"; | ||
public static final String ID_LOG_BUTTON = "log-button"; | ||
public static final String ID_DETACH_BUTTON = "detach-button"; | ||
public static final String ID_REATTACH_BUTTON = "reattach-button"; | ||
|
||
private Select<String> basicSelect; | ||
private Span basicSelectResultSpan; | ||
private Select<String> selectInGrid; | ||
|
||
public OverrideClientValidationPage() { | ||
createBasicSetup(); | ||
createGridSetup(); | ||
createActions(); | ||
} | ||
|
||
private void createBasicSetup() { | ||
basicSelect = new Select<>("a", "b", "c"); | ||
basicSelect.setId(ID_BASIC_SELECT); | ||
|
||
basicSelectResultSpan = new Span(); | ||
basicSelectResultSpan.setId(ID_BASIC_SELECT_RESULT_SPAN); | ||
|
||
add(new H1("Basic select usage"), basicSelect, basicSelectResultSpan); | ||
} | ||
|
||
private void createGridSetup() { | ||
selectInGrid = new Select<>(); | ||
Grid<String> grid = new Grid<>(); | ||
grid.setItems("test"); | ||
grid.addColumn(new ComponentRenderer<>(item -> selectInGrid, | ||
(component, item) -> component)); | ||
add(new H1("Grid select usage"), grid); | ||
} | ||
|
||
private void createActions() { | ||
NativeButton setInvalidButton = new NativeButton("Set all invalid", | ||
e -> { | ||
basicSelect.setInvalid(true); | ||
selectInGrid.setInvalid(true); | ||
}); | ||
setInvalidButton.setId(ID_SET_INVALID_BUTTON); | ||
|
||
NativeButton logButton = new NativeButton("Log validation state", | ||
e -> basicSelectResultSpan.setText( | ||
basicSelect.isInvalid() ? "invalid" : "valid")); | ||
logButton.setId(ID_LOG_BUTTON); | ||
|
||
NativeButton detachButton = new NativeButton("Detach select", | ||
e -> this.remove(basicSelect)); | ||
detachButton.setId(ID_DETACH_BUTTON); | ||
|
||
NativeButton reattachButton = new NativeButton("Reattach select", | ||
e -> this.addComponentAsFirst(basicSelect)); | ||
reattachButton.setId(ID_REATTACH_BUTTON); | ||
|
||
addComponentAsFirst(new Div(setInvalidButton, logButton, detachButton, | ||
reattachButton)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
138 changes: 138 additions & 0 deletions
138
...tests/src/test/java/com/vaadin/flow/component/select/test/OverrideClientValidationIT.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/* | ||
* Copyright 2000-2021 Vaadin Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. | ||
* | ||
*/ | ||
|
||
package com.vaadin.flow.component.select.test; | ||
|
||
import com.vaadin.flow.component.grid.testbench.GridElement; | ||
import com.vaadin.flow.component.select.examples.OverrideClientValidationPage; | ||
import com.vaadin.flow.component.select.testbench.SelectElement; | ||
import com.vaadin.flow.testutil.TestPath; | ||
import com.vaadin.testbench.TestBenchElement; | ||
import com.vaadin.tests.AbstractComponentIT; | ||
import org.junit.Assert; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
@TestPath("vaadin-select/override-client-validation") | ||
public class OverrideClientValidationIT extends AbstractComponentIT { | ||
|
||
private SelectElement basicSelectElement; | ||
private TestBenchElement setInvalidButton; | ||
private TestBenchElement logButton; | ||
private TestBenchElement detachButton; | ||
private TestBenchElement reattachButton; | ||
private TestBenchElement basicSelectResultSpan; | ||
private SelectElement selectInGridElement; | ||
|
||
@Before | ||
public void setUp() { | ||
open(); | ||
basicSelectElement = $(SelectElement.class) | ||
.id(OverrideClientValidationPage.ID_BASIC_SELECT); | ||
setInvalidButton = $("button") | ||
.id(OverrideClientValidationPage.ID_SET_INVALID_BUTTON); | ||
logButton = $("button").id(OverrideClientValidationPage.ID_LOG_BUTTON); | ||
detachButton = $("button") | ||
.id(OverrideClientValidationPage.ID_DETACH_BUTTON); | ||
reattachButton = $("button") | ||
.id(OverrideClientValidationPage.ID_REATTACH_BUTTON); | ||
basicSelectResultSpan = $("span") | ||
.id(OverrideClientValidationPage.ID_BASIC_SELECT_RESULT_SPAN); | ||
GridElement gridElement = $(GridElement.class).first(); | ||
selectInGridElement = gridElement.$(SelectElement.class).first(); | ||
} | ||
|
||
@Test | ||
public void testTriggeringClientValidationShouldNotOverrideClientValidationState() { | ||
// Set server state to invalid | ||
setInvalidButton.click(); | ||
assertClientSideSelectValidationState(basicSelectElement, false); | ||
|
||
// Trigger client side validation | ||
triggerClientSideValidation(basicSelectElement); | ||
// Client side state should still be invalid | ||
assertClientSideSelectValidationState(basicSelectElement, false); | ||
} | ||
|
||
@Test | ||
public void testModifyingClientSideValidationStateShouldNotAffectServerSideValidationState() { | ||
// Set server state to invalid | ||
setInvalidButton.click(); | ||
logButton.click(); | ||
Assert.assertEquals("invalid", basicSelectResultSpan.getText()); | ||
|
||
// Overwrite client side validation state to be valid | ||
overwriteClientSideValidationState(basicSelectElement, true); | ||
// Server state should still be invalid | ||
logButton.click(); | ||
Assert.assertEquals("invalid", basicSelectResultSpan.getText()); | ||
} | ||
|
||
@Test | ||
public void testDetachingAndReattachingShouldStillOverrideClientValidation() { | ||
// Set server state to invalid | ||
setInvalidButton.click(); | ||
assertClientSideSelectValidationState(basicSelectElement, false); | ||
|
||
// Detach and reattach | ||
detachButton.click(); | ||
reattachButton.click(); | ||
// Need to refresh Selenium reference | ||
basicSelectElement = $(SelectElement.class) | ||
.id(OverrideClientValidationPage.ID_BASIC_SELECT); | ||
|
||
// Client side state should still be invalid after reattaching | ||
assertClientSideSelectValidationState(basicSelectElement, false); | ||
|
||
// Trigger client side validation after reattaching | ||
triggerClientSideValidation(basicSelectElement); | ||
// Client side state should still be invalid after reattaching and | ||
// triggering validation | ||
assertClientSideSelectValidationState(basicSelectElement, false); | ||
} | ||
|
||
@Test | ||
public void testTriggeringClientValidationShouldNotOverrideClientValidationStateWhenUsedInComponentRenderer() { | ||
// Set server state to invalid | ||
setInvalidButton.click(); | ||
assertClientSideSelectValidationState(selectInGridElement, false); | ||
|
||
triggerClientSideValidation(selectInGridElement); | ||
|
||
assertClientSideSelectValidationState(selectInGridElement, false); | ||
} | ||
|
||
private void assertClientSideSelectValidationState( | ||
SelectElement selectElement, boolean valid) { | ||
Boolean validationState = selectElement.getPropertyBoolean("invalid"); | ||
|
||
Assert.assertEquals("Validation state did not match", !valid, | ||
validationState); | ||
} | ||
|
||
private void triggerClientSideValidation(SelectElement selectElement) { | ||
selectElement.getCommandExecutor() | ||
.executeScript("arguments[0].validate()", selectElement); | ||
getCommandExecutor().waitForVaadin(); | ||
} | ||
|
||
private void overwriteClientSideValidationState(SelectElement selectElement, | ||
boolean valid) { | ||
selectElement.setProperty("invalid", !valid); | ||
getCommandExecutor().waitForVaadin(); | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
...aadin-select-flow/src/main/java/com/vaadin/flow/component/select/FieldValidationUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* Copyright 2000-2019 Vaadin Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
package com.vaadin.flow.component.select; | ||
|
||
import com.vaadin.flow.internal.StateNode; | ||
|
||
/** | ||
* Utility class for select Flow component to disable client side validation. | ||
* | ||
* @author Vaadin Ltd | ||
*/ | ||
final class FieldValidationUtil { | ||
|
||
private FieldValidationUtil() { | ||
// utility class should not be instantiated | ||
} | ||
|
||
static void disableClientValidation(Select component) { | ||
// Since this method should be called for every time when the component | ||
// is attached to the UI, lets check that it is actually so | ||
if (!component.isAttached()) { | ||
throw new IllegalStateException(String.format( | ||
"Component %s is not attached. Client side " | ||
+ "validation can only be disabled for a component " | ||
+ "when it has been attached to the UI and because " | ||
+ "it should be called again once the component is " | ||
+ "removed/added, you should call this method from " | ||
+ "the onAttach() method of the component.", | ||
component.toString())); | ||
} | ||
// Wait until the response is being written as the validation state | ||
// should not change after that | ||
final StateNode componentNode = component.getElement().getNode(); | ||
componentNode.runWhenAttached(ui -> ui.getInternals().getStateTree() | ||
.beforeClientResponse(componentNode, | ||
executionContext -> overrideClientValidation( | ||
component))); | ||
} | ||
|
||
private static void overrideClientValidation(Select component) { | ||
// Overwrite client validation method to simply return validation state | ||
// set from server | ||
StringBuilder expression = new StringBuilder( | ||
"this.validate = function () {return !this.invalid;};"); | ||
|
||
if (component.isInvalid()) { | ||
/* | ||
* By default the invalid flag is set to false. Workaround the case | ||
* where the client side validation overrides the invalid state | ||
* before the validation function itself is overridden above. | ||
*/ | ||
expression.append("this.invalid = true;"); | ||
} | ||
component.getElement().executeJs(expression.toString()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters