summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/main/java/com/vaadin/client/ui/composite/CompositeConnector.java90
-rw-r--r--server/src/main/java/com/vaadin/ui/ComponentRootSetter.java54
-rw-r--r--server/src/main/java/com/vaadin/ui/Composite.java339
-rw-r--r--server/src/test/java/com/vaadin/tests/server/component/StateGetDoesNotMarkDirtyTest.java16
-rw-r--r--shared/src/main/java/com/vaadin/shared/composite/CompositeState.java27
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/composite/CompositeChainUI.java97
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/composite/CompositeChainUITest.java55
7 files changed, 677 insertions, 1 deletions
diff --git a/client/src/main/java/com/vaadin/client/ui/composite/CompositeConnector.java b/client/src/main/java/com/vaadin/client/ui/composite/CompositeConnector.java
new file mode 100644
index 0000000000..ad5e019b6b
--- /dev/null
+++ b/client/src/main/java/com/vaadin/client/ui/composite/CompositeConnector.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2016 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.client.ui.composite;
+
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ConnectorHierarchyChangeEvent;
+import com.vaadin.client.HasComponentsConnector;
+import com.vaadin.client.ui.AbstractHasComponentsConnector;
+import com.vaadin.shared.AbstractComponentState;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.Connect.LoadStyle;
+import com.vaadin.ui.Composite;
+
+@Connect(value = Composite.class, loadStyle = LoadStyle.EAGER)
+public class CompositeConnector extends AbstractHasComponentsConnector {
+
+ private ComponentConnector childConnector;
+
+ @Override
+ protected Widget createWidget() {
+ throw new UnsupportedOperationException(
+ "Composite has no widget of its own");
+ }
+
+ private boolean hasChildConnector() {
+ return getChildConnector() != null;
+ }
+
+ private ComponentConnector getChildConnector() {
+ // Must store the child connector to have it available when removing the
+ // connector
+ if (childConnector == null && !getChildren().isEmpty()) {
+ childConnector = (ComponentConnector) getChildren().get(0);
+ }
+ return childConnector;
+ }
+
+ @Override
+ public Widget getWidget() {
+ if (!hasChildConnector()) {
+ // This happens in doInit for instance when setConnectorId is called
+ return new Label("This widget should not end up anywhere ever");
+ } else {
+ return getChildConnector().getWidget();
+ }
+ }
+
+ @Override
+ public HasComponentsConnector getParent() {
+ return (HasComponentsConnector) super.getParent();
+ }
+
+ @Override
+ public void updateCaption(ComponentConnector component) {
+ // Parent might assume that the connector is always a child connector,
+ // therefore passing "this" instead of the child connector. The child
+ // caption will be returned as getState() returns the child's state.
+ getParent().updateCaption(this);
+ }
+
+ @Override
+ public AbstractComponentState getState() {
+ if (!hasChildConnector()) {
+ return new AbstractComponentState();
+ } else {
+ return getChildConnector().getState();
+ }
+ }
+
+ @Override
+ public void onConnectorHierarchyChange(
+ ConnectorHierarchyChangeEvent event) {
+ // Handled in getChildConnector
+ }
+}
diff --git a/server/src/main/java/com/vaadin/ui/ComponentRootSetter.java b/server/src/main/java/com/vaadin/ui/ComponentRootSetter.java
new file mode 100644
index 0000000000..1bc3565de8
--- /dev/null
+++ b/server/src/main/java/com/vaadin/ui/ComponentRootSetter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2016 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.ui;
+
+import java.io.Serializable;
+
+/**
+ * Internal utility class.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class ComponentRootSetter implements Serializable {
+
+ private ComponentRootSetter() {
+ // Util methods only
+ }
+
+ /**
+ * Sets the composition root for the given custom component or composite.
+ * <p>
+ * For internal use only.
+ *
+ * @param customComponent
+ * the custom component or composite
+ * @param component
+ * the component to assign as composition root
+ */
+ public static void setRoot(Component customComponent, Component component) {
+ if (customComponent instanceof CustomComponent) {
+ ((CustomComponent) customComponent).setCompositionRoot(component);
+ } else if (customComponent instanceof Composite) {
+ ((Composite) customComponent).setCompositionRoot(component);
+ } else {
+ throw new IllegalArgumentException(
+ "Parameter is of an unsupported type: "
+ + customComponent.getClass().getName());
+ }
+ }
+
+}
diff --git a/server/src/main/java/com/vaadin/ui/Composite.java b/server/src/main/java/com/vaadin/ui/Composite.java
new file mode 100644
index 0000000000..10bcff0510
--- /dev/null
+++ b/server/src/main/java/com/vaadin/ui/Composite.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2000-2016 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.ui;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+
+import com.vaadin.server.ErrorMessage;
+import com.vaadin.server.Resource;
+import com.vaadin.shared.composite.CompositeState;
+import com.vaadin.shared.ui.ContentMode;
+
+/**
+ * Composite allows creating new UI components by composition of existing
+ * server-side components.
+ * <p>
+ * A composite is created by extending the Composite class and setting the
+ * composition root component using {@link #setCompositionRoot(Component)}.
+ * </p>
+ * <p>
+ * The composition root itself can contain more components. The advantage of
+ * wrapping it in a composite is that the details of the composition root, such
+ * as its public API, are hidden from the users of the composite.
+ * </p>
+ * <p>
+ * A composite itself does not contribute to the DOM in any way (contrary to
+ * {@link CustomComponent} which adds a {@code <div>} to the DOM.
+ * </p>
+ *
+ * @author Vaadin Ltd.
+ * @since
+ */
+public class Composite extends AbstractComponent implements HasComponents {
+
+ private static final String COMPOSITE_HAS_NO_DOM_OR_WIDGET = "A composite has no DOM or widget";
+ /**
+ * The contained component.
+ */
+ private Component root = null;
+
+ /**
+ * Constructs a new empty composite.
+ * <p>
+ * Use {@link #setCompositionRoot(Component)} to define the contents of the
+ * composite.
+ */
+ public Composite() {
+ }
+
+ /**
+ * Constructs a new composite containing the given component.
+ *
+ * @param compositionRoot
+ * the root of the composition component tree. It must not be
+ * null.
+ */
+ public Composite(AbstractComponent compositionRoot) {
+ this();
+ Objects.requireNonNull(compositionRoot);
+ setCompositionRoot(compositionRoot);
+ }
+
+ /**
+ * Returns the composition root.
+ *
+ * @return the Component Composition root.
+ */
+ protected Component getCompositionRoot() {
+ return root;
+ }
+
+ /**
+ * Sets the component contained in the composite.
+ * <p>
+ * You must set the composition root to a non-null value before the
+ * component can be used. It cannot be changed.
+ * </p>
+ *
+ * @param compositionRoot
+ * the root of the composition component tree.
+ */
+ protected void setCompositionRoot(Component compositionRoot) {
+ if (root != null) {
+ throw new IllegalStateException(
+ "Composition root cannot be changed");
+ }
+ if (compositionRoot == null) {
+ throw new IllegalArgumentException(
+ "Composition root cannot be null");
+ }
+
+ // set new component
+ if (compositionRoot.getParent() != null) {
+ // If the component already has a parent, try to remove it
+ AbstractSingleComponentContainer.removeFromParent(compositionRoot);
+ }
+
+ compositionRoot.setParent(this);
+ root = compositionRoot;
+ markAsDirty();
+ }
+
+ /* Basic component features ------------------------------------------ */
+
+ @Override
+ public Iterator<Component> iterator() {
+ if (getCompositionRoot() != null) {
+ return Collections.singletonList(getCompositionRoot()).iterator();
+ } else {
+ return Collections.<Component> emptyList().iterator();
+ }
+ }
+
+ /**
+ * Gets the number of contained components.
+ *
+ * @return the number of contained components (zero or one)
+ */
+ public int getComponentCount() {
+ return (getCompositionRoot() != null ? 1 : 0);
+ }
+
+ @Override
+ protected CompositeState getState() {
+ return (CompositeState) super.getState();
+ }
+
+ @Override
+ protected CompositeState getState(boolean markAsDirty) {
+ return (CompositeState) super.getState(markAsDirty);
+ }
+
+ @Override
+ public void beforeClientResponse(boolean initial) {
+ super.beforeClientResponse(initial);
+ if (getComponentCount() != 1) {
+ throw new IllegalStateException(
+ "A composite must always have a composition root");
+ }
+ }
+
+ @Override
+ public String getStyleName() {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setStyleName(String style) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setStyleName(String style, boolean add) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void addStyleName(String style) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void removeStyleName(String style) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public String getPrimaryStyleName() {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setPrimaryStyleName(String style) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ private Component getRootOrThrow() {
+ return Optional.ofNullable(getCompositionRoot())
+ .orElseThrow(() -> new IllegalStateException(
+ "Composition root has not been set"));
+ }
+
+ @Override
+ public float getWidth() {
+ return getRootOrThrow().getWidth();
+ }
+
+ @Override
+ public float getHeight() {
+ return getRootOrThrow().getHeight();
+ }
+
+ @Override
+ public Unit getWidthUnits() {
+ return getRootOrThrow().getWidthUnits();
+ }
+
+ @Override
+ public Unit getHeightUnits() {
+ return getRootOrThrow().getHeightUnits();
+ }
+
+ @Override
+ public void setHeight(String height) {
+ getRootOrThrow().setHeight(height);
+ }
+
+ @Override
+ public void setWidth(float width, Unit unit) {
+ getRootOrThrow().setWidth(width, unit);
+ }
+
+ @Override
+ public void setHeight(float height, Unit unit) {
+ getRootOrThrow().setHeight(height, unit);
+ }
+
+ @Override
+ public void setWidth(String width) {
+ getRootOrThrow().setWidth(width);
+ }
+
+ @Override
+ public void setSizeFull() {
+ getRootOrThrow().setSizeFull();
+ }
+
+ @Override
+ public void setSizeUndefined() {
+ getRootOrThrow().setSizeUndefined();
+ }
+
+ @Override
+ public void setWidthUndefined() {
+ getRootOrThrow().setWidthUndefined();
+ }
+
+ @Override
+ public void setHeightUndefined() {
+ getRootOrThrow().setHeightUndefined();
+ }
+
+ @Override
+ public void setId(String id) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public String getId() {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setDebugId(String id) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public String getDebugId() {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public String getCaption() {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setCaption(String caption) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setCaptionAsHtml(boolean captionAsHtml) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public boolean isCaptionAsHtml() {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public Resource getIcon() {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setIcon(Resource icon) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public String getDescription() {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setDescription(String description) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setDescription(String description, ContentMode mode) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public ErrorMessage getErrorMessage() {
+ return null;
+ }
+
+ @Override
+ public ErrorMessage getComponentError() {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+ @Override
+ public void setComponentError(ErrorMessage componentError) {
+ throw new UnsupportedOperationException(COMPOSITE_HAS_NO_DOM_OR_WIDGET);
+ }
+
+}
diff --git a/server/src/test/java/com/vaadin/tests/server/component/StateGetDoesNotMarkDirtyTest.java b/server/src/test/java/com/vaadin/tests/server/component/StateGetDoesNotMarkDirtyTest.java
index 3b4c2413f9..29dd6638fa 100644
--- a/server/src/test/java/com/vaadin/tests/server/component/StateGetDoesNotMarkDirtyTest.java
+++ b/server/src/test/java/com/vaadin/tests/server/component/StateGetDoesNotMarkDirtyTest.java
@@ -17,6 +17,8 @@ import org.mockito.Mockito;
import com.vaadin.server.VaadinSession;
import com.vaadin.tests.VaadinClasses;
import com.vaadin.ui.Component;
+import com.vaadin.ui.ComponentRootSetter;
+import com.vaadin.ui.Composite;
import com.vaadin.ui.ConnectorTracker;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
@@ -75,7 +77,16 @@ public class StateGetDoesNotMarkDirtyTest {
}
// just to make sure we can invoke it
method.setAccessible(true);
- method.invoke(newInstance);
+ try {
+ method.invoke(newInstance);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof UnsupportedOperationException) {
+ // Overridden getter which is not supposed to be
+ // called
+ } else {
+ throw e;
+ }
+ }
}
} catch (Exception e) {
System.err.println("problem with method " + clazz.getName()
@@ -116,6 +127,9 @@ public class StateGetDoesNotMarkDirtyTest {
if (component instanceof UI) {
return component;
}
+ if (component instanceof Composite) {
+ ComponentRootSetter.setRoot(component, new Label());
+ }
emulateAttach(component);
return component;
} catch (NoSuchMethodException e) {
diff --git a/shared/src/main/java/com/vaadin/shared/composite/CompositeState.java b/shared/src/main/java/com/vaadin/shared/composite/CompositeState.java
new file mode 100644
index 0000000000..1f552390df
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/composite/CompositeState.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2016 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.shared.composite;
+
+import com.vaadin.shared.AbstractComponentState;
+
+/**
+ * Shared state for Composite.
+ *
+ * @author Vaadin Ltd
+ * @since
+ */
+public class CompositeState extends AbstractComponentState {
+}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/composite/CompositeChainUI.java b/uitest/src/main/java/com/vaadin/tests/components/composite/CompositeChainUI.java
new file mode 100644
index 0000000000..481f7c958f
--- /dev/null
+++ b/uitest/src/main/java/com/vaadin/tests/components/composite/CompositeChainUI.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2000-2016 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.tests.components.composite;
+
+import java.util.Iterator;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Composite;
+import com.vaadin.ui.HasComponents;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.VerticalLayout;
+
+@Widgetset("com.vaadin.DefaultWidgetSet")
+public class CompositeChainUI extends AbstractTestUIWithLog {
+
+ private Label innermostComponent;
+ private Composite innerComposite;
+ private Composite outerComposite;
+ private VerticalLayout container;
+ private HorizontalLayout layout;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ createComposite();
+ layout = new HorizontalLayout(outerComposite);
+ container = new VerticalLayout(layout);
+ addComponent(container);
+
+ Button updateCaption = new Button("Update caption");
+ updateCaption.addClickListener(e -> {
+ innermostComponent
+ .setCaption(innermostComponent.getCaption() + " - updated");
+ });
+ addComponent(updateCaption);
+ Button replaceWithAnotherComposite = new Button(
+ "Replace with another Composite", e -> {
+ Composite oldOuter = outerComposite;
+ createComposite();
+ layout.replaceComponent(oldOuter, outerComposite);
+ });
+ addComponent(replaceWithAnotherComposite);
+ logHierarchy();
+ }
+
+ private void createComposite() {
+ innermostComponent = new Label("Label text");
+ innermostComponent.setCaption("Label caption");
+ innermostComponent.setId("innermost");
+
+ innerComposite = new Composite(innermostComponent);
+ outerComposite = new Composite(innerComposite);
+ }
+
+ private void logHierarchy() {
+ String msg = "Hierarchy: ";
+ if (container != null) {
+ msg += getHierarchy(container);
+ }
+ log(msg);
+ }
+
+ private static String getHierarchy(Component component) {
+ String msg = component.getClass().getSimpleName();
+ if (component instanceof HasComponents) {
+
+ Iterator<Component> iterator = ((HasComponents) component)
+ .iterator();
+ if (iterator.hasNext()) {
+ Component content = iterator.next();
+ if (content != null) {
+ msg += " -> " + getHierarchy(content);
+ }
+ }
+ }
+ return msg;
+ }
+
+}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/composite/CompositeChainUITest.java b/uitest/src/test/java/com/vaadin/tests/components/composite/CompositeChainUITest.java
new file mode 100644
index 0000000000..228d20f058
--- /dev/null
+++ b/uitest/src/test/java/com/vaadin/tests/components/composite/CompositeChainUITest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2016 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.tests.components.composite;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+public class CompositeChainUITest extends SingleBrowserTest {
+
+ @Test
+ public void compositeRenderedAndUpdatedCorrectly() {
+ openTestURL();
+ LabelElement label = $(LabelElement.class).id("innermost");
+ WebElement labelGrandParent = label.findElement(By.xpath("../.."));
+
+ Assert.assertEquals("v-slot", labelGrandParent.getAttribute("class"));
+ Assert.assertEquals("Label caption", label.getCaption());
+
+ $(ButtonElement.class).caption("Update caption").first().click();
+ Assert.assertEquals("Label caption - updated", label.getCaption());
+
+ }
+
+ @Test
+ public void compositeRemovedCorrectly() {
+ openTestURL("debug");
+ LabelElement label = $(LabelElement.class).id("innermost");
+ $(ButtonElement.class).caption("Update caption").first().click();
+ Assert.assertEquals("Label caption - updated", label.getCaption());
+ $(ButtonElement.class).caption("Replace with another Composite").first()
+ .click();
+ label = $(LabelElement.class).id("innermost");
+ Assert.assertEquals("Label caption", label.getCaption());
+ assertNoErrorNotifications();
+ }
+}
30'>backport/49489/stable30 Nextcloud server, a safe home for all your data: https://github.com/nextcloud/serverwww-data
summaryrefslogtreecommitdiffstats
path: root/apps/user_ldap/l10n/ur_PK.js
blob: 693a42b05439d98a5e873dc3518751ae7ea9e14e (plain)
1
2
3
4
5
6
7
8
9