1
0
mirror of https://github.com/mail-in-a-box/mailinabox.git synced 2026-03-12 17:07:23 +01:00

qa: add core code for browser-based testing and tests for changing user passwords and adding contacts in roundcube

This commit is contained in:
downtownallday
2022-11-09 23:08:25 -05:00
parent c743ebe606
commit b4624b35eb
16 changed files with 1140 additions and 29 deletions

1
tests/suites/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
screenshot.png

View File

@@ -17,11 +17,14 @@ set +eu
. suites/_mail-functions.sh || exit 1
. suites/_mgmt-functions.sh || exit 1
. suites/_zpush-functions.sh || exit 1
. suites/_ui-functions.sh || exit 1
MIAB_DIR=".."
PYMAIL="./test_mail.py"
EDITCONF="../tools/editconf.py"
UI_TESTS_PYTHONPATH=$(realpath "lib/python")
UI_TESTS_VERBOSITY=2
# options
SKIP_REMOTE_SMTP_TESTS=no

View File

@@ -0,0 +1,44 @@
#####
##### This file is part of Mail-in-a-Box-LDAP which is released under the
##### terms of the GNU Affero General Public License as published by the
##### Free Software Foundation, either version 3 of the License, or (at
##### your option) any later version. See file LICENSE or go to
##### https://github.com/downtownallday/mailinabox-ldap for full license
##### details.
#####
run_browser_test() {
local assert=false
if [ "$1" = "assert" ]; then
assert=true
shift
fi
local path="$1" # relative to suites directory. eg "roundcube/mytest.py"
shift; # remaining arguments are passed to the test
record "[launching ui test $path $*]"
record "PYTHONPATH=$UI_TESTS_PYTHONPATH"
record "BROWSER_TESTS_VERBOSITY=${UI_TESTS_VERBOSITY:-1}"
record "BROWSER_TESTS_OUTPUT_PATH=${TEST_OF}_ui"
local output
output=$(
export PYTHONPATH="$UI_TESTS_PYTHONPATH";
export BROWSER_TESTS_VERBOSITY=${UI_TESTS_VERBOSITY:-1};
export BROWSER_TESTS_OUTPUT_PATH="${TEST_OF}_ui";
python3 suites/$path "$@" 2>&1
)
local code=$?
record "RESULT: $code"
record "OUTPUT:"; record "$output"
if [ $code -ne 0 ] && $assert; then
test_failure "ui test failed: $(python_error "$output")"
fi
return $code
}
assert_browser_test() {
run_browser_test "assert" "$@"
return $?
}

View File

@@ -0,0 +1,88 @@
#####
##### This file is part of Mail-in-a-Box-LDAP which is released under the
##### terms of the GNU Affero General Public License as published by the
##### Free Software Foundation, either version 3 of the License, or (at
##### your option) any later version. See file LICENSE or go to
##### https://github.com/downtownallday/mailinabox-ldap for full license
##### details.
#####
from browser.automation import (
TestDriver,
TimeoutException,
NoSuchElementException,
ElementNotInteractableException,
)
from browser.NextcloudAutomation import NextcloudAutomation
import sys
op = sys.argv[1]
login = sys.argv[2]
pw = sys.argv[3]
contact = {
'givenname': sys.argv[4],
'surname': sys.argv[5],
'email': sys.argv[6],
}
d = TestDriver()
nc = NextcloudAutomation(d)
try:
#
# open the browser to Nextcloud
#
# these tests work for both remote and local Nextclouds. nginx
# will redirect to a remote nextcloud during get(), if configured
#
d.start("Opening Nextcloud")
d.get("/cloud/")
nc.wait_for_login_screen()
d.say_verbose('url: ' + d.current_url())
#
# login, then open the contacts app
#
nc.login(login, pw)
nc.wait_for_app_load()
nc.open_contacts()
nc.wait_for_app_load()
#
# handle selected operation
#
if op=='exists':
d.start("Check that contact %s exists", contact['email'])
nc.click_contact(contact) # raises NoSuchElementException if not found
elif op=='delete':
d.start("Delete contact %s", contact['email'])
nc.click_contact(contact)
nc.wait_contact_loaded()
# click "..." menu
d.find_el('.contact-header__actions button.action-item__menutoggle').click()
d.wait_for_el('.popover', must_be_displayed=True, secs=2)
# click "delete"
d.find_el('.popover span.icon-delete').parent().click()
d.wait_for_el('div.empty-content', secs=2)
else:
raise ValueError('Invalid operation: %s' % op)
#
# logout
#
nc.logout()
nc.wait_for_login_screen()
#
# done
#
d.say("Success!")
except Exception as e:
d.fail(e)
raise
finally:
d.quit()

