def test_election_endpoint_for_postcode_cors(self): election_id = "local.place-name.2017-03-23" ElectionWithStatusFactory(group=None, election_id=election_id) ElectionWithStatusFactory(group=None, division_geography=None) url = "/api/elections/?postcode=SW1A1AA" resp = self.client.get(url, HTTP_ORIGIN="foo.bar/baz") self.assertEqual(resp.get("Access-Control-Allow-Origin"), "*")
def test_metadata_filter(self): election = ElectionWithStatusFactory(group=None, poll_open_date=datetime.today()) resp = self.client.get("/api/elections/?metadata=1") data = resp.json() assert data["count"] == 0 metadata = MetaData.objects.create( description="just a test", data=""" { "2018-05-03-id-pilot": { "title": "You need to show ID to vote at this election", "url": "https://www.woking.gov.uk/voterid", "detail": " Voters in Woking will be required to show photo ID before they can vote. " } } """, ) election.metadata = metadata election.save() resp = self.client.get("/api/elections/?metadata=1") data = resp.json() assert data["count"] == 1
def test_election_status(self): # 4 ballots with different moderation statuses approved = ElectionWithStatusFactory( group=None, moderation_status=related_status("Approved")) suggested = ElectionWithStatusFactory( group=None, moderation_status=related_status("Suggested")) rejected = ElectionWithStatusFactory( group=None, moderation_status=related_status("Rejected")) deleted = ElectionWithStatusFactory( group=None, moderation_status=related_status("Deleted")) # approved elections shoud be visible via the DetailView resp = self.client.get("/elections/{}/".format(approved.election_id)) self.assertEqual(200, resp.status_code) # we shouldn't be able to access elections which are # suggsted, rejected or deleted via the DetailView resp = self.client.get("/api/elections/{}/".format( rejected.election_id)) self.assertEqual(404, resp.status_code) resp = self.client.get("/api/elections/{}/".format( suggested.election_id)) self.assertEqual(404, resp.status_code) resp = self.client.get("/api/elections/{}/".format( deleted.election_id)) self.assertEqual(404, resp.status_code)
def test_child_visibility(self): # 4 ballots in the same group with different moderation statuses group = ElectionWithStatusFactory( group_type="election", moderation_status=related_status("Approved")) approved = ElectionWithStatusFactory( group=group, moderation_status=related_status("Approved")) suggested = ElectionWithStatusFactory( group=group, moderation_status=related_status("Suggested")) rejected = ElectionWithStatusFactory( group=group, moderation_status=related_status("Rejected")) deleted = ElectionWithStatusFactory( group=group, moderation_status=related_status("Deleted")) resp = self.client.get("/api/elections/{}/".format(group.election_id)) self.assertEqual(200, resp.status_code) data = resp.json() # only the approved child election should be in the response self.assertEqual(1, len(data["children"])) self.assertEqual([approved.election_id], data["children"]) # delete the group ModerationHistoryFactory( election=group, status=ModerationStatusFactory(short_label="Deleted")) resp = self.client.get("/api/elections/{}/?deleted=1".format( group.election_id)) self.assertEqual(200, resp.status_code) data = resp.json() # deleted and approved child elections should be in the response self.assertTrue(deleted.election_id in data["children"]) self.assertTrue(approved.election_id in data["children"]) # we should never show suggested or rejected elections in API outputs self.assertTrue(suggested.election_id not in data["children"]) self.assertTrue(rejected.election_id not in data["children"])
def test_election_endpoint_for_postcode_jsonp(self): election_id = "local.place-name.2017-03-23" ElectionWithStatusFactory(group=None, election_id=election_id) ElectionWithStatusFactory(group=None, division_geography=None) url = ("/api/elections/?postcode=SW1A1AA" + "&format=jsonp&callback=a_callback_string") resp = self.client.get(url) assert resp.content.decode("utf8").startswith("a_callback_string(")
def test_election_endpoint_for_invalid_postcode(self): election_id = "local.place-name.2017-03-23" ElectionWithStatusFactory(group=None, election_id=election_id) ElectionWithStatusFactory(group=None, division_geography=None) # this input should fail the validation check resp = self.client.get("/api/elections/?postcode=not-a-postcode") data = resp.json() assert data["detail"] == "Invalid postcode"
def test_current_elections_for_postcode(self): ElectionWithStatusFactory(group=None, poll_open_date=datetime.today()) ElectionWithStatusFactory(group=None, poll_open_date=datetime.today(), division_geography=None) ElectionWithStatusFactory(group=None, poll_open_date=datetime.today() - timedelta(days=60)) assert Election.public_objects.current().for_postcode( "SW1A1AA").count() == 1
def test_has_approved_parents_two_level(self): org_group = ElectionWithStatusFactory( group=None, moderation_status=related_status("Suggested")) ballot = ElectionWithStatusFactory( group=org_group, moderation_status=related_status("Approved")) self.assertFalse(has_approved_parents(ballot)) ModerationHistoryFactory( election=org_group, status=ModerationStatusFactory(short_label="Approved")) self.assertTrue(has_approved_parents(ballot))
def test_election_endpoint_for_bad_postcode(self): election_id = "local.place-name.2017-03-23" ElectionWithStatusFactory(group=None, election_id=election_id) ElectionWithStatusFactory(group=None, division_geography=None) # this input passes the validation check # but when we call out to mapit we can't find it resp = self.client.get("/api/elections/?postcode=SW1A1AX") data = resp.json() assert data["detail"] == "Invalid postcode"
def test_election_endpoint_for_lat_lng(self): election_id = "local.place-name.2017-03-23" ElectionWithStatusFactory(group=None, election_id=election_id) ElectionWithStatusFactory(group=None, division_geography=None) resp = self.client.get( "/api/elections/?coords=51.5010089365,-0.141587600123") data = resp.json() assert data["results"][0]["election_id"] == election_id assert len(data["results"]) == 1
def test_public_private_filter_simple(self): # simple case: each election only has a single status event ElectionWithStatusFactory( group=None, moderation_status=related_status("Suggested")) ElectionWithStatusFactory(group=None, moderation_status=related_status("Approved")) ElectionWithStatusFactory(group=None, moderation_status=related_status("Rejected")) ElectionWithStatusFactory(group=None, moderation_status=related_status("Deleted")) self.assertEqual(1, Election.public_objects.count()) self.assertEqual(4, Election.private_objects.count())
def test_election_endpoint_current(self): id_current = ElectionWithStatusFactory( group=None, poll_open_date=datetime.today()).election_id id_future = ElectionWithStatusFactory( # noqa group=None, poll_open_date=datetime.today() - timedelta(days=60)).election_id resp = self.client.get("/api/elections/?current") data = resp.json() assert len(data["results"]) == 1 assert data["results"][0]["election_id"] == id_current assert data["results"][0]["current"] == True
def test_election_endpoint_for_postcode(self): election_id = "local.place-name.2017-03-23" ElectionWithStatusFactory(group=None, election_id=election_id) ElectionWithStatusFactory(group=None, division_geography=None) # we should monitor this and be aware if this number increases with self.assertNumQueries(9): resp = self.client.get("/api/elections/?postcode=SW1A1AA") data = resp.json() assert len(data["results"]) == 1 assert data["results"][0]["election_id"] == election_id
def test_election_endpoint_future(self): ElectionWithStatusFactory( group=None, poll_open_date=datetime.today(), election_id="local.place-name-future-election.2017-03-23", ) ElectionWithStatusFactory(group=None, poll_open_date=datetime.today() - timedelta(days=1)) resp = self.client.get("/api/elections/?future") data = resp.json() assert len(data["results"]) == 1 assert (data["results"][0]["election_id"] == "local.place-name-future-election.2017-03-23")
def test_election_endpoint(self): id_ = ElectionWithStatusFactory(group=None).election_id resp = self.client.get("/api/elections/") data = resp.json() assert len(data["results"]) == 1 assert data["results"][0]["election_id"] == id_
def test_has_approved_child(self): org_group = ElectionWithStatusFactory(group=None) ballots = [ ElectionWithStatusFactory( group=org_group, moderation_status=related_status("Suggested")), ElectionWithStatusFactory( group=org_group, moderation_status=related_status("Suggested")), ] self.assertFalse(has_approved_child(org_group)) # approve one of the 2 child ballots ModerationHistoryFactory( election=ballots[0], status=ModerationStatusFactory(short_label="Approved")) self.assertTrue(has_approved_child(org_group))
def test_cancelled_election_with_replacement(self): cancelled = ElectionWithStatusFactory(group=None, cancelled=True) rescheduled = ElectionWithStatusFactory(group=None, replaces=cancelled) resp = self.client.get("/api/elections/{}/".format( cancelled.election_id)) self.assertEqual(200, resp.status_code) data = resp.json() self.assertTrue(data["cancelled"]) self.assertEqual(rescheduled.election_id, data["replaced_by"]) resp = self.client.get("/api/elections/{}/".format( rescheduled.election_id)) self.assertEqual(200, resp.status_code) data = resp.json() self.assertFalse(data["cancelled"]) self.assertEqual(cancelled.election_id, data["replaces"])
def test_approve(self): self.login() # 4 ballots with different moderation statuses approved = ElectionWithStatusFactory( group=None, moderation_status=related_status("Approved")) rejected = ElectionWithStatusFactory( group=None, moderation_status=related_status("Rejected")) deleted = ElectionWithStatusFactory( group=None, moderation_status=related_status("Deleted")) suggested_parent = ElectionWithStatusFactory( group=None, group_type="organisation", moderation_status=related_status("Suggested"), ) suggested_child = ElectionWithStatusFactory( group=suggested_parent, moderation_status=related_status("Suggested")) resp = self.client.get("/election_radar/moderation_queue/") self.assertEqual(200, resp.status_code) # only suggested ballot should be shown self.assertNotContains(resp, approved.election_id, html=True) self.assertNotContains(resp, rejected.election_id, html=True) self.assertNotContains(resp, deleted.election_id, html=True) # only ballots should be shown self.assertContains(resp, suggested_child.election_id, html=True) self.assertNotContains(resp, suggested_parent.election_id, html=True) self.client.post( "/election_radar/moderation_queue/", { "election": suggested_child.pk, "{}-status".format(suggested_child.pk): "Approved", }, ) # approving the child should # implicitly approve the parent # if it is not already approved self.assertEqual("Approved", suggested_child.moderation_status.short_label) self.assertEqual("Approved", suggested_parent.moderation_status.short_label)
def test_deleted_filter_detail(self): election = ElectionWithStatusFactory( group=None, moderation_status=related_status("Deleted")) id_ = election.election_id resp = self.client.get("/api/elections/{}/".format(id_)) self.assertEqual(404, resp.status_code) resp = self.client.get("/api/elections/{}/?deleted=1".format(id_)) self.assertEqual(200, resp.status_code)
def test_current_elections(self): # This is implicetly current ElectionWithStatusFactory(group=None, poll_open_date=datetime.today()) # This is implicetly not current ElectionWithStatusFactory(group=None, poll_open_date=datetime.today() - timedelta(days=60)) # This is implicetly not current, but current manually set ElectionWithStatusFactory( group=None, poll_open_date=datetime.today() - timedelta(days=60), current=True, ) # This is implicetly current, current manually set to False ElectionWithStatusFactory( group=None, poll_open_date=datetime.today() - timedelta(days=1), current=False, ) assert Election.public_objects.current().count() == 2
def test_child_election_status(self): # 4 ballots in the same group with different moderation statuses group = ElectionWithStatusFactory( group_type="election", moderation_status=related_status("Approved")) approved = ElectionWithStatusFactory( group=group, moderation_status=related_status("Approved")) suggested = ElectionWithStatusFactory( group=group, moderation_status=related_status("Suggested")) rejected = ElectionWithStatusFactory( group=group, moderation_status=related_status("Rejected")) deleted = ElectionWithStatusFactory( group=group, moderation_status=related_status("Deleted")) # DetailView should only show approved child elections resp = self.client.get("/elections/{}/".format(group.election_id)) self.assertEqual(200, resp.status_code) self.assertContains(resp, approved.election_id, html=True) self.assertNotContains(resp, suggested.election_id, html=True) self.assertNotContains(resp, rejected.election_id, html=True) self.assertNotContains(resp, deleted.election_id, html=True)
def test_has_approved_parents_three_level(self): election_group = ElectionWithStatusFactory( group=None, moderation_status=related_status("Suggested")) org_group = ElectionWithStatusFactory( group=election_group, moderation_status=related_status("Suggested")) ballot = ElectionWithStatusFactory(group=org_group) self.assertFalse(has_approved_parents(ballot)) ModerationHistoryFactory( election=election_group, status=ModerationStatusFactory(short_label="Approved"), ) # still false because only one of our 2 parents is approved self.assertFalse(has_approved_parents(ballot)) ModerationHistoryFactory( election=org_group, status=ModerationStatusFactory(short_label="Approved")) # now both parents are approved self.assertTrue(has_approved_parents(ballot))
def test_deleted_filter_list(self): approved = ElectionWithStatusFactory( group=None, moderation_status=related_status("Approved")) deleted = ElectionWithStatusFactory( group=None, moderation_status=related_status("Deleted")) ElectionWithStatusFactory(group=None, moderation_status=related_status("Rejected")) ElectionWithStatusFactory( group=None, moderation_status=related_status("Suggested")) resp = self.client.get("/api/elections/") data = resp.json() self.assertEqual(1, data["count"]) self.assertEqual(data["results"][0]["election_id"], approved.election_id) self.assertEqual(data["results"][0]["deleted"], False) resp = self.client.get("/api/elections/?deleted=1") data = resp.json() self.assertEqual(1, data["count"]) self.assertEqual(data["results"][0]["election_id"], deleted.election_id) self.assertEqual(data["results"][0]["deleted"], True)
def test_identifier_type_filter(self): group = ElectionWithStatusFactory( group_type="election", moderation_status=related_status("Approved")) ballot = ElectionWithStatusFactory( group=group, moderation_status=related_status("Approved")) resp = self.client.get("/api/elections/?identifier_type=election") data = resp.json() self.assertEqual(1, data["count"]) self.assertEqual(data["results"][0]["election_id"], group.election_id) resp = self.client.get("/api/elections/?identifier_type=ballot") data = resp.json() self.assertEqual(1, data["count"]) self.assertEqual(data["results"][0]["election_id"], ballot.election_id) resp = self.client.get("/api/elections/?identifier_type=organisation") data = resp.json() self.assertEqual(0, data["count"]) resp = self.client.get("/api/elections/?identifier_type=foobar") data = resp.json() self.assertEqual(0, data["count"])
def test_election_for_point(self): ElectionWithStatusFactory(group=None) point = Point(self.lon, self.lat) qs = Election.public_objects.for_point(point) assert qs.count() == 1
def test_has_related_status(self): self.assertFalse(has_related_status(ElectionFactory())) self.assertTrue(has_related_status(ElectionWithStatusFactory()))
def test_election_for_lat_lng(self): ElectionWithStatusFactory(group=None) qs = Election.public_objects.for_lat_lng(lat=self.lat, lng=self.lon) assert qs.count() == 1
def test_election_for_postcode(self): ElectionWithStatusFactory(group=None) qs = Election.public_objects.for_postcode("SW1A 1AA") assert qs.count() == 1
def test_future_elections(self): ElectionWithStatusFactory(group=None, poll_open_date=datetime.today()) ElectionWithStatusFactory(group=None, poll_open_date=datetime.today() - timedelta(days=1)) assert Election.public_objects.future().count() == 1
def test_all_expected_fields_returned(self): OrganisationFactory.reset_sequence(0) OrganisationDivisionFactory.reset_sequence(0) org = OrganisationFactory() org_div = OrganisationDivisionFactory(organisation=org, territory_code="ENG") ElectionWithStatusFactory(group=None, organisation=org, division=org_div) self.expected_object = json.loads(""" { "group_type": null, "identifier_type": "ballot", "current": false, "poll_open_date": "2017-03-23", "election_id": "local.place-name-0.2017-03-23", "group": null, "division": { "name": "Division 0", "slug": "0", "divisionset": { "start_date": "2017-05-04", "legislation_url": "https://example.com/the-law", "short_title": "Made up boundary changes", "notes": "This is just for testing.", "end_date": "2025-05-03", "consultation_url": "https://example.com/consultation" }, "seats_total": null, "division_election_sub_type": "", "division_subtype": "", "division_type": "test", "official_identifier": "0", "territory_code": "ENG" }, "election_type": { "name": "Local elections", "election_type": "local" }, "explanation": null, "voting_system": { "slug": "", "name": "", "uses_party_lists": false }, "children": [], "election_subtype": null, "organisation": { "url": "http://testserver/api/organisations/local-authority/0/2016-10-01/", "slug": "org-0", "territory_code": "ENG", "organisation_subtype": "", "common_name": "Organisation 0", "official_name": "The Organisation 0 Council", "organisation_type": "local-authority", "election_name": "", "official_identifier": "0", "start_date": "2016-10-01", "end_date": null }, "election_title": "Election 0", "elected_role": "Councillor", "seats_contested": 1, "tmp_election_id": null, "metadata": null, "deleted": false, "cancelled": false, "replaces": null, "replaced_by": null } """) resp = self.client.get("/api/elections/") data = resp.json() self.assertEqual(data["results"][0], self.expected_object) resp = self.client.get("/api/elections/local.place-name-0.2017-03-23/") data = resp.json() self.assertEqual(data, self.expected_object) resp = self.client.get( "/api/elections/local.place-name-0.2017-03-23/geo/", content_type="application/json", ) data = resp.json() self.assertEqual(data["properties"], self.expected_object)