This is an automated email from the ASF dual-hosted git repository. skylark17 pushed a commit to branch 2_1_X in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/2_1_X by this push: new f978c75 [SYNCOPE-1439] Fixed user membership attributes not updated in some cases f978c75 is described below commit f978c7532e36f6ab3e92e518fbc2514720a0c919 Author: skylark17 <matteo.alessandr...@tirasa.net> AuthorDate: Thu Mar 7 10:37:22 2019 +0100 [SYNCOPE-1439] Fixed user membership attributes not updated in some cases --- .../markup/html/form/AbstractMultiPanel.java | 1 + .../console/wizards/any/AnyWizardBuilder.java | 6 +- .../client/console/wizards/any/PlainAttrs.java | 148 +++++++++++--- .../apache/syncope/fit/console/UsersITCase.java | 213 +++++++++++++++++++++ 4 files changed, 344 insertions(+), 24 deletions(-) diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AbstractMultiPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AbstractMultiPanel.java index 6d3be21..925e8e6 100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AbstractMultiPanel.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AbstractMultiPanel.java @@ -60,6 +60,7 @@ public abstract class AbstractMultiPanel<INNER> extends AbstractFieldPanel<List< form = new Form<>("innerForm"); form.setDefaultButton(null); + form.setMultiPart(true); container.add(form); // ----------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java index 4076d77..3ba260e 100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java @@ -187,14 +187,15 @@ public abstract class AnyWizardBuilder<A extends AnyTO> extends AjaxWizardBuilde updated.getVirAttrs().add(virAttrTO); } } + if (updated instanceof GroupableRelatableTO && original instanceof GroupableRelatableTO) { GroupableRelatableTO.class.cast(original).getMemberships().forEach(oMemb -> { GroupableRelatableTO.class.cast(updated).getMembership(oMemb.getGroupKey()).ifPresent(uMemb -> { oMemb.getPlainAttrs().stream(). - filter(attr -> uMemb.getPlainAttr(attr.getSchema()).isPresent()). + filter(attr -> !uMemb.getPlainAttr(attr.getSchema()).isPresent()). forEach(attr -> uMemb.getPlainAttrs().add(attr)); oMemb.getVirAttrs().stream(). - filter(attr -> uMemb.getVirAttr(attr.getSchema()).isPresent()). + filter(attr -> !uMemb.getVirAttr(attr.getSchema()).isPresent()). forEach(attr -> uMemb.getVirAttrs().add(attr)); }); }); @@ -211,4 +212,5 @@ public abstract class AnyWizardBuilder<A extends AnyTO> extends AjaxWizardBuilde }); } } + } diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java index a9e1f90..804d5d9 100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java @@ -18,6 +18,7 @@ */ package org.apache.syncope.client.console.wizards.any; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -48,6 +49,7 @@ import org.apache.syncope.common.lib.SyncopeConstants; import org.apache.syncope.common.lib.to.AnyObjectTO; import org.apache.syncope.common.lib.to.AnyTO; import org.apache.syncope.common.lib.to.AttrTO; +import org.apache.syncope.common.lib.to.AttributableTO; import org.apache.syncope.common.lib.to.GroupTO; import org.apache.syncope.common.lib.to.GroupableRelatableTO; import org.apache.syncope.common.lib.to.MembershipTO; @@ -64,6 +66,7 @@ import org.apache.wicket.markup.html.form.IChoiceRenderer; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.model.IModel; +import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; @@ -113,7 +116,7 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> { @Override public WebMarkupContainer getPanel(final String panelId) { - return new PlainSchemas(panelId, schemas, attrTOs); + return new PlainSchemasOwn(panelId, schemas, attrTOs); } }), Model.of(0)).setOutputMarkupId(true)); @@ -134,10 +137,19 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> { @Override public WebMarkupContainer getPanel(final String panelId) { - return new PlainSchemas( + return new PlainSchemasMemberships( panelId, membershipSchemas.get(membershipTO.getGroupKey()), - new ListModel<>(getAttrsFromTO(membershipTO))); + new LoadableDetachableModel<AttributableTO>() { // SYNCOPE-1439 + + private static final long serialVersionUID = 526768546610546553L; + + @Override + protected AttributableTO load() { + return membershipTO; + } + + }); } }), Model.of(-1)).setOutputMarkupId(true)); } @@ -377,15 +389,88 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> { return panel; } - public class PlainSchemas extends Schemas { + protected class PlainSchemasMemberships extends PlainSchemas<AttributableTO> { + + private static final long serialVersionUID = 456754923340249215L; + + public PlainSchemasMemberships( + final String id, + final Map<String, PlainSchemaTO> schemas, + final IModel<AttributableTO> attributableTO) { + + super(id, schemas, attributableTO); + + add(new ListView<AttrTO>("schemas", + new ListModel<AttrTO>(new ArrayList<AttrTO>( + attributableTO.getObject().getPlainAttrs().stream().sorted(attrComparator). + collect(Collectors.toList())))) { + + private static final long serialVersionUID = 5306618783986001008L; + + @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected void populateItem(final ListItem<AttrTO> item) { + AttrTO attrTO = item.getModelObject(); + + AbstractFieldPanel<?> panel = getFieldPanel(schemas.get(attrTO.getSchema())); + if (mode == AjaxWizard.Mode.TEMPLATE + || !schemas.get(attrTO.getSchema()).isMultivalue()) { + + FieldPanel.class.cast(panel).setNewModel(new Model() { + + private static final long serialVersionUID = -4214654722524358000L; + + @Override + public Serializable getObject() { + return (!attributableTO.getObject().getPlainAttr(attrTO.getSchema()). + get().getValues().isEmpty()) + ? attributableTO.getObject().getPlainAttr(attrTO.getSchema()). + get().getValues().get(0) + : null; + } + + @Override + public void setObject(final Serializable object) { + attributableTO.getObject().getPlainAttr(attrTO.getSchema()).get().getValues().clear(); + if (object != null) { + attributableTO.getObject().getPlainAttr(attrTO.getSchema()). + get().getValues().add(object.toString()); + } + } + }); + } else { + panel = new MultiFieldPanel.Builder<>(new ListModel<String>() { + + private static final long serialVersionUID = -1765231556272935141L; + + @Override + public List<String> getObject() { + return attributableTO.getObject().getPlainAttr(attrTO.getSchema()).get().getValues(); + } + }).build("panel", + attrTO.getSchema(), + FieldPanel.class.cast(panel)); + // SYNCOPE-1215 the entire multifield panel must be readonly, not only its field + ((MultiFieldPanel) panel).setReadOnly(schemas.get(attrTO.getSchema()).isReadonly()); + } + item.add(panel); + + setExternalAction(attrTO, panel); + } + }); + } + } + + protected class PlainSchemasOwn extends PlainSchemas<List<AttrTO>> { private static final long serialVersionUID = -4730563859116024676L; - public PlainSchemas( + public PlainSchemasOwn( final String id, final Map<String, PlainSchemaTO> schemas, final IModel<List<AttrTO>> attrTOs) { - super(id); + + super(id, schemas, attrTOs); add(new ListView<AttrTO>("schemas", attrTOs) { @@ -399,6 +484,7 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> { AbstractFieldPanel<?> panel = getFieldPanel(schemas.get(attrTO.getSchema())); if (mode == AjaxWizard.Mode.TEMPLATE || !schemas.get(attrTO.getSchema()).isMultivalue()) { + FieldPanel.class.cast(panel).setNewModel(attrTO.getValues()); } else { panel = new MultiFieldPanel.Builder<>( @@ -411,24 +497,42 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> { } item.add(panel); - Optional<AttrTO> prevAttr = previousObject == null - ? Optional.empty() - : previousObject.getPlainAttr(attrTO.getSchema()); - if (previousObject != null - && ((!prevAttr.isPresent() && attrTO.getValues().stream().anyMatch(StringUtils::isNotBlank)) - || (prevAttr.isPresent() && !ListUtils.isEqualList( - prevAttr.get().getValues().stream(). - filter(StringUtils::isNotBlank).collect(Collectors.toList()), - attrTO.getValues().stream(). - filter(StringUtils::isNotBlank).collect(Collectors.toList()))))) { - - List<String> oldValues = prevAttr.isPresent() - ? prevAttr.get().getValues() - : Collections.<String>emptyList(); - panel.showExternAction(new LabelInfo("externalAction", oldValues)); - } + setExternalAction(attrTO, panel); } }); } } + + protected abstract class PlainSchemas<T> extends Schemas { + + private static final long serialVersionUID = 8315035592714180404L; + + public PlainSchemas( + final String id, + final Map<String, PlainSchemaTO> schemas, + final IModel<T> attrTOs) { + + super(id); + } + + protected void setExternalAction(final AttrTO attrTO, final AbstractFieldPanel<?> panel) { + Optional<AttrTO> prevAttr = previousObject == null + ? Optional.empty() + : previousObject.getPlainAttr(attrTO.getSchema()); + if (previousObject != null + && ((!prevAttr.isPresent() && attrTO.getValues().stream().anyMatch(StringUtils::isNotBlank)) + || (prevAttr.isPresent() && !ListUtils.isEqualList( + prevAttr.get().getValues().stream(). + filter(StringUtils::isNotBlank).collect(Collectors.toList()), + attrTO.getValues().stream(). + filter(StringUtils::isNotBlank).collect(Collectors.toList()))))) { + + List<String> oldValues = prevAttr.isPresent() + ? prevAttr.get().getValues() + : Collections.<String>emptyList(); + panel.showExternAction(new LabelInfo("externalAction", oldValues)); + } + } + } + } diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java index 6e18a45..691ec4e 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java @@ -58,6 +58,10 @@ public class UsersITCase extends AbstractConsoleITCase { "body:content:body:container:content:tabbedPanel:panel:accordionPanel:tabs:0:body:content:" + "searchFormContainer:search:multiValueContainer:innerForm:content:view:0:panel:container:value:" + "textField", TextField.class); + TESTER.assertComponent( + "body:content:body:container:content:tabbedPanel:panel:accordionPanel:tabs:0:body:content:" + + "searchFormContainer:search:multiValueContainer:innerForm:content:view:1:panel:container:value:" + + "textField", TextField.class); } @Test @@ -323,6 +327,215 @@ public class UsersITCase extends AbstractConsoleITCase { } @Test + public void editUserMemberships() { + TESTER.clickLink("body:realmsLI:realms"); + TESTER.executeAjaxEvent("body:content:realmChoicePanel:container:realms:btn", Constants.ON_CLICK); + TESTER.executeAjaxEvent("body:content:realmChoicePanel:container:realms:dropdown-menu:buttons:2:button", + Constants.ON_CLICK); + + TESTER.clickLink("body:content:body:container:content:tabbedPanel:tabs-container:tabs:1:link"); + + Component component = findComponentByProp("username", CONTAINER + + ":searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", "rossini"); + assertNotNull(component); + + // click on "edit" + TESTER.executeAjaxEvent(component.getPageRelativePath(), Constants.ON_CLICK); + TESTER.clickLink(TAB_PANEL + "outerObjectsRepeater:1:outer:container:content:togglePanelContainer:container:" + + "actions:actions:actionRepeater:0:action:action"); + + FormTester formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + formTester.submit("buttons:next"); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + formTester.submit("buttons:next"); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + + // add "additional" group in order to show membership attributes + formTester.setValue("view:groupsContainer:groups:paletteField:recorder", "additional,root,otherchild"); + TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:buttons:next", + Constants.ON_CLICK); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + + // open membership attributes accordion + TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:title", + Constants.ON_CLICK); + + // edit multivalue text field, set 2 elements in total + TESTER.assertComponent(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:" + + "body:content:schemas:5:panel:multiValueContainer:innerForm:content:view:0:panel:field", + TextField.class); + formTester.setValue("view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:body:content:" + + "schemas:5:panel:multiValueContainer:innerForm:content:view:0:panel:field", "2019-03-05"); + + TESTER.clickLink(TESTER.getComponentFromLastRenderedPage(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:" + + "body:content:schemas:5:panel:multiValueContainer:innerForm:content:view:0:panelPlus:add")); + + TESTER.assertComponent(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:" + + "body:content:schemas:5:panel:multiValueContainer:innerForm:content:view:1:panel:field", + TextField.class); + formTester.setValue("view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:body:content:" + + "schemas:5:panel:multiValueContainer:innerForm:content:view:1:panel:field", "2019-03-06"); + + TESTER.clickLink(TESTER.getComponentFromLastRenderedPage(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:" + + "body:content:schemas:5:panel:multiValueContainer:innerForm:content:view:1:panelPlus:add")); + + formTester.submit("buttons:next"); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + formTester.submit("buttons:finish"); + + TESTER.assertInfoMessages("Operation executed successfully"); + TESTER.cleanupFeedbackMessages(); + + TESTER.assertComponent(TAB_PANEL + + "outerObjectsRepeater:0:outer:form:content:customResultBody:resources:firstLevelContainer:first:" + + "container:content:group:beans:0:fields:1:field", Label.class); + + TESTER.clickLink(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:action:actionRepeater:0:action:action"); + + // reopen form and go to Plain Attributes page... + component = findComponentByProp("username", CONTAINER + + ":searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", "rossini"); + assertNotNull(component); + + TESTER.executeAjaxEvent(component.getPageRelativePath(), Constants.ON_CLICK); + TESTER.clickLink(TAB_PANEL + "outerObjectsRepeater:1:outer:container:content:togglePanelContainer:container:" + + "actions:actions:actionRepeater:0:action:action"); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + formTester.submit("buttons:next"); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + formTester.submit("buttons:next"); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + + // add "additional" group in order to show membership attributes + formTester.setValue("view:groupsContainer:groups:paletteField:recorder", "additional,root,otherchild"); + TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:buttons:next", + Constants.ON_CLICK); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + + // open membership attributes accordion + TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:title", + Constants.ON_CLICK); + + // ... check multivalue field values has been saved + TESTER.assertComponent(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:" + + "body:content:schemas:5:panel:multiValueContainer:innerForm:content:view:0:panel:field", + TextField.class); + + TESTER.assertComponent(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:" + + "body:content:schemas:5:panel:multiValueContainer:innerForm:content:view:1:panel:field", + TextField.class); + + Calendar cal = Calendar.getInstance(); + cal.set(2019, Calendar.MARCH, 5, 0, 0, 0); + cal.set(Calendar.MILLISECOND, 0); + Calendar cal2 = Calendar.getInstance(); + cal2.set(2019, Calendar.MARCH, 6, 0, 0, 0); + cal2.set(Calendar.MILLISECOND, 0); + TESTER.assertModelValue(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:body:content:" + + "schemas:5:panel:multiValueContainer:innerForm:content:view:0:panel:field", cal.getTime()); + TESTER.assertModelValue(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:body:content:" + + "schemas:5:panel:multiValueContainer:innerForm:content:view:1:panel:field", cal2.getTime()); + + // ... remove all values from multivalue field + TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:body:" + + "content:schemas:5:panel:multiValueContainer:innerForm:content:view:1:drop", + Constants.ON_CLICK); + TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:body:" + + "content:schemas:5:panel:multiValueContainer:innerForm:content:view:0:drop", + Constants.ON_CLICK); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + formTester.submit("buttons:finish"); + + TESTER.assertInfoMessages("Operation executed successfully"); + TESTER.cleanupFeedbackMessages(); + + TESTER.assertComponent(TAB_PANEL + + "outerObjectsRepeater:0:outer:form:content:customResultBody:resources:firstLevelContainer:first:" + + "container:content:group:beans:0:fields:1:field", Label.class); + + TESTER.clickLink(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:action:actionRepeater:0:action:action"); + + // reopen form and go to Plain Attributes page... + component = findComponentByProp("username", CONTAINER + + ":searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", "rossini"); + assertNotNull(component); + + TESTER.executeAjaxEvent(component.getPageRelativePath(), Constants.ON_CLICK); + TESTER.clickLink(TAB_PANEL + "outerObjectsRepeater:1:outer:container:content:togglePanelContainer:container:" + + "actions:actions:actionRepeater:0:action:action"); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + formTester.submit("buttons:next"); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + formTester.submit("buttons:next"); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + + // add "additional" group in order to show membership attributes + formTester.setValue("view:groupsContainer:groups:paletteField:recorder", "additional,root,otherchild"); + TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:buttons:next", + Constants.ON_CLICK); + + formTester = TESTER.newFormTester(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form"); + assertNotNull(formTester); + + // open membership attributes accordion + TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:title", + Constants.ON_CLICK); + + // ... check multivalue field is now empty + TESTER.assertModelValue(TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:body:content:" + + "schemas:5:panel:multiValueContainer:innerForm:content:view:0:panel:field", null); + component = findComponentByProp("syncope-path", TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:body:" + + "content:schemas:5:panel:multiValueContainer:innerForm", + TAB_PANEL + "outerObjectsRepeater:0:" + + "outer:form:content:form:view:membershipsPlainSchemas:0:membershipPlainSchemas:tabs:0:body:" + + "content:schemas:5:panel:multiValueContainer:innerForm:content:view:1:panel:field"); + assertNull(component); + + // close the wizard + formTester.submit("buttons:cancel"); + } + + @Test public void checkDeleteUsrLink() { TESTER.clickLink("body:realmsLI:realms"); TESTER.clickLink("body:content:body:container:content:tabbedPanel:tabs-container:tabs:1:link");