View File

@@ -127,12 +127,6 @@ test_nextcloud_contacts() {
carddav_delete_contact "$alice" "$alice_pw" "$c_uid" 2>>$TEST_OF || \
test_failure "Unable to delete contact for $alice in Nextcloud"
#
# 2. create contact in Roundcube - ensure contact appears in Nextcloud
#
# TODO
# clean up
mgmt_assert_delete_user "$alice"

126
tests/suites/roundcube.sh Normal file
View File

@@ -0,0 +1,126 @@
#####
##### This file is part of Mail-in-a-Box-LDAP which is released under the
##### terms of the GNU Affero General Public License as published by the
##### Free Software Foundation, either version 3 of the License, or (at
##### your option) any later version. See file LICENSE or go to
##### https://github.com/downtownallday/mailinabox-ldap for full license
##### details.
#####
test_password_change() {
# ensure user passwords can be changed from roundcube
test_start "password-change"
# create regular user alice
local alice="alice@somedomain.com"
local alice_old_pw="alice_1234"
local alice_new_pw="123_new_alice"
create_user "$alice" "$alice_old_pw"
# change the password using roundcube's ui
assert_browser_test \
roundcube/change_pw.py \
"$alice" \
"$alice_old_pw" \
"$alice_new_pw"
# test login using new password
if ! have_test_failures; then
get_attribute "$LDAP_USERS_BASE" "mail=$alice" "dn"
assert_r_access "$ATTR_DN" "$ATTR_DN" "$alice_new_pw" read mail
fi
# clean up
delete_user "$alice"
test_end
}
test_create_contact() {
#
# ensure contacts can be created in Roundcube and that those
# contacts appears in Nextcloud (support both local and remote
# Nextcloud setups)
#
# we're not going to check that a contact created in Nextcloud is
# available in Roundcube because there's already a test for that
# in the suite remote-nextcloud.sh
#
test_start "create-contact"
# create regular user alice
local alice="alice@somedomain.com"
local alice_pw="$(generate_password 16)"
create_user "$alice" "$alice_pw"
# which address book in roundcube?
# .. local nextcloud: the name is "ownCloud (Contacts)
# .. remote nextcloud: the name is the remote server name
#
# RCM_PLUGIN_DIR is defined in lib/locations.sh
record "[get address book name]"
local code address_book
address_book=$(php${PHP_VER} -r "require '$RCM_PLUGIN_DIR/carddav/config.inc.php'; isset(\$prefs['cloud']) ? print \$prefs['cloud']['name'] : print \$prefs['ownCloud']['name'];" 2>>$TEST_OF)
record "name: $address_book"
code=$?
if [ $code -ne 0 ]; then
test_failure "Could not determine the address book name to use"
else
# generate an email address - the contact's email must be
# unique or it can't be created
local contact_email="bob_bacon$(generate_uuid | awk -F- '{print $1 }')@example.com"
# create a contact using roundcube's ui
record "[create contact in Roundcube]"
if assert_browser_test \
roundcube/create_contact.py \
"$alice" \
"$alice_pw" \
"$address_book" \
"Bob" \
"Bacon" \
"$contact_email"
then
# ensure the contact exists in Nextcloud.
#
# skip explicitly checking for existance - when we delete
# the contact we're also checking that it exists (delete
# will fail otherwise)
# record "[ensure contact exists in Nextcloud]"
# assert_browser_test \
# nextcloud/contacts.py \
# "exists" \
# "$alice" \
# "$alice_pw" \
# "Bob" \
# "Bacon" \
# "$contact_email"
# delete the contact
record "[delete the contact in Nextcloud]"
assert_browser_test \
nextcloud/contacts.py \
"delete" \
"$alice" \
"$alice_pw" \
"Bob" \
"Bacon" \
"$contact_email"
fi
fi
test_end
}
suite_start "roundcube"
test_password_change
test_create_contact
suite_end

View File

@@ -0,0 +1,70 @@
#####
##### This file is part of Mail-in-a-Box-LDAP which is released under the
##### terms of the GNU Affero General Public License as published by the
##### Free Software Foundation, either version 3 of the License, or (at
##### your option) any later version. See file LICENSE or go to
##### https://github.com/downtownallday/mailinabox-ldap for full license
##### details.
#####
from browser.automation import (
TestDriver,
TimeoutException,
NoSuchElementException
)
from browser.RoundcubeAutomation import RoundcubeAutomation
import sys
login = sys.argv[1]
old_pw = sys.argv[2]
new_pw = sys.argv[3]
d = TestDriver()
rcm = RoundcubeAutomation(d)
try:
#
# open the browser to roundcube
#
d.start("Opening roundcube")
d.get("/mail/")
rcm.wait_for_login_screen(secs=10)
#
# login
#
rcm.login(login, old_pw)
rcm.wait_for_inbox()
#
# change password
#
d.start("Change password")
rcm.open_settings()
rcm.wait_for_settings()
d.say("Enter new password")
d.find_el('a.password').click() # open the change password section
d.wait_for_el('button[value=Save]') # wait for it to load
d.find_el('#curpasswd').send_text(old_pw) # fill old password
d.find_el('#newpasswd').send_text(new_pw) # fill new password
d.find_el('#confpasswd').send_text(new_pw) # fill confirm password
d.find_el('button[value=Save]').click() # save new password
d.wait_for_text("Successfully saved", secs=5, case_sensitive=False)
#
# logout
#
rcm.logout()
#
# done
#
d.say("Success!")
except Exception as e:
d.fail(e)
raise
finally:
d.quit()

View File

@@ -0,0 +1,88 @@
#####
##### This file is part of Mail-in-a-Box-LDAP which is released under the
##### terms of the GNU Affero General Public License as published by the
##### Free Software Foundation, either version 3 of the License, or (at
##### your option) any later version. See file LICENSE or go to
##### https://github.com/downtownallday/mailinabox-ldap for full license
##### details.
#####
from browser.automation import (
TestDriver,
TimeoutException,
NoSuchElementException,
ElementNotInteractableException,
)
from browser.RoundcubeAutomation import RoundcubeAutomation
import sys
login = sys.argv[1]
pw = sys.argv[2]
address_book = sys.argv[3]
contact = {
'givenname': sys.argv[4],
'surname': sys.argv[5],
'email': sys.argv[6],
}
d = TestDriver()
rcm = RoundcubeAutomation(d)
try:
#
# open the browser to roundcube
#
d.start("Opening roundcube")
d.get("/mail/")
rcm.wait_for_login_screen(secs=10)
#
# login
#
rcm.login(login, pw)
rcm.wait_for_inbox()
#
# add contact
#
d.start("Add contact")
rcm.open_contacts()
rcm.wait_for_contacts()
d.say("Select address book '%s'", address_book)
el = d.find_text(address_book, "a", exact=True, throws=False, case_sensitive=True)
if not el:
el = d.find_text(address_book + ' (Contacts)', "a", exact=True, case_sensitive=True)
if not el.is_displayed():
d.say_verbose("open sidebar to select address book")
d.find_el('a.back-sidebar-button').click()
el.click()
d.say("Create contact")
d.find_el('a.create').click()
iframe_el = d.wait_for_el('#contact-frame', secs=5)
d.switch_to_frame(iframe_el)
d.find_el('#ff_firstname').send_text(contact['givenname'])
d.find_el('#ff_surname').send_text(contact['surname'])
d.find_el('#ff_email0').send_text(contact['email'])
d.find_el('button[value=Save]').click() # save new password
d.switch_to_window(d.get_current_window_handle())
d.wait_for_text("Successfully saved", secs=5, case_sensitive=False)
#
# logout
#
rcm.logout()
#
# done
#
d.say("Success!")
except Exception as e:
d.fail(e)
raise
finally:
d.quit()

View File

@@ -0,0 +1,18 @@
#!/bin/bash
#####
##### This file is part of Mail-in-a-Box-LDAP which is released under the
##### terms of the GNU Affero General Public License as published by the
##### Free Software Foundation, either version 3 of the License, or (at
##### your option) any later version. See file LICENSE or go to
##### https://github.com/downtownallday/mailinabox-ldap for full license
##### details.
#####
# use this to run a browser test from the command line
mydir=$(dirname "$0")
export PYTHONPATH=$(realpath "$mydir/../lib/python"):$PYTHONPATH
export BROWSER_TESTS_VERBOSITY=3
python3 "$@"