Extending the core test vocabulary

Frankenstein is an event-driven framework. It is possible to extend the core event vocabulary by creating new event classes. Custom events need to implement the FrankensteinEvent interface. (For most custom events, it will be sufficient to extend from AbstractFrankensteinEvent). You'll need to explicitly register a custom event with Frankenstein.

Compound events

Compound events can help decouple Actions (Clicks, RightClicks, Double Clicks, Drag , Drop, etc.) from the components where the action is executed.

Here is an example of a compound event:

    package com.thoughtworks.frankenstein.events;
    
    import com.thoughtworks.frankenstein.events.actions.Action;
    
    import javax.swing.*;
    
    
    /**
     * Understands radio button actions
     */
    public class RadioButtonEvent extends AbstractCompoundEvent {
        private String radioButtonName;
    
        /**
         * Compound events need to declare a constructor that takes in a script line and an action.
         */
        public RadioButtonEvent(String scriptLine, Action action) {
            super(action);
            this.radioButtonName = scriptLine;
        }
    
        public String toString() {
            return "RadioButtonEvent: " + radioButtonName;
        }
    
        public String target() {
            return radioButtonName;
        }
    
        public void run() {
            JRadioButton radioButton = (JRadioButton) finder.findComponent(context, radioButtonName);
            action.execute(center(radioButton), radioButton, finder, context);
        }
    }
    

Adding custom events to the Ruby driver

Custom events can be added to the Frankenstein driver by adding functions to the FrankensteinDriver module. Please refer to the
Ruby Driver documentation for more information about Ruby.
    #Include the Frankenstein driver module.
    require 'frankenstein_driver'
#Add custom actions to the driver module FrankensteinDriver def custom_event(param1,param2) append_to_script("custom_event \"#{param1}\",\"#{param2}\") end end

Custom components

If required, custom recorders can be written for custom components. Most component recorders work in the following manner: Here's an example recorder: the CheckBoxRecorder (this recorder is part of the core framework).
    /**
     * Records interactions with check boxes.
     */
    public class CheckBoxRecorder extends AbstractComponentRecorder implements ActionListener {
    
        public CheckBoxRecorder(EventRecorder recorder, NamingStrategy namingStrategy) {
            super(recorder, namingStrategy, JCheckBox.class);
        }
    
        public void componentShown(Component component) {
            checkBox(component).addActionListener(this);
        }

    
        public void componentHidden(Component component) {
            checkBox(component).removeActionListener(this);
        }
    
        private JCheckBox checkBox(Component component) {
            return (JCheckBox) component;
        }
    
        public void actionPerformed(ActionEvent e) {
            JCheckBox checkBox = (JCheckBox) e.getSource();
            recorder.record(new ClickCheckboxEvent(componentName(checkBox), checkBox.isSelected()));
        }
    }
    

What to record

It would be advisable to record high level events that express the user's actions, rather than low level mouse and keyboard events.

For example: let's look at what we'd like to record when the user interacts with a Map widget which allows locations can be selected on a map.


Recording raw mouse events would typically result in a script that looks something like this:

Click map 100,100

Clearly, it's next to impossible to determine which location the user had selected


An example of a higher level event would be one that records the location, latitude, and longitude that the user selected.

Select location Bangalore, 12 58 N , 77 35 E

Transforming low level actions into high level events: