Skip to content

Commit 27629df

Browse files
authored
Make careers department helpers read from static list only. (#2802)
1 parent 4ffaaa0 commit 27629df

3 files changed

Lines changed: 231 additions & 108 deletions

File tree

tests/test_careers.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import logging
2+
import unittest
3+
from types import SimpleNamespace
4+
from unittest.mock import MagicMock
5+
6+
from webapp.careers import (
7+
DEPARTMENT_LIST,
8+
get_all_departments,
9+
group_by_department,
10+
)
11+
12+
13+
logging.getLogger("talisker.context").disabled = True
14+
15+
16+
def _make_vacancy(*department_slugs):
17+
"""
18+
Build a minimal vacancy-like object.
19+
20+
``group_by_department`` only relies on each vacancy exposing a
21+
``departments`` list whose items have a ``slug`` attribute, so we
22+
avoid constructing full ``Vacancy`` instances here.
23+
"""
24+
departments = [SimpleNamespace(slug=slug) for slug in department_slugs]
25+
return SimpleNamespace(departments=departments)
26+
27+
28+
class TestGroupByDepartment(unittest.TestCase):
29+
def test_includes_every_known_department(self):
30+
"""
31+
Every department in DEPARTMENT_LIST should be present as a key,
32+
even when there are no vacancies at all.
33+
"""
34+
grouped = group_by_department([])
35+
36+
self.assertEqual(list(grouped.keys()), list(DEPARTMENT_LIST.keys()))
37+
38+
def test_order_matches_department_list(self):
39+
"""
40+
The order of the returned dict should always match the order of
41+
DEPARTMENT_LIST, regardless of the vacancy data.
42+
"""
43+
vacancies = [
44+
_make_vacancy("legal"),
45+
_make_vacancy("engineering"),
46+
_make_vacancy("sales"),
47+
]
48+
49+
grouped = group_by_department(vacancies)
50+
51+
self.assertEqual(list(grouped.keys()), list(DEPARTMENT_LIST.keys()))
52+
53+
def test_preserves_department_metadata(self):
54+
"""
55+
Each grouped department should keep its original metadata and gain
56+
an empty "vacancies" list when no vacancies match.
57+
"""
58+
grouped = group_by_department([])
59+
60+
engineering = grouped["engineering"]
61+
self.assertEqual(engineering["name"], "Engineering")
62+
self.assertEqual(engineering["slug"], "engineering")
63+
self.assertEqual(
64+
engineering["icon"], DEPARTMENT_LIST["engineering"]["icon"]
65+
)
66+
self.assertEqual(engineering["vacancies"], [])
67+
68+
def test_assigns_vacancies_to_their_department(self):
69+
"""
70+
Vacancies should be appended to the department that matches their
71+
department slug.
72+
"""
73+
engineering_vacancy = _make_vacancy("engineering")
74+
sales_vacancy = _make_vacancy("sales")
75+
76+
grouped = group_by_department([engineering_vacancy, sales_vacancy])
77+
78+
self.assertEqual(
79+
grouped["engineering"]["vacancies"], [engineering_vacancy]
80+
)
81+
self.assertEqual(grouped["sales"]["vacancies"], [sales_vacancy])
82+
self.assertEqual(grouped["legal"]["vacancies"], [])
83+
84+
def test_vacancy_in_multiple_departments(self):
85+
"""
86+
A vacancy that belongs to several departments should appear under
87+
each matching department.
88+
"""
89+
vacancy = _make_vacancy("engineering", "product")
90+
91+
grouped = group_by_department([vacancy])
92+
93+
self.assertIn(vacancy, grouped["engineering"]["vacancies"])
94+
self.assertIn(vacancy, grouped["product"]["vacancies"])
95+
96+
def test_ignores_unknown_department_slugs(self):
97+
"""
98+
Vacancies belonging to an unknown department should be dropped and
99+
must not create new keys.
100+
"""
101+
vacancy = _make_vacancy("nonexistent-department")
102+
103+
grouped = group_by_department([vacancy])
104+
105+
self.assertNotIn("nonexistent-department", grouped)
106+
self.assertEqual(list(grouped.keys()), list(DEPARTMENT_LIST.keys()))
107+
for department in grouped.values():
108+
self.assertEqual(department["vacancies"], [])
109+
110+
111+
class TestGetAllDepartments(unittest.TestCase):
112+
def _make_greenhouse(self, vacancies):
113+
greenhouse = MagicMock()
114+
greenhouse.get_vacancies.return_value = vacancies
115+
return greenhouse
116+
117+
def test_returns_grouped_departments_and_overview(self):
118+
"""
119+
get_all_departments should return a (grouped, overview) tuple where
120+
the overview summarises each department.
121+
"""
122+
greenhouse = self._make_greenhouse(
123+
[_make_vacancy("engineering"), _make_vacancy("engineering")]
124+
)
125+
126+
all_departments, overview = get_all_departments(greenhouse)
127+
128+
self.assertEqual(
129+
list(all_departments.keys()), list(DEPARTMENT_LIST.keys())
130+
)
131+
self.assertEqual(len(overview), len(DEPARTMENT_LIST))
132+
133+
def test_overview_entry_shape_and_counts(self):
134+
"""
135+
Each overview entry should expose name, count, slug and icon, and
136+
the count should reflect the number of matching vacancies.
137+
"""
138+
greenhouse = self._make_greenhouse(
139+
[
140+
_make_vacancy("engineering"),
141+
_make_vacancy("engineering"),
142+
_make_vacancy("sales"),
143+
]
144+
)
145+
146+
_, overview = get_all_departments(greenhouse)
147+
overview_by_slug = {entry["slug"]: entry for entry in overview}
148+
149+
self.assertEqual(
150+
set(overview_by_slug["engineering"].keys()),
151+
{"name", "count", "slug", "icon"},
152+
)
153+
self.assertEqual(overview_by_slug["engineering"]["count"], 2)
154+
self.assertEqual(overview_by_slug["sales"]["count"], 1)
155+
self.assertEqual(overview_by_slug["legal"]["count"], 0)
156+
self.assertEqual(
157+
overview_by_slug["engineering"]["name"], "Engineering"
158+
)
159+
self.assertEqual(
160+
overview_by_slug["engineering"]["icon"],
161+
DEPARTMENT_LIST["engineering"]["icon"],
162+
)
163+
164+
def test_overview_order_matches_department_list(self):
165+
"""
166+
The overview order should follow DEPARTMENT_LIST.
167+
"""
168+
greenhouse = self._make_greenhouse([])
169+
170+
_, overview = get_all_departments(greenhouse)
171+
172+
self.assertEqual(
173+
[entry["slug"] for entry in overview],
174+
list(DEPARTMENT_LIST.keys()),
175+
)
176+
177+
178+
if __name__ == "__main__":
179+
unittest.main()

webapp/app.py

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@
7171
)
7272
from webapp.careers import (
7373
DEPARTMENT_LIST,
74-
_get_sorted_departments,
75-
_get_all_departments,
74+
group_by_department,
75+
get_all_departments,
7676
)
7777
from webapp.greenhouse import Greenhouse, Harvest
7878
from webapp.handlers import init_handlers
@@ -573,13 +573,12 @@ def handle_roles():
573573
"""
574574
with get_requests_session() as session:
575575
greenhouse = Greenhouse.from_session(session)
576-
harvest = Harvest.from_session(session)
577-
return roles(greenhouse, harvest)
576+
return roles(greenhouse)
578577

579578

580-
def roles(greenhouse, harvest):
581-
all_departments, departments_overview = _get_all_departments(
582-
greenhouse, harvest
579+
def roles(greenhouse):
580+
_, departments_overview = get_all_departments(
581+
greenhouse,
583582
)
584583
return flask.jsonify(departments_overview)
585584

@@ -592,14 +591,11 @@ def handle_careers_index():
592591
"""
593592
with get_requests_session() as session:
594593
greenhouse = Greenhouse.from_session(session)
595-
harvest = Harvest.from_session(session)
596-
return careers_index(greenhouse, harvest)
594+
return careers_index(greenhouse)
597595

