Commit 2c31f584 authored by Stephane Glondu's avatar Stephane Glondu

Extend scenario 1: a voter tries to vote after election is closed

parent 1e65466e
Pipeline #63946 passed with stages
in 16 minutes and 48 seconds
......@@ -113,6 +113,4 @@ Verifications all along the process is done using command line tools `belenios-t
- For each available answer in the question, she checks that the total number of votes in favor of Answer X displayed in result page is the same as the sum of votes for Answer X in all votes of voters who voted that have been randomly generated in advance
- She checks that each ballot content corresponds to content that of this vote that has been randomly generated in advance
- Verify election consistency (using command line tool `belenios_tool verify`)
- One voter tries to revote and faces an error message "Your ballot for Test vote after close is rejected, because the election is closed." after authentication
......@@ -122,6 +122,11 @@ class BeleniosTestElectionScenario1(BeleniosElectionTestBase):
verify_election_consistency(self.election_id)
console_log("### Step complete: verify_election_consistency using `belenios_tool verify` (3)")
console_log("### Starting step: voter votes after the election is closed")
self.one_voter_revotes_after_the_election_is_closed()
console_log("### Step complete: voter votes after the election is closed")
if __name__ == "__main__":
random_seed = os.getenv('RANDOM_SEED', None)
......
......@@ -3,6 +3,7 @@
import unittest
import random
import re
from urllib.parse import urlencode
from selenium.webdriver.common.alert import Alert
from util.selenium_tools import wait_for_element_exists, wait_for_elements_exist, wait_for_element_exists_and_contains_expected_text, wait_for_element_exists_and_has_non_empty_content, wait_for_an_element_with_partial_link_text_exists, verify_element_label
from util.election_testing import console_log, random_email_addresses_generator, populate_credential_and_password_for_voters_from_sent_emails, populate_random_votes_for_voters, repopulate_vote_confirmations_for_voters_from_sent_emails, wait_a_bit, build_css_selector_to_find_buttons_in_page_content_by_value, find_button_in_page_content_by_value, initialize_browser, election_page_url_to_election_id, verify_election_consistency, create_election_data_snapshot, delete_election_data_snapshot, log_in_as_administrator, log_out, administrator_starts_creation_of_election, administrator_edits_election_questions, administrator_sets_election_voters, administrator_validates_creation_of_election
......@@ -287,15 +288,14 @@ pris en compte.
log_out(browser)
def some_voters_cast_their_vote(self, voters):
"""
:param voters: list of dict. Each element contains information about a voter (their e-mail address, the planned answers to each question they will cast)
"""
def one_voter_votes(self, voter, direct=False):
browser = self.browser
voters_count = len(voters)
for index, voter in enumerate(voters):
console_log("#### Current voter casting their vote in current batch: " + str(index + 1) + "/" + str(voters_count))
if direct:
url = voter["election_page_url"]
browser.get(settings.SERVER_URL + "/vote.html#" + urlencode({"url": url}))
else:
# Bob has received 2 emails containing an invitation to vote and all necessary credentials (election page URL, username, password). He goes to the election page URL.
browser.get(voter["election_page_url"])
......@@ -307,120 +307,132 @@ pris en compte.
start_button_element = wait_for_element_exists_and_contains_expected_text(browser, start_button_css_selector, start_button_expected_label, settings.EXPLICIT_WAIT_TIMEOUT)
start_button_element.click()
wait_a_bit()
wait_a_bit()
# A loading screen appears, then another screen appears. He clicks on the "Here" button
here_button_expected_label = "here"
here_button_css_selector = "#input_code button"
here_button_element = wait_for_element_exists_and_contains_expected_text(browser, here_button_css_selector, here_button_expected_label, settings.EXPLICIT_WAIT_TIMEOUT)
here_button_element.click()
# A loading screen appears, then another screen appears. He clicks on the "Here" button
here_button_expected_label = "here"
here_button_css_selector = "#input_code button"
here_button_element = wait_for_element_exists_and_contains_expected_text(browser, here_button_css_selector, here_button_expected_label, settings.EXPLICIT_WAIT_TIMEOUT)
here_button_element.click()
wait_a_bit()
wait_a_bit()
# A modal opens (it is an HTML modal created using Window.prompt()), with an input field. He types his credential.
credential_prompt = Alert(browser)
credential_prompt.send_keys(voter["credential"])
credential_prompt.accept()
# A modal opens (it is an HTML modal created using Window.prompt()), with an input field. He types his credential.
credential_prompt = Alert(browser)
credential_prompt.send_keys(voter["credential"])
credential_prompt.accept()
wait_a_bit()
wait_a_bit()
# A new screen appears, which has a title "Step 2/6: Answer to questions", and a content:
# "Question 1?"
# "Question #1 of 1 — select between 1 and 2 answer(s)"
# [ ] "Answer 1"
# [ ] "Answer 2"
# [Next]
# (where "[ ]" is a checkbox, and [Next] is a button)
# He fills his votes to each answer of the question
answers_css_selector = "#question_div input[type=checkbox]"
answers_elements = wait_for_elements_exist(browser, answers_css_selector, settings.EXPLICIT_WAIT_TIMEOUT) # or we could use find_element_by_xpath("//div[@id='question_div']/input[@type='checkbox'][2]")
assert len(answers_elements) is 2
question1_answer1_element = answers_elements[0]
question1_answer2_element = answers_elements[1]
voter_vote_to_question_1_answer_1 = voter["votes"]["question1"]["answer1"]
voter_vote_to_question_1_answer_2 = voter["votes"]["question1"]["answer2"]
voter_vote_to_question_1_answer_1_is_checked = question1_answer1_element.get_attribute('checked')
voter_vote_to_question_1_answer_2_is_checked = question1_answer2_element.get_attribute('checked')
assert voter_vote_to_question_1_answer_1_is_checked is None
assert voter_vote_to_question_1_answer_2_is_checked is None
if voter_vote_to_question_1_answer_1:
question1_answer1_element.click()
if voter_vote_to_question_1_answer_2:
question1_answer2_element.click()
# A new screen appears, which has a title "Step 2/6: Answer to questions", and a content:
# "Question 1?"
# "Question #1 of 1 — select between 1 and 2 answer(s)"
# [ ] "Answer 1"
# [ ] "Answer 2"
# [Next]
# (where "[ ]" is a checkbox, and [Next] is a button)
# He fills his votes to each answer of the question
answers_css_selector = "#question_div input[type=checkbox]"
answers_elements = wait_for_elements_exist(browser, answers_css_selector, settings.EXPLICIT_WAIT_TIMEOUT) # or we could use find_element_by_xpath("//div[@id='question_div']/input[@type='checkbox'][2]")
assert len(answers_elements) is 2
question1_answer1_element = answers_elements[0]
question1_answer2_element = answers_elements[1]
voter_vote_to_question_1_answer_1 = voter["votes"]["question1"]["answer1"]
voter_vote_to_question_1_answer_2 = voter["votes"]["question1"]["answer2"]
voter_vote_to_question_1_answer_1_is_checked = question1_answer1_element.get_attribute('checked')
voter_vote_to_question_1_answer_2_is_checked = question1_answer2_element.get_attribute('checked')
assert voter_vote_to_question_1_answer_1_is_checked is None
assert voter_vote_to_question_1_answer_2_is_checked is None
if voter_vote_to_question_1_answer_1:
question1_answer1_element.click()
if voter_vote_to_question_1_answer_2:
question1_answer2_element.click()
wait_a_bit()
wait_a_bit()
# He clicks on the "Next" button
next_button_expected_label = "Next"
next_button_css_selector = "#question_div button"
next_button_element = wait_for_element_exists_and_contains_expected_text(browser, next_button_css_selector, next_button_expected_label, settings.EXPLICIT_WAIT_TIMEOUT)
next_button_element.click()
# He clicks on the "Next" button
next_button_expected_label = "Next"
next_button_css_selector = "#question_div button"
next_button_element = wait_for_element_exists_and_contains_expected_text(browser, next_button_css_selector, next_button_expected_label, settings.EXPLICIT_WAIT_TIMEOUT)
next_button_element.click()
wait_a_bit()
wait_a_bit()
"""
A new screen appears, showing:
"""
A new screen appears, showing:
Step 3/6: Review and encrypt
Question 1?
- Answer 1
Step 3/6: Review and encrypt
Question 1?
- Answer 1
Your ballot has been successfully encrypted, but has not been cast yet!
Your ballot has been successfully encrypted, but has not been cast yet!
Your smart ballot tracker is sLRilXoAYcodIrjWrOqPrVXLNlRyCJAqFeeHZ4WCajU
Your smart ballot tracker is sLRilXoAYcodIrjWrOqPrVXLNlRyCJAqFeeHZ4WCajU
We invite you to save it in order to check later that it is taken into account.
We invite you to save it in order to check later that it is taken into account.
[Continue]
[Restart]
"""
[Continue]
[Restart]
"""
# He remembers the smart ballot tracker that is displayed.
smart_ballot_tracker_css_selector = "#ballot_tracker"
smart_ballot_tracker_element = wait_for_element_exists_and_has_non_empty_content(browser, smart_ballot_tracker_css_selector, settings.EXPLICIT_WAIT_TIMEOUT)
smart_ballot_tracker_value = smart_ballot_tracker_element.get_attribute('innerText')
assert len(smart_ballot_tracker_value) > 5
# He remembers the smart ballot tracker that is displayed.
smart_ballot_tracker_css_selector = "#ballot_tracker"
smart_ballot_tracker_element = wait_for_element_exists_and_has_non_empty_content(browser, smart_ballot_tracker_css_selector, settings.EXPLICIT_WAIT_TIMEOUT)
smart_ballot_tracker_value = smart_ballot_tracker_element.get_attribute('innerText')
assert len(smart_ballot_tracker_value) > 5
voter["smart_ballot_tracker"] = smart_ballot_tracker_value
voter["smart_ballot_tracker"] = smart_ballot_tracker_value
# He clicks on the "Continue" button
next_button_expected_label = "Continue"
next_button_css_selector = "#div_submit input[type=submit][value='" + next_button_expected_label + "']"
next_button_element = browser.find_element_by_css_selector(next_button_css_selector)
next_button_element.click()
# He clicks on the "Continue" button
next_button_expected_label = "Continue"
next_button_css_selector = "#div_submit input[type=submit][value='" + next_button_expected_label + "']"
next_button_element = browser.find_element_by_css_selector(next_button_css_selector)
next_button_element.click()
wait_a_bit()
wait_a_bit()
# He types his voter username and password, and submits the form
username_field_css_selector = "#main input[name=username]"
username_field_element = wait_for_element_exists(browser, username_field_css_selector, settings.EXPLICIT_WAIT_TIMEOUT)
username_field_element.send_keys(voter["username"])
# He types his voter username and password, and submits the form
username_field_css_selector = "#main input[name=username]"
username_field_element = wait_for_element_exists(browser, username_field_css_selector, settings.EXPLICIT_WAIT_TIMEOUT)
username_field_element.send_keys(voter["username"])
password_field_css_selector = "#main input[name=password]"
password_field_element = browser.find_element_by_css_selector(password_field_css_selector)
password_field_element.send_keys(voter["password"])
password_field_css_selector = "#main input[name=password]"
password_field_element = browser.find_element_by_css_selector(password_field_css_selector)
password_field_element.send_keys(voter["password"])
wait_a_bit()
wait_a_bit()
password_field_element.submit()
password_field_element.submit()
wait_a_bit()
wait_a_bit()
# He checks that the smart ballot tracker value that appears on screen is the same as the one he noted
smart_ballot_tracker_verification_css_selector = "#ballot_tracker"
smart_ballot_tracker_verification_element = wait_for_element_exists_and_has_non_empty_content(browser, smart_ballot_tracker_verification_css_selector, settings.EXPLICIT_WAIT_TIMEOUT)
smart_ballot_tracker_verification_value = smart_ballot_tracker_verification_element.get_attribute('innerText')
assert len(smart_ballot_tracker_verification_value) > 5
# He checks that the smart ballot tracker value that appears on screen is the same as the one he noted
smart_ballot_tracker_verification_css_selector = "#ballot_tracker"
smart_ballot_tracker_verification_element = wait_for_element_exists_and_has_non_empty_content(browser, smart_ballot_tracker_verification_css_selector, settings.EXPLICIT_WAIT_TIMEOUT)
smart_ballot_tracker_verification_value = smart_ballot_tracker_verification_element.get_attribute('innerText')
assert len(smart_ballot_tracker_verification_value) > 5
assert smart_ballot_tracker_verification_value == voter["smart_ballot_tracker"]
assert smart_ballot_tracker_verification_value == voter["smart_ballot_tracker"]
# He clicks on the "I cast my vote" button
submit_button_css_selector = "#main input[type=submit]"
submit_button_element = browser.find_element_by_css_selector(submit_button_css_selector)
submit_button_element.click()
# He clicks on the "I cast my vote" button
submit_button_css_selector = "#main input[type=submit]"
submit_button_element = browser.find_element_by_css_selector(submit_button_css_selector)
submit_button_element.click()
def some_voters_cast_their_vote(self, voters):
"""
:param voters: list of dict. Each element contains information about a voter (their e-mail address, the planned answers to each question they will cast)
"""
browser = self.browser
voters_count = len(voters)
for index, voter in enumerate(voters):
console_log("#### Current voter casting their vote in current batch: " + str(index + 1) + "/" + str(voters_count))
self.one_voter_votes(voter)
wait_a_bit()
"""
......@@ -465,6 +477,25 @@ pris en compte.
assert voter["smart_ballot_tracker"] == voter["smart_ballot_tracker_in_vote_confirmation_email"], "Ballot tracker read in vote confirmation email (" + voter["smart_ballot_tracker"] + ") is not the same as the one read on the vote confirmation page (" + voter["smart_ballot_tracker_in_vote_confirmation_email"] + ")"
def one_voter_casts_after_the_election_is_closed(self, voter):
browser = self.browser
console_log("#### Current voter casting their vote after the election is closed")
self.one_voter_votes(voter, direct=True)
wait_a_bit()
"""
Next screen looks like this:
Your ballot for Test vote after close is rejected, because the election is closed.
{Go back to election}
Where {xxx} is a link
"""
# He checks that "the election is closed" is present
wait_for_element_exists_and_contains_expected_text(browser, "#main p", "the election is closed", settings.EXPLICIT_WAIT_TIMEOUT)
def all_voters_vote(self):
"""
This function selects a random set of `NUMBER_OF_VOTING_VOTERS` voters, and casts their vote.
......@@ -544,6 +575,15 @@ pris en compte.
self.some_voters_cast_their_vote(voters_who_will_vote_now_data)
def one_voter_revotes_after_the_election_is_closed(self):
voters_list_we_pick_from = self.voters_email_addresses_who_have_voted.keys()
voters_who_will_vote_now = random.sample(voters_list_we_pick_from, 1)
voters_who_will_vote_now_data = populate_credential_and_password_for_voters_from_sent_emails(self.fake_sent_emails_manager, voters_who_will_vote_now, settings.ELECTION_TITLE)
voters_who_will_vote_now_data = populate_random_votes_for_voters(voters_who_will_vote_now_data)
self.update_voters_data(voters_who_will_vote_now_data)
self.one_voter_casts_after_the_election_is_closed(voters_who_will_vote_now_data[0])
def administrator_verifies_vote_results(self):
"""
Initial browser (required) state: on the vote results page
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment