In part 2 of our tutorial we’ll get started with some simple Marionette commands that allow us to remotely control Firefox OS. While this doesn't cover writing a full test, it teaches you the basic code features that you will use while writing a test. In part 3, we’ll progress onto evolving this code into a real test.
Starting up Firefox OS
When writing these tests we’ll need to have Firefox OS already running and ready to receive commands:
- Start up desktop B2G.
- Disable the lock screen using Settings App > Screen lock > uncheck Lock screen.
- Disable screen timeout/sleep mode by changing the Settings App > Display > Screen timeout setting to never.
- Move the window over to the side to await our test commands.
Firing up Marionette
Now we will start a Python console: simply go to a Terminal window and issue the python
command.
From here we can send commands to the Marionette server inside Firefox OS. After issuing many of the below commands you should see Firefox OS respond. In the Python console, enter the following command to import the Marionette library containing the code we need:
from marionette import Marionette
Now run the next two lines, which initiate a Marionette session, preparing Marionette to receive commands from the client:
marionette = Marionette() marionette.start_session()
If you didn't disable the lock screen as explained above, you can unlock the screen programmatically, using this command:
marionette.execute_script('window.wrappedJSObject.lockScreen.unlock();')
Accessing different frames inside Firefox OS
Web apps in Firefox OS operate in different iFrames. Running web apps in separate frames gives them distinct containers for security and also visual management (like a window). You can think of it like a sandbox the app runs in. Marionette can only operate in one of the frames at a time. We need Marionette to switch into the frame that we’re intending to interact with.
The top frame is also the System app. All apps and their frames are children of the System app. Our new Marionette session starts in the System frame but to start the test we'll need to find and switch into the home screen.
To find the iFrame, we need to identify it somehow. As Marionette is based on the WebDriver API, it uses the same strategies to locate elements, so we can easily use any of the strategies used to identify WebDriver web elements. Read more information on element location strategies.
In this case we will use the CSS Selector div.homescreen iframe
to select the homescreen iFrame; the find_element()
function takes this as its second argument, the first argument being a definition of what selection mechanism is being used to perform the find. We'll then store this result in a variable and run the switch_to_frame()
function with that as the argument. Try the following two commands now:
# Switch context to the homescreen iframe and tap on the Contacts app icon home_frame = marionette.find_element('css selector', 'div.homescreen iframe') marionette.switch_to_frame(home_frame)
Note: For further reading and diagrams describing switching frames, please read Working with iFrames.
Opening an application
OK. Now we’re in the Homescreen app we can target icons and tap on them using the find_element()
function, in combination with the tap()
function.
contacts_icon = marionette.find_element('xpath', "
//div[@class='icon']//span[contains(text(),'Contacts')]")
contacts_icon.tap()
If that’s all gone right then you should now have seen the Contacts app open, but we still need to switch into the Contacts app frame in order to interact with it, like we did with the Homescreen earlier:
# First, we need to switch context back to the System frame marionette.switch_to_frame() # Now, switch context to the contacts app frame contacts_frame = marionette.find_element('css selector', "iframe[data-url*='contacts']") marionette.switch_to_frame(contacts_frame)
Switch to frame should return True
. If it did, then great this means we are inside the contacts app context and ready to start using it.
Manipulating the app
In the next step we’ll perform a typical test task — creating a new contact, entering a name into it, and saving it. First, we'll tap the add contact button:
# Tap [+] to add a new Contact marionette.find_element('id', 'add-contact-button').tap()
Now let’s add the contact's name using the next two commands (send_keys()
is used to insert a value into an element):
marionette.find_element('id', 'givenName').send_keys('Foo') # Add the contact's surname marionette.find_element('id', 'familyName').send_keys('Bar')
Now let’s tap the Done button to save the Contact:
marionette.find_element('id', 'save-button').tap()
Now you should see a new contact entered inside the Contacts app. If so, great!
Note: If you don't, reset or kill the Contacts app and navigate Firefox OS back to the Homescreen and try running the task again.
Closing your Marionette session
Finally, you should finish your Marionette session by issuing the following command:
marionette.delete_session()
That worked pretty well, but you can’t go typing into a Python console each time you want to run a test. In Part 3, we’ll compile this script into a Python file which we can reuse each time we want to run the test. We’ll also add an assertion so that we can distinguish whether the test has passed or failed.
Note: When writing Marionette commands, you'll certainly notice that accessing the underlying HTML structure of the app is vitally important to figure out the locators you need. Part 7: Writing your own tests offers some useful resources to help you with this.