Skip to content

Commit 9d9e569

Browse files
committed
test: add testing for voting
1 parent 9fa57e1 commit 9d9e569

File tree

2 files changed

+154
-117
lines changed

2 files changed

+154
-117
lines changed

ballot/election/doctype/candidate_vote/test_candidate_vote.py

Lines changed: 91 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -5,152 +5,132 @@
55
from faker import Faker
66
from frappe.tests import IntegrationTestCase
77

8+
from ballot.id.doctypes import (
9+
CANDIDATE,
10+
CANDIDATE_APPLICATION,
11+
ELECTION,
12+
NOMINATION_FORM,
13+
TEAM,
14+
VOTE,
15+
)
16+
from ballot.tests.utils import (
17+
create_candidate_application,
18+
create_election,
19+
create_election_team,
20+
create_nomination_form,
21+
)
22+
823
fake = Faker()
924

10-
ELECTION = "Election"
11-
TEAM = "Election Team"
12-
CANDIDATE_DOC = "Election Candidate"
13-
FORM = "Election Nomination Form"
14-
APPLICATION_DOC = "Election Candidate Application"
15-
VOTE_DOC = "Candidate Vote"
25+
1626
TEAM_OWNER = "test1@example.com"
17-
CANDIDATE_1 = "test2@example.com"
18-
CANDIDATE_2 = "test3@example.com"
27+
CANDIDATE_USER = "test2@example.com"
28+
VOTER = "test3@example.com"
1929

2030