598596

599-
def careers_index(greenhouse, harvest):
600-
all_departments, departments_overview = _get_all_departments(
601-
greenhouse, harvest
602-
)
597+
def careers_index(greenhouse):
598+
all_departments, departments_overview = get_all_departments(greenhouse)
603599

604600
return flask.render_template(
605601
"/careers/index.html",
@@ -616,12 +612,11 @@ def careers_index(greenhouse, harvest):
616612
def handle_all_careers():
617613
with get_requests_session() as session:
618614
greenhouse = Greenhouse.from_session(session)
619-
harvest = Harvest.from_session(session)
620-
return all_careers(greenhouse, harvest)
615+
return all_careers(greenhouse)
621616

622617

623-
def all_careers(greenhouse, harvest):
624-
sorted_departments = _get_sorted_departments(greenhouse, harvest)
618+
def all_careers(greenhouse):
619+
sorted_departments = group_by_department(greenhouse.get_vacancies())
625620

626621
return flask.render_template(
627622
"/careers/all.html",
@@ -654,14 +649,11 @@ def culture():
654649
def handle_careers_progression():
655650
with get_requests_session() as session:
656651
greenhouse = Greenhouse.from_session(session)
657-
harvest = Harvest.from_session(session)
658-
return careers_progression(greenhouse, harvest)
652+
return careers_progression(greenhouse)
659653

660654

661-
def careers_progression(greenhouse, harvest):
662-
all_departments, departments_overview = _get_all_departments(
663-
greenhouse, harvest
664-
)
655+
def careers_progression(greenhouse):
656+
all_departments, departments_overview = get_all_departments(greenhouse)
665657

666658
return flask.render_template(
667659
"/careers/company-culture/progression.html",
@@ -720,12 +712,11 @@ def working_here_pages(greenhouse):
720712
def handle_department_group(department_slug):
721713
with get_requests_session() as session:
722714
greenhouse = Greenhouse.from_session(session)
723-
harvest = Harvest.from_session(session)
724-
return department_group(greenhouse, harvest, department_slug)
715+
return department_group(greenhouse, department_slug)
725716

726717

727-
def department_group(greenhouse, harvest, department_slug):
728-
departments = _get_sorted_departments(greenhouse, harvest)
718+
def department_group(greenhouse, department_slug):
719+
departments = group_by_department(greenhouse.get_vacancies())
729720

730721
if department_slug not in departments:
731722
flask.abort(404)
@@ -734,13 +725,16 @@ def department_group(greenhouse, harvest, department_slug):
734725

735726
# format edge case slugs
736727
formatted_slug = ""
737-
if " & " in department.name:
738-
formatted_slug = department.name.replace(" & ", "+%26+")
739-
elif " " in department.name:
740-
formatted_slug = department.name.replace(" ", "+")
741-
742-
featured_jobs = [job for job in department.vacancies if job.featured]
743-
fast_track_jobs = [job for job in department.vacancies if job.fast_track]
728+
department_name = department["name"]
729+
if " & " in department_name:
730+
formatted_slug = department_name.replace(" & ", "+%26+")
731+
elif " " in department_name:
732+
formatted_slug = department_name.replace(" ", "+")
733+
734+
featured_jobs = [job for job in department["vacancies"] if job.featured]
735+
fast_track_jobs = [
736+
job for job in department["vacancies"] if job.fast_track
737+
]
744738

745739
templates = []
746740

0 commit comments

Comments
 (0)