Forum Discussion

PaulDonny's avatar
PaulDonny
Regular Contributor
12 years ago

UISupport ActionaListener for Buttons

S I have created a single groovy script that will parameterize and run my entire test case all being controlled by this groovy script. It sends each other the 'Test Steps' to a single test step and runs them from there (The actual test steps are simply place holders to easily update the XML on an as needed basis). All of this works wonderfully well and does the job I need.


I now need the ability to be able to edit the XML and send for a test step if the assertions fail. I have everything set up (I have a dual TextArea panel, one with the Request and one with response) and the request is editable. The problem is that the groovy script never pays attention to the actionListener (I am using JButton) for the button. And when the test fails, groovy stops completely and the panel just sits there doing nothing.


What I am asking is essentially, how do I create the actionListener and have it actually work? The action that it needs to do is rather simple.
  • PaulDonny's avatar
    PaulDonny
    Regular Contributor
    OK, so I am able to keep the groovy script running as long as the window is active now. It's a very ..... bad way to go about it but I was able to achieve that. So now I just need to be able to create the actionListener for the button.



     
    import javax.swing.*;
    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.border.EmptyBorder;
    import javax.swing.JTextArea;
    import javax.swing.JScrollPane;
    import java.awt.event.ActionListener;
    import java.awt.event.ActionEvent;
    import javax.swing.BoxLayout;
    import java.awt.Component;
    import javax.swing.Box;
    import java.awt.Dimension;


    def UISupport = com.eviware.soapui.support.UISupport;

    SoapUITest.LaunchLog()

    public class SoapUITest extends JFrame {

    public static JPanel contentPane;
    public static JTextArea xmlInput;
    private JScrollPane scrollPane_1;
    public static JTextArea LoggerResults;
    private Box horizontalBox;
    private Box verticalBox;
    private Box horizontalBox_1;
    private JButton btnSubmit;
    private JButton btnCancel;
    private Component rigidArea;
    private Component rigidArea_1;
    private Component verticalStrut;
    private Component verticalStrut_1;
    private Component horizontalStrut;
    public static boolean kill;
    public static JFrame frame;

    public static void LaunchLog() {
    EventQueue.invokeAndWait(new Runnable() {
    public void run() {
    try {
    frame = new SoapUITest();
    frame.setName("Output");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.setVisible(true);
    } catch (Exception e) {
    }
    }
    });
    }

    public SoapUITest() {
    setTitle("SoapUI Output");
    setBounds(100, 100, 1000, 750);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS));

    verticalBox = Box.createVerticalBox();
    contentPane.add(verticalBox);

    horizontalBox = Box.createHorizontalBox();
    verticalBox.add(horizontalBox);

    JScrollPane scrollPane = new JScrollPane();
    horizontalBox.add(scrollPane);

    xmlInput = new JTextArea();
    xmlInput.setLineWrap(true);
    scrollPane.setViewportView(xmlInput);

    horizontalStrut = Box.createHorizontalStrut(20);
    horizontalBox.add(horizontalStrut);

    scrollPane_1 = new JScrollPane();
    horizontalBox.add(scrollPane_1);

    LoggerResults = new JTextArea();
    LoggerResults.setLineWrap(true);
    scrollPane_1.setViewportView(LoggerResults);

    horizontalBox_1 = Box.createHorizontalBox();
    verticalBox.add(horizontalBox_1);

    verticalStrut = Box.createVerticalStrut(20);
    horizontalBox_1.add(verticalStrut);

    btnCancel = new JButton("Cancel");
    btnCancel.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    }
    });
    horizontalBox_1.add(btnCancel);

    rigidArea = Box.createRigidArea(new Dimension(20, 20));
    horizontalBox_1.add(rigidArea);

    btnSubmit = new JButton("Submit");
    btnSubmit.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    log.info "Test";
    }
    });
    horizontalBox_1.add(btnSubmit);





    rigidArea_1 = Box.createRigidArea(new Dimension(480, 20));
    horizontalBox_1.add(rigidArea_1);

    verticalStrut_1 = Box.createVerticalStrut(20);
    horizontalBox_1.add(verticalStrut_1);
    }

    }
    def activeFrame;
    def allFrames = SoapUITest.frame.getFrames();
    for(listFrames in allFrames ) {
    if (listFrames.getName().equals("Output") && listFrames.isShowing()) {
    activeFrame = listFrames
    }
    }

    while (activeFrame.isShowing()) {

    }

    log.info "fin"


    Source for my UI, to some degree. Currently I just have the XML being sent into the left JTextArea and the Output into the Right.
  • PaulDonny's avatar
    PaulDonny
    Regular Contributor
    OK, so I was able to make this work, to some degree. The while loop keeps Groovy 'active' still and the listener I used to adjust a variable to simply say that it was pressed and then if the variable changes it runs the script I want.

    Sorry to keep posting in my own thread but figured since UISupport seems to have very little documentation someone else might find this information useful.


    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import java.util.HashMap;
    import java.util.Map;
    import javax.swing.JFileChooser;
    import javax.swing.*;
    import com.eviware.soapui.support.types.StringToStringsMap
    import com.eviware.soapui.support.UISupport
    import com.eviware.soapui.model.testsuite.Assertable
    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.border.EmptyBorder;
    import javax.swing.JTextArea;
    import javax.swing.JScrollPane;
    import java.awt.event.ActionListener;
    import java.awt.event.ActionEvent;
    import javax.swing.BoxLayout;
    import java.awt.Component;
    import javax.swing.Box;
    import java.awt.Dimension;


    def UISupport = com.eviware.soapui.support.UISupport;

    SoapUITest.LaunchLog()

    public class SoapUITest extends JFrame {

    public static JPanel contentPane;
    public static JTextArea xmlInput;
    private JScrollPane scrollPane_1;
    public static JTextArea LoggerResults;
    private Box horizontalBox;
    private Box verticalBox;
    private Box horizontalBox_1;
    private JButton btnSubmit;
    private JButton btnCancel;
    private Component rigidArea;
    private Component rigidArea_1;
    private Component verticalStrut;
    private Component verticalStrut_1;
    private Component horizontalStrut;
    public static int testThis = 0;
    public static JFrame frame;

    public static void LaunchLog() {
    EventQueue.invokeAndWait(new Runnable() {
    public void run() {
    try {
    frame = new SoapUITest();
    frame.setName("Output");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.setVisible(true);
    } catch (Exception e) {
    }
    }
    });
    }

    public SoapUITest() {
    setTitle("SoapUI Output");
    setBounds(100, 100, 1000, 750);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS));

    verticalBox = Box.createVerticalBox();
    contentPane.add(verticalBox);

    horizontalBox = Box.createHorizontalBox();
    verticalBox.add(horizontalBox);

    JScrollPane scrollPane = new JScrollPane();
    horizontalBox.add(scrollPane);

    xmlInput = new JTextArea();
    xmlInput.setLineWrap(true);
    scrollPane.setViewportView(xmlInput);

    horizontalStrut = Box.createHorizontalStrut(20);
    horizontalBox.add(horizontalStrut);

    scrollPane_1 = new JScrollPane();
    horizontalBox.add(scrollPane_1);

    LoggerResults = new JTextArea();
    LoggerResults.setLineWrap(true);
    scrollPane_1.setViewportView(LoggerResults);

    horizontalBox_1 = Box.createHorizontalBox();
    verticalBox.add(horizontalBox_1);

    verticalStrut = Box.createVerticalStrut(20);
    horizontalBox_1.add(verticalStrut);

    btnCancel = new JButton("Cancel");
    btnCancel.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    }
    });
    horizontalBox_1.add(btnCancel);

    rigidArea = Box.createRigidArea(new Dimension(20, 20));
    horizontalBox_1.add(rigidArea);

    btnSubmit = new JButton("Submit");
    btnSubmit.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
    testThis++;
    }
    });
    horizontalBox_1.add(btnSubmit);





    rigidArea_1 = Box.createRigidArea(new Dimension(480, 20));
    horizontalBox_1.add(rigidArea_1);

    verticalStrut_1 = Box.createVerticalStrut(20);
    horizontalBox_1.add(verticalStrut_1);
    }

    }
    def activeFrame;
    def allFrames = SoapUITest.frame.getFrames();
    for(listFrames in allFrames ) {
    if (listFrames.getName().equals("Output") && listFrames.isShowing()) {
    activeFrame = listFrames
    }
    }

    int buttonpushNum = 0;
    while (activeFrame.isShowing()) {
    if (SoapUITest.testThis != buttonpushNum) {
    log.info SoapUITest.xmlInput.getText();
    log.info SoapUITest.testThis + " " + buttonpushNum
    buttonpushNum++
    }
    }



    If anyone is interested in this code, feel free to use it. I will give a brief explanation of what I am using it for and if anyone has a suggestion for improvements please let me know.


    Step 1)

    The groovy script asks the user to input the property file(s)


    public File[] propFilesSelect() {
    def propPath = context.expand('${#Project#propPath}');
    File[] propfiles = null;
    JFileChooser chooser;
    String currentDir = new File("").getAbsolutePath();
    if (propPath.length() > 1 ) {
    chooser = new JFileChooser(propPath);
    } else {
    chooser = new JFileChooser(currentDir);
    }
    if( com.eviware.soapui.SoapUI.isCommandLine() ) {
    chooser.setSelectedFile(new File(context.expand('${#Project#propFiles}')));
    }
    chooser.setMultiSelectionEnabled(true);
    int returnValue = chooser.showOpenDialog(null);
    if (returnValue == JFileChooser.APPROVE_OPTION) {
    propfiles = chooser.getSelectedFiles();
    }
    //If the path wasn't the same as what was stored, ask if they want to change their default path. Genius!
    if( !com.eviware.soapui.SoapUI.isCommandLine() ) {
    if ( propfiles[0].getParent() != context.expand('${#Project#propPath}') ) {
    int reply = JOptionPane.showConfirmDialog(null, "Would you like to store this Directory?", "Default Directory", JOptionPane.YES_NO_OPTION);
    if (reply == JOptionPane.YES_OPTION) {
    testRunner.testCase.testSuite.project.setPropertyValue( "propPath", propfiles[0].getParent() )
    }
    }
    }
    return propfiles;
    }


    Note the command line ability, it still asks for property file if ran from my external source in case the user wants to run multiple (it preselects the one being sent to it for ease though).

    Step 2)

    The groovy script finds all of the test steps for the test case, storing these into a map



    propFiles = propFilesSelect();
    int buttonpushNum = 0;
    for (file in propFiles ) {
    //SoapUITest.LaunchLog();
    propReader = new FileReader(file);
    def propArray = []
    //Just reading the file here
    propReader.eachLine({propArray.add(it)});
    def temp = []
    for (prop in propArray ) {
    if (prop.length() > 1 ) {
    if (prop.substring(0,1) != '#' ) {
    properties = prop.split('=')
    if (properties.size() > 1) {
    //Split the file, trim it down, put it to lower case and store it in the map
    props.put("["+properties[0].trim().toLowerCase()+"]",properties[1].trim());
    }
    }
    }
    }


    Note: The code does not close here. It stays open so that it will continue to process each property file individually. If you wanted to here, you could possibly multi-thread to do it simultaneously (Does SoapUI support multi-threading, haven't tried yet)



    Step 3)

    Parse your properties as needed and then launch your UI to control the flow of the system. After the UI launch, insert a loop for each different test case from your TC list. This will be used to parse your XML for running. These test steps are essentially just place holders for the XML and tags for the properties.


    SoapUITest.LaunchLog();
    for ( tests in testRunner.testCase.getTestStepsOfType(com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class) ) {
    testName = tests.getName();
    //this section disables the test step if there is a flag in the property saying testName = false or enables if testName = true.
    if ( props.containsKey("["+testName.toLowerCase()+"]")) {
    if ( props.get("["+testName.toLowerCase()+"]").toBoolean() && tests.disabled) {
    log.info "Enabling " + testName
    tests.disabled = false;
    } else if (!props.get("["+testName.toLowerCase()+"]").toBoolean() && !tests.disabled){
    tests.disabled = true;
    }
    }
    //this section checks to see if it failed previously, is the testName is "Runner" (My step for running) or if the step is disabled
    if (testName != "Runner" && fail != true && !tests.disabled) {
    //Put the testName into the Results output screen so the user knows which test step is being ran
    SoapUITest.LoggerResults.append("\n"+testName + "\n\n");



    //Regexp to parse through the XML and check for the tags. I use [property$default~casesens]. I was lazy with casesens

    def holder = groovyUtils.getXmlHolder(testName+"#Request");
    def xml = holder.getPrettyXml()
    def regexp = ("<([^<>]+)>(.*?)</\\1>");
    def matcher = xml =~ regexp;
    matcher.each {
    /*
    * Getting default properties and whether it is case sensitive
    */
    def propKey;
    def String[] defaultProp = it[2].tokenize("\$");
    if (defaultProp.size() > 1) {
    propKey = defaultProp[0] + "]";
    } else {
    propKey = it[2];
    }
    def String[] caseSens = it[2].tokenize("~");
    if ( props.containsKey(propKey.toLowerCase())) {
    def replaced = props.get(propKey.toLowerCase());
    if ( caseSens.size() > 1 && caseSens[1].equalsIgnoreCase("lower]") ) {
    replaced = replaced.toLowerCase();
    } else if ( caseSens.size() > 1 && caseSens[1].equalsIgnoreCase("upper]") ) {
    replaced = replaced.toUpperCase();
    }
    xml = xml.replace(it[2],replaced);
    } else if (defaultProp.size() > 1){
    if (caseSens.size() > 1 ) {
    xml = xml.replace(it[2],defaultProp[1].substring(0,defaultProp[1].size()-7));
    } else {
    xml = xml.replace(it[2],defaultProp[1].substring(0,defaultProp[1].size() - 1 ));
    }
    } else {
    xml = xml.replace(it[0],"")
    }
    }


    //Putting the current Test step as the title of the UI, the XML in both of the text areas so that we can edit and view the XML

    SoapUITest.frame.setTitle(testName);
    SoapUITest.xmlInput.setText(xml + "\n");
    SoapUITest.LoggerResults.append("\nRequest:\n");
    SoapUITest.LoggerResults.append(xml + "\n");
    SoapUITest.LoggerResults.setCaretPosition(SoapUITest.LoggerResults.getDocument().getLength());


    /*
    * This section puts the formatted xml from the previous step into a
    * property. It then starts setting up information for the test case
    * like headers, username and password.
    */
    testRunner.testCase.setPropertyValue("Runner",xml);


    //Headers
    if (props.containsKey("[xxxx]")) {

    String[] curHeader = context.testCase.getTestStepByName("Runner").getTestRequest().getRequestHeaders().get("xxxx");
    for (remove in curHeader ) {
    headers.remove('PARTNER_NAME',remove)
    context.testCase.getTestStepByName("Runner").getTestRequest().setRequestHeaders(headers)
    }
    headers.put('PARTNER_NAME',props.get("[partner_name]"))
    context.testCase.getTestStepByName("Runner").getTestRequest().setRequestHeaders(headers)

    } else {
    String[] curHeader = context.testCase.getTestStepByName("Runner").getTestRequest().getRequestHeaders().get("xxxx");
    for (remove in curHeader ) {
    headers.remove('xxxx',remove)
    context.testCase.getTestStepByName("Runner").getTestRequest().setRequestHeaders(headers)
    }
    }


    //Username and Password
    context.testCase.getTestStepByName("Runner").getTestRequest().setPassword(props.get("[password]"));
    context.testCase.getTestStepByName("Runner").getTestRequest().setUsername(props.get("[username]"));

    /*
    * Stealing the assertions from the respective test steps and putting it into the Runner
    * test step
    */
    def testRan = testRunner.testCase.getTestStepByName(testName);
    def Assertions = testRan.getAssertions();
    def removeAssertions = testRunner.testCase.getTestStepByName("Runner").getAssertions();

    for (key in removeAssertions.keySet()) {
    testRunner.testCase.getTestStepByName("Runner").removeAssertion(removeAssertions.get(key));
    }
    for (assertion in Assertions.keySet()) {
    testRunner.testCase.getTestStepByName("Runner").cloneAssertion(Assertions.get(assertion),assertion);
    }


    /*
    * So all the parsing and set up has been performed, it is time to go ahead and run it.
    * The below function runs the Runner TestStep once and stores the XML in 2 different
    * ways currently. This should make it easier for different verification steps.
    */

    testRunResultsXML = testRunner.runTestStepByName("Runner").getResponse();
    testRunResults = groovyUtils.getXmlHolder("Runner#Response");
    testPrint = testRunResults.getPrettyXml();



    /*
    * TODO:
    *
    * Verification Steps
    * Conversation ID storing
    * Any other information that we need/want stored
    * Default information
    * Other awesomeness
    */
    def resultsMatcher = testPrint =~ regexp;
    resultsMatcher.each {
    //it[1] is your XML tag, it[2] is your xml value. If you need to store info from your XML for later use (Passer step, essentially), do it here
    }
    //Let's put the Response from the step back to the output
    SoapUITest.LoggerResults.append("\nResponse:\n");
    SoapUITest.LoggerResults.append(testPrint + "\n");
    SoapUITest.LoggerResults.setCaretPosition(SoapUITest.LoggerResults.getDocument().getLength());





    //I have mine set up to be automated unless it fails, if you want to verify the XML at every step just bypass this if statement and that should take care of it

    if ( testRunner.testCase.getTestStepByName("Runner").getAssertionStatus().toString().equals("FAILED") && fail != true) {
    fixed = false;
    //Alert the user that it failed. Bad day.
    SoapUITest.LoggerResults.append("\n\n\n Test Step Failed.\n Edit XML and fix!");
    SoapUITest.LoggerResults.setCaretPosition(SoapUITest.LoggerResults.getDocument().getLength());
    //Get a list of the frames
    def activeFrame;
    def allFrames = SoapUITest.frame.getFrames();
    for(listFrames in allFrames ) {
    if (listFrames.getName().equals("Output") && listFrames.isShowing()) {
    //Set the frame you want to activeFrame variable.
    activeFrame = listFrames
    }
    }

    //While the frame exists, it is open and nothing has been fixed, wait for the User input
    while (activeFrame != null && activeFrame.isShowing() && fixed == false) {
    //This if statement checks if the user pushed the button.
    if (SoapUITest.testThis != buttonpushNum) {
    //If it did, just repeat the above steps with the XML from the xmlInput Text Area this time.
    testRunner.testCase.setPropertyValue("Runner",SoapUITest.xmlInput.getText());
    testRunResultsXML = testRunner.runTestStepByName("Runner").getResponse();
    testRunResults = groovyUtils.getXmlHolder("Runner#Response");
    testPrint = testRunResults.getPrettyXml();
    resultsMatcher = testPrint =~ regexp;
    resultsMatcher.each {
    //Insert your regex here, a lot of these sections will be better off as functions I know but I am simply testing at the point
    }
    //and print the respone.
    SoapUITest.LoggerResults.append("\nResponse:\n");
    SoapUITest.LoggerResults.append(testPrint + "\n");
    //Increase buttonpushNum to equal the testThis number
    buttonpushNum++
    }

    //If the assertion isn't failed this time, than set fixed to true to break the while loop
    if ( !testRunner.testCase.getTestStepByName("Runner").getAssertionStatus().toString().equals("FAILED") ) {
    fixed = true;
    }
    }
    //If all of that didn't fix it, give the user the option to just quit trying.
    if ( fixed != true ) {
    int assertAlert = JOptionPane.showConfirmDialog(null," Assertion failed at Test Step " +testName+". Would you like to continue?", "Assertion Failed. Bad Day", JOptionPane.YES_NO_OPTION);
    if (assertAlert == JOptionPane.NO_OPTION) {
    fail = true;
    }
    }
    }
    }
    }
    }




    If anyone has any suggestions, questions or comments please, please feel free to ask. If you want the command line controls, just let me know.