2131
class TestCandidateVote(IntegrationTestCase):
2232
def setUp(self):
2333
frappe.set_user(TEAM_OWNER)
24-
25-
# Create a Team
26-
team = frappe.get_doc(
27-
{
28-
"doctype": TEAM,
29-
"team_name": fake.name(),
30-
}
34+
self.election_team = create_election_team()
35+
self.election = create_election(
36+
"Test Election", self.election_team.name, voting_status="Live"
3137
)
32-
team.insert()
33-
self.team = team
34-
35-
# Create an Election, linked to the above team
36-
election = frappe.get_doc(
37-
{
38-
"doctype": ELECTION,
39-
"title": fake.name(),
40-
"organizing_team": self.team.name,
41-
}
38+
self.nomination_form = create_nomination_form(self.election, status="Live")
39+
frappe.set_user(CANDIDATE_USER)
40+
self.candidate_application = create_candidate_application(
41+
self.election.name, self.nomination_form.name
4242
)
43-
election.insert()
44-
self.election = election
45-
46-
# Create a Nomination Form for the election
47-
form = frappe.get_doc(
43+
self.candidate = frappe.get_doc(
44+
CANDIDATE,
4845
{
49-
"doctype": FORM,
50-
"status": "Live",
46+
"linked_application": self.candidate_application.name,
5147
"election": self.election.name,
52-
}
48+
},
5349
)
54-
form.insert()
55-
self.form = form
5650

57-
# Create a 1st Candidate Application for the election
58-
frappe.set_user(CANDIDATE_1)
59-
application_1 = frappe.get_doc(
51+
def tearDown(self):
52+
frappe.set_user("Administrator")
53+
frappe.delete_doc(TEAM, self.election_team.name, force=True)
54+
frappe.delete_doc(ELECTION, self.election.name, force=1)
55+
frappe.delete_doc(NOMINATION_FORM, self.nomination_form.name, force=1)
56+
frappe.delete_doc(CANDIDATE_APPLICATION, self.candidate_application.name, force=1)
57+
frappe.delete_doc(CANDIDATE, self.candidate.name, force=1)
58+
59+
def test_single_candidate_vote(self):
60+
frappe.set_user(VOTER)
61+
62+
candidate_vote = frappe.get_doc(
6063
{
61-
"doctype": APPLICATION_DOC,
62-
"user": CANDIDATE_1,
64+
"doctype": VOTE,
65+
"vote_by": frappe.session.user,
6366
"election": self.election.name,
64-
"nomination_form": form.name,
65-
"full_name": fake.name(),
66-
"email": fake.email(),
67+
"candidate_tiers": [
68+
{
69+
"rank": 1,
70+
"candidate": self.candidate.name,
71+
}
72+
],
6773
}
6874
)
69-
application_1.insert()
75+
candidate_vote.submit()
7076

71-
# Create a 2nd Candidate Application for the election
72-
frappe.set_user(CANDIDATE_2)
73-
application_2 = frappe.get_doc(
77+
# Given a Voter has already voted for a Candidate, they should not be able to vote again
78+
second_vote = frappe.get_doc(
7479
{
75-
"doctype": APPLICATION_DOC,
76-
"user": CANDIDATE_2,
80+
"doctype": VOTE,
81+
"vote_by": frappe.session.user,
7782
"election": self.election.name,
78-
"nomination_form": form.name,
79-
"full_name": fake.name(),
80-
"email": fake.email(),
83+
"candidate_tiers": [
84+
{
85+
"rank": 1,
86+
"candidate": self.candidate.name,
87+
}
88+
],
8189
}
8290
)
83-
application_2.insert()
84-
85-
# Accept the applications
86-
frappe.set_user(TEAM_OWNER)
87-
application_1.status = "Accepted"
88-
application_1.save()
89-
90-
application_2.status = "Accepted"
91-
application_2.save()
92-
93-
self.application_1 = application_1
94-
self.application_2 = application_2
91+
with self.assertRaises(frappe.ValidationError):
92+
second_vote.submit()
9593

96-
frappe.set_user("Administarator")
94+
def test_valid_user_vote(self):
95+
frappe.set_user(VOTER)
9796

98-
# Get Candidate Docs
99-
candidate_1 = frappe.get_doc(
100-
CANDIDATE_DOC,
101-
{
102-
"election": self.election.name,
103-
"linked_application": self.application_1.name,
104-
},
105-
)
106-
candidate_2 = frappe.get_doc(
107-
CANDIDATE_DOC,
97+
candidate_vote = frappe.get_doc(
10898
{
99+
"doctype": VOTE,
100+
"vote_by": "not_a_valid_user@example.com",
109101
"election": self.election.name,
110-
"linked_application": self.application_2.name,
111-
},
102+
"candidate_tiers": [
103+
{
104+
"rank": 1,
105+
"candidate": self.candidate.name,
106+
}
107+
],
108+
}
112109
)
113110

114-
self.candidate_1 = candidate_1
115-
self.candidate_2 = candidate_2
111+
with self.assertRaises(frappe.ValidationError):
112+
candidate_vote.submit()
116113

117-
def tearDown(self):
118-
frappe.set_user("Administrator")
119-
frappe.delete_doc(TEAM, self.team.name, force=1)
120-
frappe.delete_doc(ELECTION, self.election.name, force=1)
121-
frappe.delete_doc(FORM, self.form.name, force=1)
122-
frappe.delete_doc(APPLICATION_DOC, self.application_1.name, force=1)
123-
frappe.delete_doc(APPLICATION_DOC, self.application_2.name, force=1)
124-
frappe.delete_doc(CANDIDATE_DOC, self.candidate_1.name, force=1)
125-
frappe.delete_doc(CANDIDATE_DOC, self.candidate_2.name, force=1)
126-
127-
def test_single_vote(self):
128-
# Given a candidate vote is created for an election
129-
# When the user tries to vote for another candidate in the same election
130-
# Then the user should not be able to vote for another candidate
131-
132-
frappe.set_user("test4@example.com")
133-
vote1 = frappe.get_doc(
134-
{
135-
"doctype": VOTE_DOC,
136-
"vote_by": frappe.session.user,
137-
"election": self.election.name,
138-
"candidate": self.candidate_1.name,
139-
}
140-
)
141-
vote1.insert()
114+
def test_voting_when_voting_is_closed(self):
115+
frappe.set_user(TEAM_OWNER)
116+
self.election.voting_status = "Closed"
117+
self.election.save()
142118

143-
vote2 = frappe.get_doc(
119+
frappe.set_user(VOTER)
120+
121+
candidate_vote = frappe.get_doc(
144122
{
145-
"doctype": VOTE_DOC,
123+
"doctype": VOTE,
146124
"vote_by": frappe.session.user,
147125
"election": self.election.name,
148-
"candidate": self.candidate_2.name,
126+
"candidate_tiers": [
127+
{
128+
"rank": 1,
129+
"candidate": self.candidate.name,
130+
}
131+
],
149132
}
150133
)
151134

152135
with self.assertRaises(frappe.ValidationError):
153-
vote2.insert()
154-
155-
frappe.set_user('Administrator')
156-
vote1.delete(force=1)
136+
candidate_vote.submit()

ballot/tests/utils.py

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import frappe
22
from faker import Faker
33

4+
from ballot.id.doctypes import CANDIDATE, CANDIDATE_APPLICATION, ELECTION, NOMINATION_FORM, TEAM
5+
46
fake = Faker()
57

68

7-
def create_election_team():
9+
def create_election_team() -> dict:
810
"""
911
Creates and returns an Election Team.
1012
1113
Note: session user is auto added as a team member
1214
"""
1315
election_team = frappe.get_doc(
1416
{
15-
"doctype": "Election Team",
17+
"doctype": TEAM,
1618
"team_name": fake.name(),
1719
}
1820
)
@@ -21,16 +23,71 @@ def create_election_team():
2123
return election_team
2224

2325

24-
def create_election(title, team_name):
26+
def create_election(title: str, team_id: str, **kwargs) -> dict:
2527
"""Creates and returns an Election linked to an Election Team."""
2628
election = frappe.get_doc(
2729
{
28-
"doctype": "Election",
30+
"doctype": ELECTION,
2931
"title": title,
30-
"organizing_team": team_name,
31-
"status": "Draft",
32+
"organizing_team": team_id,
33+
"status": kwargs.get("status", "Draft"),
34+
"voting_status": kwargs.get("voting_status", "Unopened"),
35+
"allowed_preference_count": kwargs.get("allowed_preference_count", 1),
3236
}
3337
)
3438
election.insert()
3539

3640
return election
41+
42+
43+
def create_nomination_form(election, **kwargs) -> dict:
44+
"""Creates and returns a Nomination Form linked to an Election."""
45+
nomination_form = frappe.get_doc(
46+
{
47+
"doctype": NOMINATION_FORM,
48+
"election": election.name,
49+
"status": kwargs.get("status", "Draft"),
50+
"accept_incoming_applications": kwargs.get("accept_incoming_applications", 1),
51+
}
52+
)
53+
nomination_form.insert()
54+
55+
return nomination_form
56+
57+
58+
def create_candidate_application(election_id: str, form_id: str, **kwargs) -> dict:
59+
"""Creates and returns a Candidate Application linked to a Nomination Form.
60+
61+
Note: session user is auto added as a candidate
62+
"""
63+
64+
candidate_application = frappe.get_doc(
65+
{
66+
"user": kwargs.get("user", frappe.session.user),
67+
"doctype": CANDIDATE_APPLICATION,
68+
"election": election_id,
69+
"nomination_form": form_id,
70+
"status": kwargs.get("status", "Pending"),
71+
"full_name": fake.name(),
72+
"email": fake.email(),
73+
"designation": fake.job(),
74+
"organization": fake.company(),
75+
}
76+
)
77+
candidate_application.insert()
78+
79+
return candidate_application
80+
81+
82+
def create_candidate(election_id: str, application_id: str) -> dict:
83+
"""Creates and returns a Candidate linked to a Candidate Application."""
84+
candidate = frappe.get_doc(
85+
{
86+
"doctype": CANDIDATE,
87+
"election": election_id,
88+
"linked_application": application_id,
89+
}
90+
)
91+
candidate.insert()
92+
93+
return candidate

0 commit comments

Comments
 (0)