renatoathaydes / Automaton

Simple framework which allows the testing of Swing and JavaFX2 applications.
Apache License 2.0
100 stars 21 forks source link

How do you handle Swing Dialog Components with Automaton Framework? #26

Closed peterpilgrim closed 9 years ago

peterpilgrim commented 9 years ago

Hi Renato

I found a reference to your framework through the JavaFX developers list.

Give this sample code that opens a Swing JFrame followed by a custom JDialog compenent, how can you find the dialog component with Automaton?

    JFrame frame;
    Swinger swinger;
    FileLoaderDialog dialog;

    @Before
    public void setup()
    {
        frame = null;
        dialog = null;

        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame(FileLoaderDialog.class.getSimpleName());
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            //Add the ubiquitous "Hello World" label.
            frame.getContentPane().setLayout(new FlowLayout());
            frame.getContentPane().add(new JLabel("Hello World"));

            final JButton openBtn = new JButton("Open Dialog ...");
            openBtn.setMnemonic(KeyEvent.VK_O);
            frame.getContentPane().add(openBtn);

            final JButton quitBtn = new JButton("Quit");
            quitBtn.setMnemonic(KeyEvent.VK_Q);
            frame.getContentPane().add(quitBtn);

            openBtn.addActionListener(e -> {
                dialog = new FileLoaderDialog(null, "Local File Loader Dialog");
                // ....
                System.out.printf("\ndirectory = %s\n", dialog.getDirectoryPath());
            });

            quitBtn.addActionListener(e -> System.out.println("Goodbye"));

            frame.setPreferredSize(new Dimension(600, 400));
            frame.pack();
            frame.setVisible(true);
        });

        swinger = Swinger.forSwingWindow();
    }

    @Test
    public void open_dialog_then_click_confirm()
    {
        swinger.clickOn("text:Open Dialog ...").pause(5000).clickOn("text:Ok").pause(250);
        assertThat(dialog, is(notNullValue()));
    }

The error I see is the following:

com.athaydes.automaton.GuiItemNotFound: Could not locate prefix=text:, query=Open Dialog ...
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
    at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:77)
    at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:71)
    at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrap.callConstructor(ConstructorSite.java:81)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:57)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:232)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:244)
    at com.athaydes.automaton.HasSelectors.findOnePrefixed(HasSelectors.groovy:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at org.codehaus.groovy.runtime.metaclass.TransformMetaMethod.invoke(TransformMetaMethod.java:55)
    at groovy.lang.MetaClassImpl$3.invoke(MetaClassImpl.java:1224)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1207)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:151)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:163)
    at com.athaydes.automaton.HasSelectors.getAt(HasSelectors.groovy:32)
    at com.athaydes.automaton.HasSelectors$getAt.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:110)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:122)
    at com.athaydes.automaton.Swinger.clickOn(SwingAutomaton.groovy:135)
    at com.athaydes.automaton.Swinger.clickOn(SwingAutomaton.groovy)
    at emso.client.cashbalance.ui.GlobeOpCashBalanceLocalFileDialogAutomatonTest.shouldWork(LocalFileDialogAutomatonTest.java:94)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

Does your framework support modal dialogs? Is there a missing method that searches for the dialog by component name that I need to apply here in the test? Do you have any suggestions?

Thanks in advance

peterpilgrim commented 9 years ago

Sorry I found the answer I was looking for.

The answer is the execute the setRoot(Component)

@Test
    public void open_dialog_then_click_confirm()
    {
        swinger.clickOn("text:Open Dialog ...").pause(1000).setRoot(dialog);
        swinger.clickOn("name:dialogConfirmBtn").pause(250);
        assertThat(dialog, is(notNullValue()));
    }

PS: You might want to add a similar name method to setRoot() like Swinger Swinger.setComponentRoot(Component) that can return this in order to keep the fluent design.

renatoathaydes commented 9 years ago

Hi, glad you found a solution. Usually you should create a new Swinger for each frame you have like this:

Swinger swinger = Swinger.getUserWith(dialog);

So you don't need to set root (but you can if you prefer).