diff --git a/.travis.yml b/.travis.yml index 01d28440..2dd25a06 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,17 +5,23 @@ sudo: false python: - "2.7" +addons: + apt: + packages: + - xvfb + - firefox + env: global: - COLAB_SETTINGS=tests/colab_settings.py install: - - pip install coveralls flake8 behave behave_django + - pip install coveralls flake8 behave behave_django selenium - pip install . script: - python setup.py test - - colab-admin behave + - xvfb-run -a colab-admin behave --format=progress - flake8 colab after_success: diff --git a/README.rst b/README.rst index 14682e69..6e8ba39e 100644 --- a/README.rst +++ b/README.rst @@ -129,3 +129,52 @@ Follow the steps below: .. code-block:: python setup.py test + +How to run Acceptance Tests +--------------------------- + +Follow the steps below to run the acceptance tests. + +1- Log in virtual machine: + +1.1 - To run without opening a graphic interface + +.. code-block:: + + vagrant ssh + +1.2 - To run opening a graphic interface + +.. code-block:: + + vagrant ssh -- -X + +2- Use colab virtualenv: + +.. code-block:: + + workon colab + +3- Enter into colab source code directory: + +.. code-block:: + + cd /vagrant + +4- Run all the acceptance tests with: + +.. code-block:: + + COLAB_SETTINGS=tests/colab_settings.py colab-admin behave + +4.1 To run without opening a browser: +.. code-block:: + + COLAB_SETTINGS=tests/colab_settings.py xvfb-run -a colab-admin behave + +4.2 To run a specific feature: + +.. code-block:: + + COLAB_SETTINGS=tests/colab_settings.py colab-admin behave /path/to/features/file.feature + diff --git a/features/environment.py b/features/environment.py new file mode 100644 index 00000000..ce081d4f --- /dev/null +++ b/features/environment.py @@ -0,0 +1,11 @@ +from selenium import webdriver + + +def before_feature(context, feature): + context.driver = webdriver.Firefox() + context.driver.set_window_size(1000, 600) + context.driver.implicitly_wait(5) + + +def after_feature(context, feature): + context.driver.quit() diff --git a/features/profile_edition.feature b/features/profile_edition.feature new file mode 100644 index 00000000..41c1d827 --- /dev/null +++ b/features/profile_edition.feature @@ -0,0 +1,79 @@ + +Feature: User Profile Edition + In order to update my personal information + As an User + I want to be able to edit my profile + + Background: + Given I am logged in as "john" + + Scenario: Edit profile without required information + When I open the user menu + When I click in "My Profile" + When I click in "Edit Profile" + When I fill " " in "id_first_name" field + When I fill " " in "id_last_name" field + When I click in "Update" button + Then The field "id_first_name" should have an error + Then The field "id_last_name" should have an error + + Scenario: Edit profile with valid information + When I open the user menu + When I click in "My Profile" + When I click in "Edit Profile" + When I fill "John" in "id_first_name" field + When I fill "McClaine" in "id_last_name" field + When I fill "Die Hard" in "id_institution" field + When I fill "police officer" in "id_role" field + When I fill "diehard.com" in "id_webpage" field + When I fill "I am tough." in "id_bio" field + When I click in "Update" button + Then I should see "John McClaine" in "user-profile" + Then I should see "Die Hard" in "user-profile" + Then I should see "police officer" in "user-profile" + Then I should see "I am tough." in "user-profile" + When I click in "Edit Profile" + Then I should see "diehard.com" in "id_webpage" + + Scenario: Change password with wrong current password + When I open the user menu + When I click in "My Profile" + When I click in "Edit Profile" + When I click in "Change Password" + When I fill "wrong" in "id_old_password" field + When I fill "newpassword" in "id_new_password1" field + When I fill "newpassword" in "id_new_password2" field + When I click in "Change my password" button + Then The field "id_old_password" should have an error + + Scenario: Change password with wrong password confirmation + When I open the user menu + When I click in "My Profile" + When I click in "Edit Profile" + When I click in "Change Password" + When I fill "john" in "id_old_password" field + When I fill "newpassword" in "id_new_password1" field + When I fill "differentpassword" in "id_new_password2" field + When I click in "Change my password" button + Then The field "id_new_password2" should have an error + + Scenario: Change password with success + When I open the user menu + When I click in "My Profile" + When I click in "Edit Profile" + When I click in "Change Password" + When I fill "john" in "id_old_password" field + When I fill "newpassword" in "id_new_password1" field + When I fill "newpassword" in "id_new_password2" field + When I click in "Change my password" button + When I open the user menu + When I click in "My Profile" + When I open the user menu + When I click in "Logout" + When I click in "Acesso " + When I click in "Login" + When I fill "john" in "id_username" field + When I fill "newpassword" in "id_password" field + When I click in "Acesso " + When I click in "Login" button + Then The browser URL should be "/dashboard" diff --git a/features/steps/home.py b/features/steps/home.py deleted file mode 100644 index 5896f0fc..00000000 --- a/features/steps/home.py +++ /dev/null @@ -1,9 +0,0 @@ - - -@when(u'I access the URL "{url}"') -def step_impl(context, url): - context.response = context.test.client.get(url) - -@then(u'The browser URL should be "{url}"') -def step_impl(context, url): - context.test.assertRedirects(context.response, url, status_code=301) diff --git a/features/steps/user_steps.py b/features/steps/user_steps.py new file mode 100644 index 00000000..961fe065 --- /dev/null +++ b/features/steps/user_steps.py @@ -0,0 +1,38 @@ +from colab.accounts.models import User +from behave import given, when + + +@given(u'The user "{username}" with the password "{password}" is "{status}"') +def create_user(context, username, password, status): + user = User() + user.username = username + user.set_password(password) + user.email = "usertest@colab.com.br" + user.id = 1 + user.first_name = "USERtestCoLaB" + user.last_name = "COLAB" + user.needs_update = False + if status == "active": + user.is_active = True + else: + user.is_active = False + user.save() + + +@given(u'I am logged in as "{username}"') +def step_impl(context, username): + context.execute_steps(''' + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + Given The user "%s" with the password "%s" is "%s" + When I fill "%s" in "id_username" field + When I fill "%s" in "id_password" field + When I click in "Login" button + ''' % (username, username, 'active', username, username)) + + +@when(u'I open the user menu') +def step_impl(context): + dropdown = context.driver.find_element_by_id('user-menu') + dropdown.find_element_by_xpath('.//a').click() diff --git a/features/steps/web_steps.py b/features/steps/web_steps.py new file mode 100644 index 00000000..ea92a9cf --- /dev/null +++ b/features/steps/web_steps.py @@ -0,0 +1,55 @@ +from selenium.webdriver.common.keys import Keys +from behave import when, then + + +@when(u'I access the URL "{url}"') +def step_impl(context, url): + context.driver.get(context.base_url + "/") + + +@when(u'I click in "{link}"') +def step_impl(context, link): + context.driver.find_element_by_xpath("//a[contains(., '%s')]" % + link).click() + + +@when(u'I click in "{button_value}" button') +def step_impl(context, button_value): + context.driver.find_element_by_xpath( + "//input[@value='%s']|//button[.='%s']" % + (button_value, button_value)).click() + + +@when(u'I fill "{text}" in "{field_id}" field') +def step_impl(context, text, field_id): + field = context.driver.find_element_by_id(field_id) + field.clear() + field.send_keys(text) + + +@when(u'I fill "{text}" in "{field_id}" field and hit enter') +def step_impl(context, text, field_id): + field = context.driver.find_element_by_id(field_id) + field.clear() + field.send_keys(text) + field.send_keys(Keys.RETURN) + + +@then(u'The field "{field_id}" should have an error') +def step_impl(context, field_id): + field = context.driver.find_element_by_id(field_id) + container = field.find_element_by_xpath('..') + classes = container.get_attribute('class') + assert 'has-error' in classes + + +@then(u'I should see "{content}" in "{element_id}"') +def step_impl(context, content, element_id): + element = context.driver.find_element_by_id(element_id) + assert (content in element.text) or \ + (content in element.get_attribute("value")) + + +@then(u'The browser URL should be "{url}"') +def step_impl(context, url): + assert context.driver.current_url.endswith(url) diff --git a/features/user_sign_in.feature b/features/user_sign_in.feature new file mode 100644 index 00000000..cb082761 --- /dev/null +++ b/features/user_sign_in.feature @@ -0,0 +1,97 @@ + +Feature: User sign in + In order to be able to access the system funcionalities + As an User + I want to be able to sign in + + # Valid scenarios + + Scenario: Clicking the login button and displaying login page + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + Then The browser URL should be "/account/login" + + Scenario: Sign in with a valid user + Given The user "colabtest" with the password "colabtest" is "active" + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + When I fill "colabtest" in "id_username" field + When I fill "colabtest" in "id_password" field + When I click in "Login" button + Then The browser URL should be "/dashboard" + + Scenario: Sign in with a valid user by hitting ENTER + Given The user "colabtest" with the password "colabtest" is "active" + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + When I fill "colabtest" in "id_username" field + When I fill "colabtest" in "id_password" field and hit enter + Then The browser URL should be "/dashboard" + + Scenario: Sign in with a valid user and displaying user profile + Given The user "colabtest" with the password "colabtest" is "active" + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + When I fill "colabtest" in "id_username" field + When I fill "colabtest" in "id_password" field + When I click in "Login" button + Then The browser URL should be "/dashboard" + When I open the user menu + Then I should see "USERtestCoLaB COLAB" in "user-menu" + Then I should see "usertest@colab.com.br" in "user-menu" + + + # Invalid scenarios + + Scenario: Sign in with an unregistered user + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + When I fill "unregistered" in "id_username" field + When I fill "any" in "id_password" field + When I click in "Login" button + Then The browser URL should be "/account/login" + Then I should see "Please correct the error below and try again" in "main-content" + + Scenario: Sign in with a inactive user + Given The user "colabtest" with the password "colabtest" is "inactive" + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + When I fill "colabtest" in "id_username" field + When I fill "colabtest" in "id_password" field + When I click in "Login" button + Then The browser URL should be "/account/login" + Then I should see "This account is inactive" in "main-content" + + Scenario: Sign in with no user information given + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + When I click in "Login" button + Then The browser URL should be "/account/login" + Then The field "id_username" should have an error + Then The field "id_password" should have an error + + Scenario: Sign in with no password given + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + When I fill "colabtest" in "id_username" field + When I click in "Login" button + Then The browser URL should be "/account/login" + Then The field "id_password" should have an error + + Scenario: Sign in with no username given + When I access the URL "/" + When I click in "Acesso " + When I click in "Login" + When I fill "colabtest" in "id_password" field + When I click in "Login" button + Then The browser URL should be "/account/login" + Then The field "id_username" should have an error + diff --git a/features/user_sign_up.feature b/features/user_sign_up.feature new file mode 100644 index 00000000..ee59afa4 --- /dev/null +++ b/features/user_sign_up.feature @@ -0,0 +1,57 @@ + +Feature: User Sign Up + In order to use the system + As an User + I want to be able to sign up + + Scenario: Sign up with no information + When I access the URL "/" + When I click in "Acesso " + When I click in "Register" + When I click in "Register" button + Then The field "id_username" should have an error + Then The field "id_first_name" should have an error + Then The field "id_last_name" should have an error + Then The field "id_email" should have an error + Then The field "id_password1" should have an error + Then The field "id_password2" should have an error + + Scenario: Sign up with all required information + When I access the URL "/" + When I click in "Acesso " + When I click in "Register" + When I fill "johndiehard" in "id_username" field + When I fill "John" in "id_first_name" field + When I fill "McClane" in "id_last_name" field + When I fill "john@email.com" in "id_email" field + When I fill "100guns100" in "id_password1" field + When I fill "100guns100" in "id_password2" field + When I click in "Register" button + Then The browser URL should be "/account/johndiehard" + Then I should see "John McClane" in "user-profile" + + Scenario: Sign up with invalid email + When I access the URL "/" + When I click in "Acesso " + When I click in "Register" + When I fill "johndiehard" in "id_username" field + When I fill "John" in "id_first_name" field + When I fill "McClane" in "id_last_name" field + When I fill "john@email" in "id_email" field + When I fill "100guns100" in "id_password1" field + When I fill "100guns100" in "id_password2" field + When I click in "Register" button + Then The field "id_email" should have an error + + Scenario: Sign up with different passwords + When I access the URL "/" + When I click in "Acesso " + When I click in "Register" + When I fill "johndiehard" in "id_username" field + When I fill "John" in "id_first_name" field + When I fill "McClane" in "id_last_name" field + When I fill "john@email.com" in "id_email" field + When I fill "100guns100" in "id_password1" field + When I fill "100guns999" in "id_password2" field + When I click in "Register" button + Then The field "id_password2" should have an error diff --git a/setup.py b/setup.py index 8cb9f428..afc212bd 100644 --- a/setup.py +++ b/setup.py @@ -17,6 +17,10 @@ # Async Signals 'celery[redis]>=3.1.2', + # Acceptance tests + 'selenium>=2.53.1', + 'behave_django>=0.3.0', + ### Move out of colab (as plugins): # Deps for super_archives @@ -32,8 +36,6 @@ 'coveralls>=0.5', 'flake8>=2.3.0', 'mock==1.0.1', - 'behave>= 1.2.0', - 'behave_django>=0.2.2', ] diff --git a/vagrant/centos.sh b/vagrant/centos.sh index e477896d..973ff73e 100755 --- a/vagrant/centos.sh +++ b/vagrant/centos.sh @@ -24,6 +24,9 @@ yum -y groupinstall "Development tools" yum install -y git unzip gettext libxml2-devel libxslt-devel openssl-devel libffi-devel python-devel python-pip python-virtualenvwrapper redis +### Acceptance Tests dependencies + +yum install -y Xvfb firefox ### Init Redis systemctl enable redis diff --git a/vagrant/ubuntu.sh b/vagrant/ubuntu.sh index f145a588..8c451697 100755 --- a/vagrant/ubuntu.sh +++ b/vagrant/ubuntu.sh @@ -6,3 +6,7 @@ set -ex apt-get update apt-get install curl git unzip build-essential gettext libxml2-dev libxslt1-dev libssl-dev libffi-dev python-dev virtualenvwrapper python-pip redis-server -y + +### Acceptance Tests dependencies + +apt-get install xvfb firefox -y \ No newline at end of file