Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@

package io.jmix.flowui.testassist;

import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.HasElement;
import com.vaadin.flow.component.UI;
import io.jmix.core.annotation.Internal;
import io.jmix.flowui.component.UiComponentUtils;
import io.jmix.flowui.component.validation.ValidationErrors;
import io.jmix.flowui.Dialogs;
import io.jmix.flowui.OpenedDialogWindows;
import io.jmix.flowui.testassist.dialog.DialogInfo;
import io.jmix.flowui.testassist.dialog.OpenedDialogs;
import io.jmix.flowui.testassist.notification.NotificationInfo;
import io.jmix.flowui.testassist.notification.OpenedNotifications;
import io.jmix.flowui.view.OpenMode;
import io.jmix.flowui.view.StandardDetailView;
import io.jmix.flowui.view.View;
import org.apache.commons.collections4.CollectionUtils;
Expand Down Expand Up @@ -129,6 +133,10 @@ public static NotificationInfo getLastOpenedNotification() {
/**
* Returns an immutable list of {@link DialogInfo} objects in the order they were opened.
* <p>
* This method covers <i>component</i> {@link Dialog}s created via {@link Dialogs}
* (message, option, background-task and side dialogs). Views shown as dialogs (e.g. {@code InputDialog}
* or any view opened in {@link OpenMode#DIALOG}) are not included here — use {@link #getOpenedViewDialogs()}.
* <p>
* Example of the order in which dialogs are stored:
* <ul>
* <li>first opened dialog has index {@code 0}</li>
Expand All @@ -143,10 +151,56 @@ public static List<DialogInfo> getOpenedDialogs() {
}

/**
* Returns the most recently opened <i>component</i> {@link Dialog} created via
* {@link Dialogs}. For views shown as dialogs (e.g. {@code InputDialog}) use
* {@link #getLastOpenedViewDialog()}.
*
* @return the most recent opened {@link DialogInfo} or {@code null} if no opened dialogs
*/
@Nullable
public static DialogInfo getLastOpenedDialog() {
return applicationContext.getBean(OpenedDialogs.class).getLastDialog();
}

/**
* Returns an immutable list of {@link View}s shown as dialogs (i.e. opened in {@link OpenMode#DIALOG}),
* in the order they were opened. This includes any lookup or detail view opened as a dialog, as well as
* the framework {@code InputDialog}.
* <p>
* Example of the order in which view dialogs are stored:
* <ul>
* <li>first opened view dialog has index {@code 0}</li>
* <li>second opened view dialog has index {@code 1}</li>
* <li>last opened view dialog has index {@code openedViewDialogs.size() - 1}</li>
* </ul>
* <p>
* For <i>component</i> dialogs created via {@link Dialogs} (message, option, background-task and side
* dialogs) use {@link #getOpenedDialogs()} instead.
*
* @return immutable list of {@link View}s shown as dialogs, in order of opening
*/
public static List<View<?>> getOpenedViewDialogs() {
return applicationContext.getBean(OpenedDialogWindows.class).getDialogs();
}

/**
* Returns the most recently opened {@link View} shown as a dialog, i.e. the topmost view opened in
* {@link OpenMode#DIALOG} (a lookup or detail view, a custom view, etc.). Usage example:
* <pre>
* // open a view as a dialog (e.g. via DialogWindows or OpenMode.DIALOG), then:
* CustomerDetailView view = UiTestUtils.getLastOpenedViewDialog();
* </pre>
* <p>
* Note: the framework {@code InputDialog} is also a view dialog and can be obtained the same way.
*
* @param <T> expected type of the view
* @return the most recently opened view dialog, or {@code null} if there are no opened view dialogs
*/
@SuppressWarnings("unchecked")
@Nullable
public static <T extends View<?>> T getLastOpenedViewDialog() {
return (T) applicationContext.getBean(OpenedDialogWindows.class)
.getCurrentDialog()
.orElse(null);
}
}
71 changes: 71 additions & 0 deletions jmix-flowui/flowui/src/test/java/dialog/ViewDialogTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2026 Haulmont.
*
* 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 dialog;

import dialog.view.DialogsTestView;
import io.jmix.flowui.app.inputdialog.InputDialog;
import io.jmix.flowui.testassist.FlowuiTestAssistConfiguration;
import io.jmix.flowui.testassist.UiTest;
import io.jmix.flowui.testassist.UiTestUtils;
import io.jmix.flowui.view.View;
import io.jmix.flowui.view.navigation.ViewNavigationSupport;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import test_support.FlowuiTestConfiguration;

import static org.junit.jupiter.api.Assertions.*;

/**
* Verifies that views shown as dialogs (e.g. {@code InputDialog}) are reported through the view-dialog
* accessors of {@link UiTestUtils} and are kept separate from component dialogs.
*/
@UiTest(viewBasePackages = {"io.jmix.flowui.app.inputdialog","dialog.view"})
@SpringBootTest(classes = {FlowuiTestConfiguration.class, FlowuiTestAssistConfiguration.class})
public class ViewDialogTest {

@Autowired
ViewNavigationSupport navigationSupport;

@Test
@DisplayName("InputDialog is reported as a view dialog, not as a component dialog")
public void inputDialogIsReportedAsViewDialogTest() {
// Navigate to DialogsTestView
DialogsTestView view = navigateToDialogsTestView();

// Open an InputDialog (a view shown as a dialog)
view.openInputDialog();

// It is available through the view-dialog accessors
View<?> lastViewDialog = UiTestUtils.getLastOpenedViewDialog();
assertNotNull(lastViewDialog);
assertInstanceOf(InputDialog.class, lastViewDialog);
assertEquals(1, UiTestUtils.getOpenedViewDialogs().size());
assertSame(lastViewDialog, UiTestUtils.getOpenedViewDialogs().get(0));

// ...and it is not reported as a component dialog
assertNull(UiTestUtils.getLastOpenedDialog());
assertTrue(UiTestUtils.getOpenedDialogs().isEmpty());
}

protected <T extends View<?>> T navigateToDialogsTestView() {
//noinspection unchecked
navigationSupport.navigate((Class<T>) DialogsTestView.class);
return UiTestUtils.getCurrentView();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.vaadin.flow.router.Route;
import io.jmix.flowui.Dialogs;
import io.jmix.flowui.action.DialogAction;
import io.jmix.flowui.app.inputdialog.InputParameter;
import io.jmix.flowui.view.StandardView;
import io.jmix.flowui.view.ViewController;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -50,4 +51,10 @@ public void openOptionDialog() {
)
.open();
}

public void openInputDialog() {
dialogs.createInputDialog(this)
.withParameter(InputParameter.stringParameter("name"))
.open();
}
}