1283 lines
47 KiB
Diff
1283 lines
47 KiB
Diff
diff -up evolution-3.13.4/tests/addressbook.feature.missing-tests evolution-3.13.4/tests/addressbook.feature
|
|
--- evolution-3.13.4/tests/addressbook.feature.missing-tests 2014-07-30 11:21:47.031172903 +0200
|
|
+++ evolution-3.13.4/tests/addressbook.feature 2014-07-30 11:21:47.031172903 +0200
|
|
@@ -0,0 +1,101 @@
|
|
+Feature: Addressbook: File: Create contacts
|
|
+
|
|
+ Background:
|
|
+ * Open Evolution and setup fake account
|
|
+ * Open "Contacts" section
|
|
+ * Select "Personal" addressbook
|
|
+ * Change categories view to "Any Category"
|
|
+ * Delete all contacts containing "Doe"
|
|
+
|
|
+ @addressbook_contacts
|
|
+ Scenario: Create a simple contact
|
|
+ * Create a new contact
|
|
+ * Set "Full Name..." in contact editor to "John Doe"
|
|
+ * Save the contact
|
|
+ * Refresh addressbook
|
|
+ * Select "Doe, John" contact
|
|
+ * Open contact editor for selected contact
|
|
+ Then "Full Name..." property is set to "John Doe"
|
|
+
|
|
+ @addressbook_contacts
|
|
+ Scenario: Create a new contact with data
|
|
+ * Create a new contact
|
|
+ * Set "Full Name..." in contact editor to "Jimmy Doe"
|
|
+ * Set "Nickname:" in contact editor to "Unknown"
|
|
+ * Set emails in contact editor to
|
|
+ | Field | Value |
|
|
+ | Work Email | jimmy.doe@company.com |
|
|
+ | Home Email | jimmy_doe_72@gmail.com |
|
|
+ | Other Email | jimmydoe72@yahoo.com |
|
|
+ | Other Email | xxjimmyxx@free_email.com |
|
|
+ * Tick "Wants to receive HTML mail" checkbox
|
|
+ * Set phones in contact editor to
|
|
+ | Field | Value |
|
|
+ | Assistant Phone | 123 |
|
|
+ | Business Phone | 234 |
|
|
+ | Business Fax | 345 |
|
|
+ | Callback Phone | 456 |
|
|
+ | Car Phone | 567 |
|
|
+ | Company Phone | 678 |
|
|
+ | Home Phone | 789 |
|
|
+ | Home Fax | 890 |
|
|
+ | ISDN | 123 |
|
|
+ | Mobile Phone | 234 |
|
|
+ | Other Phone | 345 |
|
|
+ | Other Fax | 456 |
|
|
+ | Pager | 567 |
|
|
+ | Primary Phone | 678 |
|
|
+ | Radio | 789 |
|
|
+ | Telex | 890 |
|
|
+ * Set IMs in contact editor to
|
|
+ | Field | Value |
|
|
+ | AIM | 123 |
|
|
+ | Jabber | 234 |
|
|
+ | Yahoo | 345 |
|
|
+ | Gadu-Gadu | 456 |
|
|
+ | MSN | 123 |
|
|
+ | ICQ | 234 |
|
|
+ | GroupWise | 345 |
|
|
+ | Skype | jimmy.doe |
|
|
+ | Twitter | @jimmydoe |
|
|
+ * Save the contact
|
|
+ * Refresh addressbook
|
|
+ * Select "Doe, Jimmy" contact
|
|
+ * Open contact editor for selected contact
|
|
+ Then "Nickname:" property is set to "Unknown"
|
|
+ And Emails are set to
|
|
+ | Field | Value |
|
|
+ | Work Email | jimmy.doe@company.com |
|
|
+ | Home Email | jimmy_doe_72@gmail.com |
|
|
+ | Other Email | jimmydoe72@yahoo.com |
|
|
+ | Other Email | xxjimmyxx@free_email.com |
|
|
+ And "Wants to receive HTML mail" checkbox is ticked
|
|
+ And Phones are set to
|
|
+ | Field | Value |
|
|
+ | Assistant Phone | 123 |
|
|
+ | Business Phone | 234 |
|
|
+ | Business Fax | 345 |
|
|
+ | Callback Phone | 456 |
|
|
+ | Car Phone | 567 |
|
|
+ | Company Phone | 678 |
|
|
+ | Home Phone | 789 |
|
|
+ | Home Fax | 890 |
|
|
+ | ISDN | 123 |
|
|
+ | Mobile Phone | 234 |
|
|
+ | Other Phone | 345 |
|
|
+ | Other Fax | 456 |
|
|
+ | Pager | 567 |
|
|
+ | Primary Phone | 678 |
|
|
+ | Radio | 789 |
|
|
+ | Telex | 890 |
|
|
+ And IMs are set to
|
|
+ | Field | Value |
|
|
+ | AIM | 123 |
|
|
+ | Jabber | 234 |
|
|
+ | Yahoo | 345 |
|
|
+ | Gadu-Gadu | 456 |
|
|
+ | MSN | 123 |
|
|
+ | ICQ | 234 |
|
|
+ | GroupWise | 345 |
|
|
+ | Skype | jimmy.doe |
|
|
+ | Twitter | @jimmydoe |
|
|
diff -up evolution-3.13.4/tests/common_steps.py.missing-tests evolution-3.13.4/tests/common_steps.py
|
|
--- evolution-3.13.4/tests/common_steps.py.missing-tests 2014-07-30 11:21:47.031172903 +0200
|
|
+++ evolution-3.13.4/tests/common_steps.py 2014-07-30 11:21:47.031172903 +0200
|
|
@@ -0,0 +1,238 @@
|
|
+# -*- coding: UTF-8 -*-
|
|
+from dogtail.utils import isA11yEnabled, enableA11y
|
|
+if isA11yEnabled() is False:
|
|
+ enableA11y(True)
|
|
+
|
|
+from time import time, sleep
|
|
+from functools import wraps
|
|
+from os import strerror, errno, system
|
|
+from signal import signal, alarm, SIGALRM
|
|
+from subprocess import Popen, PIPE
|
|
+from behave import step
|
|
+from gi.repository import GLib, Gio
|
|
+import fcntl, os
|
|
+
|
|
+from dogtail.rawinput import keyCombo, absoluteMotion, pressKey
|
|
+from dogtail.tree import root
|
|
+from unittest import TestCase
|
|
+
|
|
+
|
|
+# Create a dummy unittest class to have nice assertions
|
|
+class dummy(TestCase):
|
|
+ def runTest(self): # pylint: disable=R0201
|
|
+ assert True
|
|
+
|
|
+
|
|
+def wait_until(my_lambda, element, timeout=30, period=0.25):
|
|
+ """
|
|
+ This function keeps running lambda with specified params until the result is True
|
|
+ or timeout is reached
|
|
+ Sample usages:
|
|
+ * wait_until(lambda x: x.name != 'Loading...', context.app)
|
|
+ Pause until window title is not 'Loading...'.
|
|
+ Return False if window title is still 'Loading...'
|
|
+ Throw an exception if window doesn't exist after default timeout
|
|
+
|
|
+ * wait_until(lambda element, expected: x.text == expected, element, ('Expected text'))
|
|
+ Wait until element text becomes the expected (passed to the lambda)
|
|
+
|
|
+ """
|
|
+ exception_thrown = None
|
|
+ mustend = int(time()) + timeout
|
|
+ while int(time()) < mustend:
|
|
+ try:
|
|
+ if my_lambda(element):
|
|
+ return True
|
|
+ except Exception as e:
|
|
+ # If lambda has thrown the exception we'll re-raise it later
|
|
+ # and forget about if lambda passes
|
|
+ exception_thrown = e
|
|
+ sleep(period)
|
|
+ if exception_thrown:
|
|
+ raise exception_thrown
|
|
+ else:
|
|
+ return False
|
|
+
|
|
+
|
|
+class TimeoutError(Exception):
|
|
+ """
|
|
+ Timeout exception class for limit_execution_time_to function
|
|
+ """
|
|
+ pass
|
|
+
|
|
+
|
|
+def limit_execution_time_to(
|
|
+ seconds=10, error_message=strerror(errno.ETIME)):
|
|
+ """
|
|
+ Decorator to limit function execution to specified limit
|
|
+ """
|
|
+ def decorator(func):
|
|
+ def _handle_timeout(signum, frame):
|
|
+ raise TimeoutError(error_message)
|
|
+
|
|
+ def wrapper(*args, **kwargs):
|
|
+ signal(SIGALRM, _handle_timeout)
|
|
+ alarm(seconds)
|
|
+ try:
|
|
+ result = func(*args, **kwargs)
|
|
+ finally:
|
|
+ alarm(0)
|
|
+ return result
|
|
+
|
|
+ return wraps(func)(wrapper)
|
|
+
|
|
+ return decorator
|
|
+
|
|
+
|
|
+class App(object):
|
|
+ """
|
|
+ This class does all basic events with the app
|
|
+ """
|
|
+ def __init__(
|
|
+ self, appName, shortcut='<Control><Q>', a11yAppName=None,
|
|
+ forceKill=True, parameters='', recordVideo=False):
|
|
+ """
|
|
+ Initialize object App
|
|
+ appName command to run the app
|
|
+ shortcut default quit shortcut
|
|
+ a11yAppName app's a11y name is different than binary
|
|
+ forceKill is the app supposed to be kill before/after test?
|
|
+ parameters has the app any params needed to start? (only for startViaCommand)
|
|
+ recordVideo start gnome-shell recording while running the app
|
|
+ """
|
|
+ self.appCommand = appName
|
|
+ self.shortcut = shortcut
|
|
+ self.forceKill = forceKill
|
|
+ self.parameters = parameters
|
|
+ self.internCommand = self.appCommand.lower()
|
|
+ self.a11yAppName = a11yAppName
|
|
+ self.recordVideo = recordVideo
|
|
+ self.pid = None
|
|
+
|
|
+ # a way of overcoming overview autospawn when mouse in 1,1 from start
|
|
+ pressKey('Esc')
|
|
+ absoluteMotion(100, 100, 2)
|
|
+
|
|
+ # attempt to make a recording of the test
|
|
+ if self.recordVideo:
|
|
+ keyCombo('<Control><Alt><Shift>R')
|
|
+
|
|
+ def isRunning(self):
|
|
+ """
|
|
+ Is the app running?
|
|
+ """
|
|
+ if self.a11yAppName is None:
|
|
+ self.a11yAppName = self.internCommand
|
|
+
|
|
+ # Trap weird bus errors
|
|
+ for attempt in xrange(0, 30):
|
|
+ sleep(1)
|
|
+ try:
|
|
+ return self.a11yAppName in [x.name for x in root.applications()]
|
|
+ except GLib.GError:
|
|
+ continue
|
|
+ raise Exception("10 at-spi errors, seems that bus is blocked")
|
|
+
|
|
+ def kill(self):
|
|
+ """
|
|
+ Kill the app via 'killall'
|
|
+ """
|
|
+ if self.recordVideo:
|
|
+ keyCombo('<Control><Alt><Shift>R')
|
|
+
|
|
+ try:
|
|
+ self.process.kill()
|
|
+ except:
|
|
+ # Fall back to killall
|
|
+ Popen("killall " + self.appCommand, shell=True).wait()
|
|
+
|
|
+ def startViaCommand(self):
|
|
+ """
|
|
+ Start the app via command
|
|
+ """
|
|
+ if self.forceKill and self.isRunning():
|
|
+ self.kill()
|
|
+ assert not self.isRunning(), "Application cannot be stopped"
|
|
+
|
|
+ #command = "%s %s" % (self.appCommand, self.parameters)
|
|
+ #self.pid = run(command, timeout=5)
|
|
+ self.process = Popen(self.appCommand.split() + self.parameters.split(),
|
|
+ stdout=PIPE, stderr=PIPE, bufsize=0)
|
|
+ self.pid = self.process.pid
|
|
+
|
|
+ assert self.isRunning(), "Application failed to start"
|
|
+ return root.application(self.a11yAppName)
|
|
+
|
|
+ def closeViaShortcut(self):
|
|
+ """
|
|
+ Close the app via shortcut
|
|
+ """
|
|
+ if not self.isRunning():
|
|
+ raise Exception("App is not running")
|
|
+
|
|
+ keyCombo(self.shortcut)
|
|
+ assert not self.isRunning(), "Application cannot be stopped"
|
|
+
|
|
+
|
|
+@step(u'Start a new Evolution instance')
|
|
+def start_new_evolution_instance(context):
|
|
+ context.app = context.app_class.startViaCommand()
|
|
+
|
|
+
|
|
+def cleanup():
|
|
+ # Remove cached data and settings
|
|
+ folders = ['~/.local/share/evolution', '~/.cache/evolution', '~/.config/evolution']
|
|
+ for folder in folders:
|
|
+ system("rm -rf %s > /dev/null" % folder)
|
|
+
|
|
+ # Clean up goa data
|
|
+ system("rm -rf ~/.config/goa-1.0/accounts.conf")
|
|
+ system("killall goa-daemon 2&> /dev/null")
|
|
+
|
|
+ # Reset GSettings
|
|
+ schemas = [x for x in Gio.Settings.list_schemas() if 'evolution' in x.lower()]
|
|
+ for schema in schemas:
|
|
+ system("gsettings reset-recursively %s" % schema)
|
|
+
|
|
+ # Skip warning dialog
|
|
+ system("gsettings set org.gnome.evolution.shell skip-warning-dialog true")
|
|
+ # Show switcher buttons as icons (to minimize tree scrolling)
|
|
+ system("gsettings set org.gnome.evolution.shell buttons-style icons")
|
|
+ # Skip default mailer handler dialog
|
|
+ system("gsettings set org.gnome.evolution.mail prompt-check-if-default-mailer false")
|
|
+
|
|
+
|
|
+def check_for_errors(context):
|
|
+ """Check that no error is displayed on Evolution UI"""
|
|
+ # Don't try to check for errors on dead app
|
|
+ if not context.app or context.app.dead:
|
|
+ return
|
|
+ alerts = context.app.findChildren(lambda x: x.roleName == 'alert')
|
|
+ if not alerts:
|
|
+ # alerts can also return None
|
|
+ return
|
|
+ alerts = filter(lambda x: x.showing, alerts)
|
|
+ if len(alerts) > 0:
|
|
+ labels = alerts[0].findChildren(lambda x: x.roleName == 'label')
|
|
+ messages = [x.name for x in labels]
|
|
+
|
|
+ if alerts[0].name != 'Error' and alerts[0].showing:
|
|
+ # Erase the configuration and start all over again
|
|
+ system("evolution --force-shutdown &> /dev/null")
|
|
+
|
|
+ # Remove previous data
|
|
+ folders = ['~/.local/share/evolution', '~/.cache/evolution', '~/.config/evolution']
|
|
+ for folder in folders:
|
|
+ system("rm -rf %s > /dev/null" % folder)
|
|
+
|
|
+ raise RuntimeError("Error occurred: %s" % messages)
|
|
+
|
|
+
|
|
+def non_block_read(output):
|
|
+ fd = output.fileno()
|
|
+ fl = fcntl.fcntl(fd, fcntl.F_GETFL)
|
|
+ fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
|
|
+ try:
|
|
+ return output.read()
|
|
+ except:
|
|
+ return ""
|
|
diff -up evolution-3.13.4/tests/environment.py.missing-tests evolution-3.13.4/tests/environment.py
|
|
--- evolution-3.13.4/tests/environment.py.missing-tests 2014-07-30 11:21:47.031172903 +0200
|
|
+++ evolution-3.13.4/tests/environment.py 2014-07-30 11:21:47.031172903 +0200
|
|
@@ -0,0 +1,82 @@
|
|
+# -*- coding: UTF-8 -*-
|
|
+
|
|
+from time import sleep, localtime, strftime
|
|
+from dogtail.utils import isA11yEnabled, enableA11y
|
|
+if not isA11yEnabled():
|
|
+ enableA11y(True)
|
|
+
|
|
+from common_steps import App, dummy, cleanup, non_block_read
|
|
+from dogtail.config import config
|
|
+import os
|
|
+
|
|
+
|
|
+def before_all(context):
|
|
+ """Setup evolution stuff
|
|
+ Being executed once before any test
|
|
+ """
|
|
+
|
|
+ try:
|
|
+ # Close running evo instances
|
|
+ os.system("evolution --force-shutdown > /dev/null")
|
|
+
|
|
+ # Skip dogtail actions to print to stdout
|
|
+ config.logDebugToStdOut = False
|
|
+ config.typingDelay = 0.2
|
|
+
|
|
+ # Include assertion object
|
|
+ context.assertion = dummy()
|
|
+
|
|
+ # Cleanup existing data before any test
|
|
+ cleanup()
|
|
+
|
|
+ # Store scenario start time for session logs
|
|
+ context.log_start_time = strftime("%Y-%m-%d %H:%M:%S", localtime())
|
|
+
|
|
+ context.app_class = App('evolution')
|
|
+
|
|
+ except Exception as e:
|
|
+ print("Error in before_all: %s" % e.message)
|
|
+
|
|
+
|
|
+def after_step(context, step):
|
|
+ try:
|
|
+ if step.status == 'failed' and hasattr(context, "embed"):
|
|
+ # Embed screenshot if HTML report is used
|
|
+ os.system("dbus-send --print-reply --session --type=method_call " +
|
|
+ "--dest='org.gnome.Shell.Screenshot' " +
|
|
+ "'/org/gnome/Shell/Screenshot' " +
|
|
+ "org.gnome.Shell.Screenshot.Screenshot " +
|
|
+ "boolean:true boolean:false string:/tmp/screenshot.png")
|
|
+ context.embed('image/png', open("/tmp/screenshot.png", 'r').read())
|
|
+ except Exception as e:
|
|
+ print("Error in after_step: %s" % str(e))
|
|
+
|
|
+
|
|
+def after_scenario(context, scenario):
|
|
+ """Teardown for each scenario
|
|
+ Kill evolution (in order to make this reliable we send sigkill)
|
|
+ """
|
|
+ try:
|
|
+ # Attach journalctl logs
|
|
+ if hasattr(context, "embed"):
|
|
+ os.system("journalctl /usr/bin/gnome-session --no-pager -o cat --since='%s'> /tmp/journal-session.log" % context.log_start_time)
|
|
+ data = open("/tmp/journal-session.log", 'r').read()
|
|
+ if data:
|
|
+ context.embed('text/plain', data)
|
|
+
|
|
+ context.app_class.kill()
|
|
+
|
|
+ stdout = non_block_read(context.app_class.process.stdout)
|
|
+ stderr = non_block_read(context.app_class.process.stderr)
|
|
+
|
|
+ if stdout:
|
|
+ context.embed('text/plain', stdout)
|
|
+
|
|
+ if stderr:
|
|
+ context.embed('text/plain', stderr)
|
|
+
|
|
+ # Make some pause after scenario
|
|
+ sleep(1)
|
|
+ except Exception as e:
|
|
+ # Stupid behave simply crashes in case exception has occurred
|
|
+ print("Error in after_scenario: %s" % e.message)
|
|
diff -up evolution-3.13.4/tests/shortcuts.feature.missing-tests evolution-3.13.4/tests/shortcuts.feature
|
|
--- evolution-3.13.4/tests/shortcuts.feature.missing-tests 2014-07-30 11:21:47.032172902 +0200
|
|
+++ evolution-3.13.4/tests/shortcuts.feature 2014-07-30 11:21:47.031172903 +0200
|
|
@@ -0,0 +1,135 @@
|
|
+Feature: Shortcuts
|
|
+
|
|
+ Background:
|
|
+ * Open Evolution and setup fake account
|
|
+
|
|
+ @general_shortcuts
|
|
+ Scenario: Ctrl-Q to quit application - two instances
|
|
+ * Start a new Evolution instance
|
|
+ * Press "<Control>Q"
|
|
+ Then Evolution is closed
|
|
+
|
|
+ @general_shortcuts
|
|
+ Scenario: F1 to launch help
|
|
+ * Press "<F1>"
|
|
+ Then Help section "Evolution Mail and Calendar" is displayed
|
|
+
|
|
+ @general_shortcuts
|
|
+ Scenario: Shift-Ctrl-W to open a new window
|
|
+ * Press "<Control><Shift>W"
|
|
+ Then Evolution has 2 windows opened
|
|
+
|
|
+ @general_shortcuts
|
|
+ Scenario: Ctrl-W to close a window
|
|
+ * Press "<Control><Shift>W"
|
|
+ * Press "<Control>W"
|
|
+ Then Evolution has 1 window opened
|
|
+
|
|
+ @general_shortcuts
|
|
+ Scenario: Ctrl-Shift-S to open Preferences
|
|
+ * Press "<Control><Shift>S"
|
|
+ Then Preferences dialog is opened
|
|
+
|
|
+ @mail_shortcuts
|
|
+ Scenario: Mail: Ctrl-Shift-M to compose new message
|
|
+ * Open "Mail" section
|
|
+ * Press "<Control><Shift>M"
|
|
+ Then Message composer with title "Compose Message" is opened
|
|
+
|
|
+ @contacts_shortcuts
|
|
+ Scenario: Contacts: Ctrl-Shift-C to create new contact
|
|
+ * Open "Contacts" section
|
|
+ * Press "<Control><Shift>C"
|
|
+ Then Contact editor window is opened
|
|
+
|
|
+ @contacts_shortcuts
|
|
+ Scenario: Contacts: Ctrl-Shift-L to create new contact list
|
|
+ * Open "Contacts" section
|
|
+ * Press "<Control><Shift>L"
|
|
+ Then Contact List editor window is opened
|
|
+
|
|
+ @calendar_shortcuts
|
|
+ Scenario: Calendar: Ctrl-Shift-A to create new appointment
|
|
+ * Open "Calendar" section
|
|
+ * Press "<Control><Shift>A"
|
|
+ Then Event editor with title "Appointment - No Summary" is displayed
|
|
+
|
|
+ @calendar_shortcuts
|
|
+ Scenario: Calendar: Ctrl-Shift-E to create new meeting
|
|
+ * Open "Calendar" section
|
|
+ * Press "<Control><Shift>E"
|
|
+ Then Event editor with title "Meeting - No Summary" is displayed
|
|
+
|
|
+ @calendar_shortcuts
|
|
+ Scenario: Tasks: Ctrl-Shift-T to create new task
|
|
+ * Open "Tasks" section
|
|
+ * Press "<Control><Shift>T"
|
|
+ Then Task editor with title "Task - No Summary" is opened
|
|
+
|
|
+ @memos_shortcuts
|
|
+ Scenario: Memos: Ctrl-Shift-O to create new memo
|
|
+ * Open "Memos" section
|
|
+ * Press "<Control><Shift>O"
|
|
+ Then Memo editor with title "Memo - No Summary" is opened
|
|
+
|
|
+ @memos_shortcuts
|
|
+ Scenario: Memos: Ctrl-Shift-O to create new task
|
|
+ * Open "Memos" section
|
|
+ * Press "<Control><Shift>O"
|
|
+ Then Shared memo editor with title "Memo - No Summary" is opened
|
|
+
|
|
+ @view_shortcuts
|
|
+ Scenario Outline: Ctrl+<1-5> to switch views
|
|
+ * Press "<shortcut>"
|
|
+ Then "<section>" view is opened
|
|
+
|
|
+ Examples:
|
|
+ | shortcut | section |
|
|
+ | <Ctrl>1 | Mail |
|
|
+ | <Ctrl>2 | Contacts |
|
|
+ | <Ctrl>3 | Calendar |
|
|
+ | <Ctrl>4 | Tasks |
|
|
+ | <Ctrl>5 | Memos |
|
|
+
|
|
+ @menu_shortcuts
|
|
+ Scenario Outline: Menu shortcuts on all views
|
|
+ * Open "<section>" section
|
|
+ * Press "<shortcut>"
|
|
+ Then "<menu>" menu is opened
|
|
+
|
|
+ Examples:
|
|
+ | section | shortcut | menu |
|
|
+ | Mail | <Alt>F | File |
|
|
+ | Mail | <Alt>E | Edit |
|
|
+ | Mail | <Alt>V | View |
|
|
+ | Mail | <Alt>O | Folder |
|
|
+ | Mail | <Alt>M | Message |
|
|
+ | Mail | <Alt>S | Search |
|
|
+ | Mail | <Alt>H | Help |
|
|
+
|
|
+ | Contacts | <Alt>F | File |
|
|
+ | Contacts | <Alt>E | Edit |
|
|
+ | Contacts | <Alt>V | View |
|
|
+ | Contacts | <Alt>A | Actions |
|
|
+ | Contacts | <Alt>S | Search |
|
|
+ | Contacts | <Alt>H | Help |
|
|
+
|
|
+ | Calendar | <Alt>F | File |
|
|
+ | Calendar | <Alt>E | Edit |
|
|
+ | Calendar | <Alt>V | View |
|
|
+ | Calendar | <Alt>A | Actions |
|
|
+ | Calendar | <Alt>S | Search |
|
|
+ | Calendar | <Alt>H | Help |
|
|
+
|
|
+ | Tasks | <Alt>F | File |
|
|
+ | Tasks | <Alt>E | Edit |
|
|
+ | Tasks | <Alt>V | View |
|
|
+ | Tasks | <Alt>A | Actions |
|
|
+ | Tasks | <Alt>S | Search |
|
|
+ | Tasks | <Alt>H | Help |
|
|
+
|
|
+ | Memos | <Alt>F | File |
|
|
+ | Memos | <Alt>E | Edit |
|
|
+ | Memos | <Alt>V | View |
|
|
+ | Memos | <Alt>S | Search |
|
|
+ | Memos | <Alt>H | Help |
|
|
diff -up evolution-3.13.4/tests/steps/addressbook_steps.py.missing-tests evolution-3.13.4/tests/steps/addressbook_steps.py
|
|
--- evolution-3.13.4/tests/steps/addressbook_steps.py.missing-tests 2014-07-30 11:21:47.032172902 +0200
|
|
+++ evolution-3.13.4/tests/steps/addressbook_steps.py 2014-07-30 11:21:47.032172902 +0200
|
|
@@ -0,0 +1,391 @@
|
|
+# -*- coding: UTF-8 -*-
|
|
+from behave import step, then
|
|
+from common_steps import wait_until
|
|
+from dogtail.predicate import GenericPredicate
|
|
+from dogtail.rawinput import keyCombo
|
|
+from time import time, sleep
|
|
+from gi.repository import GLib
|
|
+import pyatspi
|
|
+
|
|
+
|
|
+@step(u'Select "{name}" addressbook')
|
|
+def select_addressbook(context, name, password=None):
|
|
+ cells = context.app.findChildren(
|
|
+ GenericPredicate(name=name, roleName='table cell'))
|
|
+ visible_cells = filter(lambda x: x.showing, cells)
|
|
+ if visible_cells == []:
|
|
+ raise RuntimeError("Cannot find addressbook '%s'" % name)
|
|
+ visible_cells[0].click()
|
|
+ # Wait for addressbook to load
|
|
+ try:
|
|
+ spinner = context.app.findChild(
|
|
+ GenericPredicate(name='Spinner'), retry=False, requireResult=False)
|
|
+ if spinner:
|
|
+ start_time = time()
|
|
+ while spinner.showing:
|
|
+ sleep(1)
|
|
+ if (time() - start_time) > 180:
|
|
+ raise RuntimeError("Contacts take too long to synchronize")
|
|
+ except (GLib.GError, TypeError):
|
|
+ pass
|
|
+
|
|
+
|
|
+@step(u'Change categories view to "{category}"')
|
|
+def change_categories_view(context, category):
|
|
+ labels = context.app.findChildren(
|
|
+ lambda x: x.labeller.name == 'Show:' and x.showing)
|
|
+ if labels == []:
|
|
+ raise RuntimeError("Cannot find category switcher")
|
|
+ labels[0].combovalue = category
|
|
+
|
|
+
|
|
+@step(u'Delete selected contact')
|
|
+def delete_selected_contact(context):
|
|
+ context.app.menu('Edit').click()
|
|
+ mnu = context.app.menu('Edit').menuItem("Delete Contact")
|
|
+ if pyatspi.STATE_ENABLED in mnu.getState().getStates():
|
|
+ context.app.menu('Edit').menuItem("Delete Contact").click()
|
|
+
|
|
+ alert = context.app.child(roleName='alert', name='Question')
|
|
+ alert.button('Delete').click()
|
|
+ context.execute_steps(u"* Wait for email to synchronize")
|
|
+
|
|
+
|
|
+@step(u'Delete all contacts containing "{part}"')
|
|
+def delete_all_contacts_containing(context, part):
|
|
+ context.app.search_bar.grab_focus()
|
|
+ for attempts in range(0, 10):
|
|
+ try:
|
|
+ context.app.search_bar.text = part
|
|
+ break
|
|
+ except (GLib.GError, AttributeError):
|
|
+ sleep(0.1)
|
|
+ continue
|
|
+ keyCombo("<Enter>")
|
|
+ context.execute_steps(u"* Wait for email to synchronize")
|
|
+ context.app.search_bar.grab_focus()
|
|
+ keyCombo("<Tab>")
|
|
+ sleep(3)
|
|
+ heading = context.app.findChild(
|
|
+ GenericPredicate(roleName='heading'),
|
|
+ retry=False, requireResult=False)
|
|
+ if heading:
|
|
+ keyCombo("<Control>a")
|
|
+ context.execute_steps(u"* Delete selected contact")
|
|
+ sleep(3)
|
|
+
|
|
+
|
|
+@step(u'Create a new contact')
|
|
+def create_a_new_contact(context):
|
|
+ context.app.menu('File').click()
|
|
+ context.app.menu('File').menu('New').point()
|
|
+ context.app.menu('File').menu('New').menuItem("Contact").click()
|
|
+ context.execute_steps(u"Then Contact editor window is opened")
|
|
+
|
|
+
|
|
+def get_element_by_name(contact_editor, name, section=None):
|
|
+ """Get a field object by name in section (if specified)"""
|
|
+ element = None
|
|
+ if section:
|
|
+ panel = contact_editor.findChild(
|
|
+ GenericPredicate(roleName='panel', name=section), retry=False, requireResult=False)
|
|
+ if not panel:
|
|
+ # Other section is not a panel, but a toggle button
|
|
+ panel = contact_editor.child(roleName='toggle button', name=section)
|
|
+ element = panel.childLabelled(name)
|
|
+ else:
|
|
+ label = contact_editor.findChild(
|
|
+ GenericPredicate(label=name), retry=False, requireResult=False)
|
|
+ if not label:
|
|
+ # In case childLabelled is missing
|
|
+ # Find a filler with this name and get its text child
|
|
+ element = contact_editor.child(
|
|
+ roleName='filler', name=name).child(roleName='text')
|
|
+ else:
|
|
+ element = contact_editor.childLabelled(name)
|
|
+ if element:
|
|
+ return element
|
|
+ else:
|
|
+ raise RuntimeError("Cannot find element named '%s' in section '%s'" % (
|
|
+ name, section))
|
|
+
|
|
+
|
|
+@step(u'Set "{field_name}" in contact editor to "{field_value}"')
|
|
+def set_field_to_value(context, field_name, field_value):
|
|
+ element = get_element_by_name(context.app.contact_editor, field_name)
|
|
+ if element.roleName == "text":
|
|
+ element.text = field_value
|
|
+ elif element.roleName == "combo box":
|
|
+ if element.combovalue != field_value:
|
|
+ element.combovalue = field_value
|
|
+
|
|
+
|
|
+@step(u'Save the contact')
|
|
+def save_contact(context):
|
|
+ context.app.contact_editor.button('Save').click()
|
|
+ assert wait_until(lambda x: not x.showing, context.app.contact_editor),\
|
|
+ "Contact Editor was not hidden"
|
|
+ assert wait_until(lambda x: x.dead, context.app.contact_editor),\
|
|
+ "Contact Editor was not closed"
|
|
+ context.app.contact_editor = None
|
|
+
|
|
+
|
|
+@step(u'Refresh addressbook')
|
|
+def refresh_addressbook(context):
|
|
+ #Clear the search
|
|
+ icons = context.app.search_bar.findChildren(lambda x: x.roleName == 'icon')
|
|
+ if icons != []:
|
|
+ icons[-1].click()
|
|
+ else:
|
|
+ for attempts in range(0, 10):
|
|
+ try:
|
|
+ context.app.search_bar.text = ''
|
|
+ break
|
|
+ except (GLib.GError, AttributeError):
|
|
+ sleep(0.1)
|
|
+ continue
|
|
+ context.app.search_bar.grab_focus()
|
|
+ keyCombo('<Enter>')
|
|
+ context.execute_steps(u"* Wait for email to synchronize")
|
|
+
|
|
+
|
|
+@step(u'Select "{contact_name}" contact list')
|
|
+@step(u'Select "{contact_name}" contact')
|
|
+def select_contact_with_name(context, contact_name):
|
|
+ # heading shows the name of currently selected contact
|
|
+ # We have to keep on pressing Tab to select the next contact
|
|
+ # Until we meet the first contact
|
|
+ # WARNING - what if we will have two identical contacts?
|
|
+ fail = False
|
|
+ selected_contact = None
|
|
+
|
|
+ # HACK
|
|
+ # To make the contact table appear
|
|
+ # we need to focus on search window
|
|
+ # and send Tabs to have the first contact focused
|
|
+ context.app.search_bar.grab_focus()
|
|
+ sleep(0.1)
|
|
+ # Switch to 'Any field contains' (not reachable in 3.6)
|
|
+ icons = context.app.search_bar.findChildren(GenericPredicate(roleName='icon'))
|
|
+
|
|
+ if icons != []:
|
|
+ icons[0].click()
|
|
+ wait_until(lambda x: x.findChildren(
|
|
+ GenericPredicate(roleName='check menu item', name='Any field contains')) != [],
|
|
+ context.app)
|
|
+ context.app.menuItem('Any field contains').click()
|
|
+ for attempts in range(0, 10):
|
|
+ try:
|
|
+ context.app.search_bar.text = contact_name
|
|
+ break
|
|
+ except (GLib.GError, AttributeError):
|
|
+ sleep(0.1)
|
|
+ continue
|
|
+ keyCombo("<Enter>")
|
|
+ context.app.search_bar.grab_focus()
|
|
+
|
|
+ keyCombo("<Tab>")
|
|
+ first_contact_name = context.app.child(roleName='heading').text
|
|
+
|
|
+ while True:
|
|
+ selected_contact = context.app.child(roleName='heading')
|
|
+ if selected_contact.text == contact_name:
|
|
+ fail = False
|
|
+ break
|
|
+ keyCombo("<Tab>")
|
|
+ # Wait until contact data is being rendered
|
|
+ sleep(1)
|
|
+ if first_contact_name == selected_contact.text:
|
|
+ fail = True
|
|
+ break
|
|
+
|
|
+ context.assertion.assertFalse(
|
|
+ fail, "Can't find contact named '%s'" % contact_name)
|
|
+ context.selected_contact_text = selected_contact.text
|
|
+
|
|
+
|
|
+@step(u'Open contact editor for selected contact')
|
|
+def open_contact_editor_for_selected_contact(context):
|
|
+ context.app.menu('File').click()
|
|
+ context.app.menu('File').menuItem('Open Contact').click()
|
|
+ context.execute_steps(u"""
|
|
+ Then Contact editor window with title "Contact Editor - %s" is opened
|
|
+ """ % context.selected_contact_text)
|
|
+
|
|
+
|
|
+@then(u'"{field}" property is set to "{expected}"')
|
|
+def property_in_contact_window_is_set_to(context, field, expected):
|
|
+ element = get_element_by_name(context.app.contact_editor, field)
|
|
+ actual = None
|
|
+ if element.roleName == "text":
|
|
+ actual = element.text
|
|
+ elif element.roleName == "combo box":
|
|
+ actual = element.combovalue
|
|
+ if actual == '':
|
|
+ actual = element.textentry('').text
|
|
+ assert unicode(actual) == expected, "Incorrect value"
|
|
+
|
|
+
|
|
+def get_combobox_textbox_object(contact_editor, section, scroll_to_bottom=True):
|
|
+ """Get a list of paired 'combobox-textbox' objects in contact editor"""
|
|
+ section_names = {
|
|
+ 'Ims': 'Instant Messaging',
|
|
+ 'Phones': 'Telephone',
|
|
+ 'Emails': 'Email'}
|
|
+ section = section_names[section.capitalize()]
|
|
+ lbl = contact_editor.child(roleName='label', name=section)
|
|
+ panel = lbl.findAncestor(GenericPredicate(roleName='panel'))
|
|
+ textboxes = panel.findChildren(GenericPredicate(roleName='text'))
|
|
+
|
|
+ # Scroll to the bottom of the page if needed
|
|
+ pagetab = panel.findAncestor(GenericPredicate(roleName='page tab'))
|
|
+ for scroll in pagetab.findChildren(lambda x: x.roleName == 'scroll bar'):
|
|
+ if scroll_to_bottom:
|
|
+ scroll.value = scroll.maxValue
|
|
+ else:
|
|
+ scroll.value = 0
|
|
+
|
|
+ # Expand section if button exists
|
|
+ button = panel.findChild(
|
|
+ GenericPredicate(roleName='push button', name=section),
|
|
+ retry=False, requireResult=False)
|
|
+ # Expand button if any of textboxes is not visible
|
|
+ if button and (False in [x.showing for x in textboxes]):
|
|
+ button.click()
|
|
+
|
|
+ comboboxes = panel.findChildren(GenericPredicate(roleName='combo box'))
|
|
+
|
|
+ # Rearrange comboboxes and textboxes according to their position
|
|
+ result = []
|
|
+ for combo in comboboxes:
|
|
+ combo_row = combo.position[1]
|
|
+ matching_textboxes = [
|
|
+ x for x in textboxes
|
|
+ if ((x.position[1] - combo_row) == 0) and (x.position[0] > combo.position[0])]
|
|
+ if (matching_textboxes != []):
|
|
+ correct_textbox = min(matching_textboxes, key=lambda x: x.position[0])
|
|
+ result.append((combo, correct_textbox))
|
|
+
|
|
+ comboboxes = [x[0] for x in result][::-1]
|
|
+ textboxes = [x[1] for x in result][::-1]
|
|
+
|
|
+ return (textboxes, comboboxes, button)
|
|
+
|
|
+
|
|
+@step(u'Set {section} in contact editor to')
|
|
+def set_contact_emails_to_value(context, section):
|
|
+ (textboxes, comboboxes, collapse_button) = get_combobox_textbox_object(
|
|
+ context.app.contact_editor, section)
|
|
+
|
|
+ # clear existing data
|
|
+ for textbox in textboxes:
|
|
+ textbox.text = ""
|
|
+
|
|
+ for index, row in enumerate(context.table.rows):
|
|
+ # Check that we have sufficient amount of textboxes
|
|
+ # If not - click plus buttons until we have enough
|
|
+ if index == len(textboxes):
|
|
+ textboxes[0].parent.child(roleName="push button").click()
|
|
+ (textboxes, comboboxes, collapse_button) = get_combobox_textbox_object(
|
|
+ context.app.contact_editor, section)
|
|
+ textboxes[index].text = row['Value']
|
|
+ if comboboxes[index].combovalue != row['Field']:
|
|
+ comboboxes[index].combovalue = row['Field']
|
|
+
|
|
+
|
|
+@then(u'{section} are set to')
|
|
+def emails_are_set_to(context, section):
|
|
+ (textboxes, comboboxes, collapse_button) = get_combobox_textbox_object(
|
|
+ context.app.contact_editor, section, section == 'IMs')
|
|
+
|
|
+ actual = []
|
|
+ for index, textbox in enumerate(textboxes):
|
|
+ combo_value = textbox.text
|
|
+ if combo_value.strip() != '':
|
|
+ type_value = comboboxes[index].combovalue
|
|
+ actual.append({'Field': unicode(type_value), 'Value': unicode(combo_value)})
|
|
+ actual = sorted(actual)
|
|
+
|
|
+ expected = []
|
|
+ for row in context.table:
|
|
+ expected.append({'Field': row['Field'], 'Value': row['Value']})
|
|
+ expected = sorted(expected)
|
|
+
|
|
+ assert actual == expected, "Incorrect %s value:\nexpected:%s\n but was:%s" % (
|
|
+ row['Field'], expected, actual)
|
|
+
|
|
+ # Collapse the section after check
|
|
+ collapse_button.click()
|
|
+
|
|
+
|
|
+@step(u'Tick "Wants to receive HTML mail" checkbox')
|
|
+def tick_checkbox(context):
|
|
+ context.app.contact_editor.childNamed("Wants to receive HTML mail").click()
|
|
+
|
|
+
|
|
+@step(u'"Wants to receive HTML mail" checkbox is ticked')
|
|
+def checkbox_is_ticked(context):
|
|
+ check_state = context.app.childNamed("Wants to receive HTML mail").checked
|
|
+ assert check_state, "Incorrect checkbox state"
|
|
+
|
|
+
|
|
+@step(u'Switch to "{name}" tab in contact editor')
|
|
+def switch_to_tab(context, name):
|
|
+ context.app.contact_editor.tab(name).click()
|
|
+
|
|
+
|
|
+@step(u'Set the following properties in contact editor')
|
|
+def set_properties(context):
|
|
+ for row in context.table.rows:
|
|
+ context.execute_steps(u"""
|
|
+ * Set "%s" in contact editor to "%s"
|
|
+ """ % (row['Field'], row['Value']))
|
|
+
|
|
+
|
|
+@step(u'The following properties in contact editor are set')
|
|
+def verify_properties(context):
|
|
+ for row in context.table.rows:
|
|
+ context.execute_steps(u"""
|
|
+ Then "%s" property is set to "%s"
|
|
+ """ % (row['Field'], row['Value']))
|
|
+
|
|
+
|
|
+@step(u'Set the following properties in "{section}" section of contact editor')
|
|
+def set_properties_in_section(context, section):
|
|
+ for row in context.table.rows:
|
|
+ context.execute_steps(u"""
|
|
+ * Set "%s" in "%s" section of contact editor to "%s"
|
|
+ """ % (row['Field'], section, row['Value']))
|
|
+
|
|
+
|
|
+@step(u'The following properties in "{section}" section of contact editor are set')
|
|
+def verify_properties_in_section(context, section):
|
|
+ for row in context.table.rows:
|
|
+ context.execute_steps(u"""
|
|
+ Then "%s" property in "%s" section is set to "%s"
|
|
+ """ % (row['Field'], section, row['Value']))
|
|
+
|
|
+
|
|
+@step(u'Set the following note for the contact')
|
|
+def set_note_for_contact(context):
|
|
+ context.app.contact_editor.child(
|
|
+ roleName='page tab', name='Notes').textentry('').text = context.text
|
|
+
|
|
+
|
|
+@then(u'The following note is set for the contact')
|
|
+def verify_note_set_for_contact(context):
|
|
+ actual = context.app.contact_editor.child(
|
|
+ roleName='page tab', name='Notes').textentry('').text
|
|
+ expected = context.text
|
|
+ assert actual == expected,\
|
|
+ "Incorrect note value:\nexpected:%s\n but was:%s" % (expected, actual)
|
|
+
|
|
+
|
|
+@step(u'Set "{field_name}" in "{section}" section of contact editor to "{field_value}"')
|
|
+def set_field_in_section_to_value(context, field_name, section, field_value):
|
|
+ element = get_element_by_name(
|
|
+ context.app.contact_editor, field_name, section=section)
|
|
+ if element.roleName == "text":
|
|
+ element.text = field_value
|
|
+ elif element.roleName == "combo box":
|
|
+ element.combovalue = field_value
|
|
diff -up evolution-3.13.4/tests/steps/initial_setup_steps.py.missing-tests evolution-3.13.4/tests/steps/initial_setup_steps.py
|
|
--- evolution-3.13.4/tests/steps/initial_setup_steps.py.missing-tests 2014-07-30 11:21:47.032172902 +0200
|
|
+++ evolution-3.13.4/tests/steps/initial_setup_steps.py 2014-07-30 11:21:47.032172902 +0200
|
|
@@ -0,0 +1,130 @@
|
|
+# -*- coding: UTF-8 -*-
|
|
+from behave import step
|
|
+
|
|
+from common_steps import check_for_errors
|
|
+from dogtail.tree import root
|
|
+from os import system
|
|
+from pyatspi import STATE_SENSITIVE
|
|
+from time import sleep
|
|
+
|
|
+
|
|
+@step(u'Open Evolution and setup fake account')
|
|
+def open_evolution_and_setup_fake_account(context):
|
|
+ system("evolution --force-shutdown 2&> /dev/null")
|
|
+ context.execute_steps(u'* Start a new Evolution instance')
|
|
+ window = context.app.child(roleName='frame')
|
|
+ if window.name == 'Welcome':
|
|
+ context.execute_steps(u"""
|
|
+ * Complete Welcome dialog in Evolution Account Assistant
|
|
+ * Complete Restore from Backup dialog in Evolution Account Assistant
|
|
+ * Complete Identity dialog setting name to "GNOME QE User" and email address to "test@test"
|
|
+ * Wait for account is being looked up dialog in Evolution Account Assistant
|
|
+ * Complete Receiving Email dialog of Evolution Account Assistant setting
|
|
+ | Field | Value |
|
|
+ | Server Type: | None |
|
|
+ * Complete Sending Email dialog of Evolution Account Assistant setting
|
|
+ | Field | Value |
|
|
+ | Server Type: | Sendmail |
|
|
+ * Complete Account Summary in Evolution Account Assistant
|
|
+ * Complete Done dialog in Evolution Account Assistant
|
|
+ """)
|
|
+
|
|
+
|
|
+@step(u'Complete Receiving Options in Evolution Account Assistant')
|
|
+@step(u'Complete Account Summary in Evolution Account Assistant')
|
|
+@step(u'Complete Restore from Backup dialog in Evolution Account Assistant')
|
|
+@step(u'Complete Welcome dialog in Evolution Account Assistant')
|
|
+def evo_account_assistant_dummy_dialogs(context):
|
|
+ # nothing to do here, skip it
|
|
+ window = context.app.child(roleName='frame')
|
|
+ click_next(window)
|
|
+
|
|
+
|
|
+@step(u'Complete Identity dialog setting name to "{name}" and email address to "{email}"')
|
|
+def evo_account_assistant_identity_dialog(context, name, email):
|
|
+ # nothing to do here, skip it
|
|
+ window = context.app.child(roleName='frame')
|
|
+ window.childLabelled("Full Name:").text = name
|
|
+ window.childLabelled("Email Address:").text = email
|
|
+ click_next(window)
|
|
+
|
|
+
|
|
+@step(u"Wait for account is being looked up dialog in Evolution Account Assistant")
|
|
+def wait_for_account_to_be_looked_up(context):
|
|
+ window = context.app.child(roleName='frame')
|
|
+ skip_lookup = window.findChildren(lambda x: x.name == 'Skip Lookup')
|
|
+ visible_skip_lookup = [x for x in skip_lookup if x.showing]
|
|
+ if len(visible_skip_lookup) > 0:
|
|
+ visible_skip_lookup = visible_skip_lookup[0]
|
|
+ # bug https://bugzilla.gnome.org/show_bug.cgi?id=726539: Skip Lookup is not being removed
|
|
+ #assert wait_until(lambda x: not x.showing, visible_skip_lookup),\
|
|
+ # "Skip Lookup button didn't dissappear"
|
|
+
|
|
+
|
|
+def click_next(window):
|
|
+ # As initial wizard dialog creates a bunch of 'Next' buttons
|
|
+ # We have to click to the visible and enabled one
|
|
+ buttons = window.findChildren(lambda x: x.name == 'Next' and x.showing and
|
|
+ STATE_SENSITIVE in x.getState().getStates())
|
|
+ if buttons == []:
|
|
+ raise Exception("Enabled Next button was not found")
|
|
+ else:
|
|
+ buttons[0].click()
|
|
+
|
|
+
|
|
+@step(u'Complete {sending_or_receiving} Email dialog of Evolution Account Assistant setting')
|
|
+def evo_account_assistant_receiving_email_dialog_from_table(context, sending_or_receiving):
|
|
+ window = context.app.child(roleName='frame')
|
|
+ for row in context.table:
|
|
+ label = str(row['Field'])
|
|
+ value = str(row['Value'])
|
|
+ filler = window.child(roleName='filler', name='%s Email' % sending_or_receiving)
|
|
+ widgets = filler.findChildren(lambda x: x.showing)
|
|
+ visible_widgets = [x for x in widgets if x.labeller and x.labeller.name == label]
|
|
+ if len(visible_widgets) == 0:
|
|
+ raise RuntimeError("Cannot find visible widget labelled '%s'" % label)
|
|
+ widget = visible_widgets[0]
|
|
+ if widget.roleName == 'combo box':
|
|
+ if label != 'Port:':
|
|
+ widget.click()
|
|
+ widget.menuItem(value).click()
|
|
+ else:
|
|
+ # Port is a combobox, but you can type your port there
|
|
+ widget.textentry('').text = value
|
|
+ widget.textentry('').grab_focus()
|
|
+ widget.textentry('').keyCombo("<Enter>")
|
|
+ if widget.roleName == 'text':
|
|
+ widget.text = value
|
|
+
|
|
+ # Check for password here and accept self-generated certificate (if appears)
|
|
+ btns = window.findChildren(lambda x: x.name == 'Check for Supported Types')
|
|
+ visible_btns = [w for w in btns if w.showing]
|
|
+ if visible_btns == []:
|
|
+ click_next(window)
|
|
+ return
|
|
+ visible_btns[0].click()
|
|
+
|
|
+ # Confirm all certificates by clicking 'Accept Permanently' until dialog is visible
|
|
+ apps = [x.name for x in root.applications()]
|
|
+ if 'evolution-user-prompter' in apps:
|
|
+ prompter = root.application('evolution-user-prompter')
|
|
+ dialog = prompter.child(roleName='dialog')
|
|
+ while dialog.showing:
|
|
+ if prompter.findChild(lambda x: x.name == 'Accept Permanently', retry=False, requireResult=False):
|
|
+ prompter.button('Accept Permanently').click()
|
|
+ else:
|
|
+ sleep(0.1)
|
|
+
|
|
+ # Wait until Cancel button disappears
|
|
+ cancel = filler.findChildren(lambda x: x.name == 'Cancel')[0]
|
|
+ while cancel.showing:
|
|
+ sleep(0.1)
|
|
+ check_for_errors(context)
|
|
+ click_next(window)
|
|
+
|
|
+
|
|
+@step(u'Complete Done dialog in Evolution Account Assistant')
|
|
+def evo_account_assistant_done_dialog(context):
|
|
+ # nothing to do here, skip it
|
|
+ window = context.app.child(roleName='frame')
|
|
+ window.button('Apply').click()
|
|
diff -up evolution-3.13.4/tests/steps/steps.py.missing-tests evolution-3.13.4/tests/steps/steps.py
|
|
--- evolution-3.13.4/tests/steps/steps.py.missing-tests 2014-07-30 11:21:47.032172902 +0200
|
|
+++ evolution-3.13.4/tests/steps/steps.py 2014-07-30 11:21:47.032172902 +0200
|
|
@@ -0,0 +1,177 @@
|
|
+# -*- coding: UTF-8 -*-
|
|
+from behave import step, then
|
|
+from common_steps import wait_until
|
|
+from dogtail.tree import root
|
|
+from dogtail.rawinput import keyCombo
|
|
+from time import sleep, time
|
|
+from os import system
|
|
+from gi.repository import Gio, GLib
|
|
+
|
|
+
|
|
+@step(u'Help section "{name}" is displayed')
|
|
+def help_is_displayed(context, name):
|
|
+ try:
|
|
+ context.yelp = root.application('yelp')
|
|
+ frame = context.yelp.child(roleName='frame')
|
|
+ wait_until(lambda x: x.showing, frame)
|
|
+ sleep(1)
|
|
+ context.assertion.assertEquals(name, frame.name)
|
|
+ finally:
|
|
+ system("killall yelp")
|
|
+
|
|
+
|
|
+@step(u'Evolution has {num:d} window opened')
|
|
+@step(u'Evolution has {num:d} windows opened')
|
|
+def evolution_has_num_windows_opened(context, num):
|
|
+ windows = context.app.findChildren(lambda x: x.roleName == 'frame')
|
|
+ context.assertion.assertEqual(len(windows), num)
|
|
+
|
|
+
|
|
+@step(u'Preferences dialog is opened')
|
|
+def preferences_dialog_opened(context):
|
|
+ context.app.window('Evolution Preferences')
|
|
+
|
|
+
|
|
+@step(u'"{name}" view is opened')
|
|
+def view_is_opened(context, name):
|
|
+ if name != 'Mail':
|
|
+ window_name = context.app.children[0].name
|
|
+ context.assertion.assertEquals(window_name, "%s - Evolution" % name)
|
|
+ else:
|
|
+ # A special case for Mail
|
|
+ context.assertion.assertTrue(context.app.menu('Message').showing)
|
|
+
|
|
+
|
|
+def get_visible_searchbar(context):
|
|
+ """Wait for searchbar to become visible"""
|
|
+ def get_searchbars():
|
|
+ return context.app.findChildren(lambda x: x.labeller.name == 'Search:' and x.showing)
|
|
+ assert wait_until(lambda x: len(x()) > 0, get_searchbars), "No visible searchbars found"
|
|
+ return get_searchbars()[0]
|
|
+
|
|
+
|
|
+@step(u'Open "{section_name}" section')
|
|
+def open_section_by_name(context, section_name):
|
|
+ wait_until(lambda x: x.showing, context.app.menu('View'))
|
|
+ sleep(0.2)
|
|
+ context.app.menu('View').click()
|
|
+ context.app.menu('View').menu('Window').point()
|
|
+ context.app.menu('View').menu('Window').menuItem(section_name).click()
|
|
+
|
|
+ # Find a search bar
|
|
+ context.app.search_bar = get_visible_searchbar(context)
|
|
+
|
|
+ # Check that service required for this sections is running
|
|
+ required_services = {
|
|
+ 'Mail': 'org.gnome.evolution.dataserver.Sources',
|
|
+ 'Calendar': 'org.gnome.evolution.dataserver.Calendar',
|
|
+ 'Tasks': 'org.gnome.evolution.dataserver.Calendar',
|
|
+ 'Memos': 'org.gnome.evolution.dataserver.Calendar',
|
|
+ 'Contacts': 'org.gnome.evolution.dataserver.AddressBook',
|
|
+ }
|
|
+ required_service = required_services[section_name]
|
|
+ bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
|
|
+ dbus_proxy = Gio.DBusProxy.new_sync(bus, Gio.DBusProxyFlags.NONE, None,
|
|
+ 'org.freedesktop.DBus',
|
|
+ '/org/freedesktop/DBus',
|
|
+ 'org.freedesktop.DBus', None)
|
|
+ for attempt in xrange(0, 10):
|
|
+ result = dbus_proxy.call_sync(
|
|
+ 'ListNames', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None)
|
|
+ sleep(1)
|
|
+ if True in [required_service in x for x in result[0]]:
|
|
+ return
|
|
+ raise RuntimeError("%s service was not found" % required_service)
|
|
+
|
|
+
|
|
+@step(u'"{name}" menu is opened')
|
|
+def menu_is_opened(context, name):
|
|
+ sleep(0.5)
|
|
+ menu = context.app.menu(name)
|
|
+ children_displayed = [x.showing for x in menu.children]
|
|
+ context.assertion.assertTrue(True in children_displayed, "Menu '%s' is not opened" % name)
|
|
+
|
|
+
|
|
+@step(u'Press "{sequence}"')
|
|
+def press_button_sequence(context, sequence):
|
|
+ keyCombo(sequence)
|
|
+ sleep(0.5)
|
|
+
|
|
+
|
|
+@then(u'Evolution is closed')
|
|
+def evolution_is_closed(context):
|
|
+ assert wait_until(lambda x: x.dead, context.app),\
|
|
+ "Evolution window is opened"
|
|
+ context.assertion.assertFalse(context.app_class.isRunning(), "Evolution is in the process list")
|
|
+
|
|
+
|
|
+@step(u'Message composer with title "{name}" is opened')
|
|
+def message_composer_is_opened(context, name):
|
|
+ context.app.composer = context.app.window(name)
|
|
+
|
|
+
|
|
+@then(u'Contact editor window with title "{title}" is opened')
|
|
+def contact_editor_with_label_is_opened(context, title):
|
|
+ context.app.contact_editor = context.app.dialog(title)
|
|
+ context.assertion.assertIsNotNone(
|
|
+ context.app.contact_editor, "Contact Editor was not found")
|
|
+ context.assertion.assertTrue(
|
|
+ context.app.contact_editor.showing, "Contact Editor didn't appear")
|
|
+
|
|
+
|
|
+@then(u'Contact editor window is opened')
|
|
+def contact_editor_is_opened(context):
|
|
+ context.execute_steps(u'Then Contact editor window with title "Contact Editor" is opened')
|
|
+
|
|
+
|
|
+@then(u'Contact List editor window is opened')
|
|
+def contact_list_editor_is_opened(context):
|
|
+ context.execute_steps(
|
|
+ u'Then Contact List editor window with title "Contact List Editor" is opened')
|
|
+
|
|
+
|
|
+@then(u'Contact List editor window with title "{name}" is opened')
|
|
+def contact_list_editor__with_name_is_opened(context, name):
|
|
+ context.app.contact_list_editor = context.app.dialog(name)
|
|
+
|
|
+
|
|
+@step(u'Memo editor with title "{name}" is opened')
|
|
+def memo_editor_is_opened(context, name):
|
|
+ context.execute_steps(u'* Task editor with title "%s" is opened' % name)
|
|
+
|
|
+
|
|
+@step(u'Shared Memo editor with title "{name}" is opened')
|
|
+def shared_memo_editor_is_opened(context, name):
|
|
+ context.execute_steps(u'* Task editor with title "%s" is opened' % name)
|
|
+
|
|
+
|
|
+@step(u'Task editor with title "{title}" is opened')
|
|
+def task_editor_with_title_is_opened(context, title):
|
|
+ context.app.task_editor = context.app.window(title)
|
|
+ # Spoof event_editor for assigned tasks
|
|
+ if 'Assigned' in title:
|
|
+ context.app.event_editor = context.app.task_editor
|
|
+
|
|
+
|
|
+@step(u'Event editor with title "{name}" is displayed')
|
|
+def event_editor_with_name_displayed(context, name):
|
|
+ context.app.event_editor = context.app.window(name)
|
|
+
|
|
+
|
|
+@step(u'Wait for email to synchronize')
|
|
+def wait_for_mail_folder_to_synchronize(context):
|
|
+ # Wait until Google calendar is loaded
|
|
+ for attempt in range(0, 10):
|
|
+ start_time = time()
|
|
+ try:
|
|
+ spinners = context.app.findChildren(lambda x: x.name == 'Spinner')
|
|
+ for spinner in spinners:
|
|
+ try:
|
|
+ while spinner.showing:
|
|
+ sleep(0.1)
|
|
+ if (time() - start_time) > 180:
|
|
+ raise RuntimeError("Mail takes too long to synchronize")
|
|
+ except GLib.GError:
|
|
+ continue
|
|
+ except (GLib.GError, TypeError):
|
|
+ continue
|