codeforlife-portal 5.33.5__py2.py3-none-any.whl → 8.9.9__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. cfl_common/common/__init__.py +1 -0
  2. cfl_common/common/app_settings.py +66 -0
  3. cfl_common/common/apps.py +6 -0
  4. cfl_common/common/context_processors.py +9 -0
  5. cfl_common/common/csp_config.py +85 -0
  6. cfl_common/common/helpers/__init__.py +0 -0
  7. cfl_common/common/helpers/data_migration_loader.py +42 -0
  8. cfl_common/common/helpers/emails.py +393 -0
  9. cfl_common/common/helpers/generators.py +52 -0
  10. cfl_common/common/helpers/organisation.py +10 -0
  11. cfl_common/common/mail.py +201 -0
  12. cfl_common/common/migrations/0001_initial.py +240 -0
  13. cfl_common/common/migrations/0002_emailverification.py +55 -0
  14. cfl_common/common/migrations/0003_aimmocharacter.py +31 -0
  15. cfl_common/common/migrations/0004_add_aimmocharacters.py +17 -0
  16. cfl_common/common/migrations/0005_add_worksheets.py +8 -0
  17. cfl_common/common/migrations/0006_update_aimmo_character_image_path.py +17 -0
  18. cfl_common/common/migrations/0007_add_pdf_names_to_first_two_worksheets.py +8 -0
  19. cfl_common/common/migrations/0008_unlock_worksheet_3.py +11 -0
  20. cfl_common/common/migrations/0009_add_blocked_time_to_teacher_and_student.py +24 -0
  21. cfl_common/common/migrations/0010_remove_teacher_title.py +18 -0
  22. cfl_common/common/migrations/0011_student_login_id.py +18 -0
  23. cfl_common/common/migrations/0012_usersession.py +39 -0
  24. cfl_common/common/migrations/0013_class_school.py +42 -0
  25. cfl_common/common/migrations/0014_login_type.py +29 -0
  26. cfl_common/common/migrations/0015_dailyactivity.py +31 -0
  27. cfl_common/common/migrations/0016_joinreleasestudent.py +42 -0
  28. cfl_common/common/migrations/0017_copy_email_to_username.py +18 -0
  29. cfl_common/common/migrations/0018_update_aimmo_character_image_path.py +15 -0
  30. cfl_common/common/migrations/0019_aimmocharacter_alt.py +16 -0
  31. cfl_common/common/migrations/0020_class_is_active_and_null_access_code.py +23 -0
  32. cfl_common/common/migrations/0021_school_is_active.py +28 -0
  33. cfl_common/common/migrations/0022_school_cleanup.py +29 -0
  34. cfl_common/common/migrations/0023_userprofile_aimmo_badges.py +22 -0
  35. cfl_common/common/migrations/0024_teacher_invited_by.py +25 -0
  36. cfl_common/common/migrations/0025_schoolteacherinvitation.py +47 -0
  37. cfl_common/common/migrations/0026_teacher_remove_join_request.py +22 -0
  38. cfl_common/common/migrations/0027_class_created_by.py +25 -0
  39. cfl_common/common/migrations/0028_coding_club_downloads.py +23 -0
  40. cfl_common/common/migrations/0029_dynamicelement.py +22 -0
  41. cfl_common/common/migrations/0030_add_maintenance_banner.py +25 -0
  42. cfl_common/common/migrations/0031_improve_admin_panel.py +56 -0
  43. cfl_common/common/migrations/0032_dailyactivity_level_control_submits.py +18 -0
  44. cfl_common/common/migrations/0033_password_reset_tracking_fields.py +23 -0
  45. cfl_common/common/migrations/0034_dailyactivity_daily_school_student_lockout_reset.py +18 -0
  46. cfl_common/common/migrations/0035_rename_lockout_fields.py +27 -0
  47. cfl_common/common/migrations/0036_rename_awaiting_email_verification_userprofile_is_verified.py +17 -0
  48. cfl_common/common/migrations/0037_migrate_email_verification.py +21 -0
  49. cfl_common/common/migrations/0038_delete_emailverification.py +16 -0
  50. cfl_common/common/migrations/0039_copy_email_to_username.py +18 -0
  51. cfl_common/common/migrations/0040_school_county.py +18 -0
  52. cfl_common/common/migrations/0041_populate_gb_counties.py +27 -0
  53. cfl_common/common/migrations/0042_totalactivity.py +25 -0
  54. cfl_common/common/migrations/0043_add_total_activity.py +30 -0
  55. cfl_common/common/migrations/0044_update_activity_models.py +33 -0
  56. cfl_common/common/migrations/0045_otp.py +23 -0
  57. cfl_common/common/migrations/0046_alter_school_country.py +19 -0
  58. cfl_common/common/migrations/0047_delete_school_postcode.py +16 -0
  59. cfl_common/common/migrations/0048_unique_school_names.py +42 -0
  60. cfl_common/common/migrations/0049_anonymise_orphan_users.py +29 -0
  61. cfl_common/common/migrations/0050_anonymise_orphan_schools.py +30 -0
  62. cfl_common/common/migrations/0051_verify_returning_users.py +26 -0
  63. cfl_common/common/migrations/0052_add_cse_fields.py +68 -0
  64. cfl_common/common/migrations/0053_clean_class_data.py +24 -0
  65. cfl_common/common/migrations/0054_delete_aimmo_models.py +20 -0
  66. cfl_common/common/migrations/0055_alter_schoolteacherinvitation_token.py +18 -0
  67. cfl_common/common/migrations/0056_set_non_school_teachers_as_non_admins.py +25 -0
  68. cfl_common/common/migrations/0057_teacher_teacher__is_admin.py +19 -0
  69. cfl_common/common/migrations/0058_userprofile_google_refresh_token_and_more.py +24 -0
  70. cfl_common/common/migrations/__init__.py +0 -0
  71. cfl_common/common/models.py +557 -0
  72. cfl_common/common/permissions.py +84 -0
  73. cfl_common/common/tests/__init__.py +0 -0
  74. cfl_common/common/tests/test_migration_anonymise_orphan_schools.py +30 -0
  75. cfl_common/common/tests/test_migration_anonymise_orphan_users.py +30 -0
  76. cfl_common/common/tests/test_migration_blocked_time.py +15 -0
  77. cfl_common/common/tests/test_migration_remove_teacher_title.py +13 -0
  78. cfl_common/common/tests/test_migration_unique_school_names.py +33 -0
  79. cfl_common/common/tests/test_migration_verify_returning_users.py +59 -0
  80. cfl_common/common/tests/test_models.py +87 -0
  81. cfl_common/common/tests/utils/__init__.py +0 -0
  82. cfl_common/common/tests/utils/classes.py +38 -0
  83. cfl_common/common/tests/utils/email.py +67 -0
  84. cfl_common/common/tests/utils/organisation.py +41 -0
  85. cfl_common/common/tests/utils/student.py +123 -0
  86. cfl_common/common/tests/utils/teacher.py +73 -0
  87. cfl_common/common/tests/utils/user.py +27 -0
  88. cfl_common/common/utils.py +56 -0
  89. cfl_common/setup.py +61 -0
  90. codeforlife_portal-8.9.9.dist-info/METADATA +226 -0
  91. {codeforlife_portal-5.33.5.dist-info → codeforlife_portal-8.9.9.dist-info}/RECORD +339 -241
  92. {codeforlife_portal-5.33.5.dist-info → codeforlife_portal-8.9.9.dist-info}/WHEEL +1 -1
  93. codeforlife_portal-8.9.9.dist-info/licenses/LICENSE.md +3 -0
  94. {codeforlife_portal-5.33.5.dist-info → codeforlife_portal-8.9.9.dist-info}/top_level.txt +1 -0
  95. deploy/middleware/maintenance.py +25 -0
  96. deploy/middleware/screentime_warning.py +29 -0
  97. deploy/middleware/security.py +5 -6
  98. deploy/middleware/session_timeout.py +4 -2
  99. deploy/middleware/tmp_basic_auth.py +41 -0
  100. example_project/portal_test_settings.py +239 -0
  101. example_project/settings.py +156 -17
  102. example_project/urls.py +5 -6
  103. portal/__init__.py +1 -1
  104. portal/admin.py +142 -29
  105. portal/app_settings.py +8 -7
  106. portal/forms/dotmailer.py +6 -4
  107. portal/forms/invite_teacher.py +19 -10
  108. portal/forms/organisation.py +137 -68
  109. portal/forms/play.py +53 -98
  110. portal/forms/registration.py +70 -164
  111. portal/forms/teach.py +147 -121
  112. portal/handlers.py +1 -2
  113. portal/helpers/decorators.py +30 -10
  114. portal/helpers/password.py +86 -47
  115. portal/helpers/ratelimit.py +32 -15
  116. portal/helpers/regexes.py +5 -0
  117. portal/helpers/request_handlers.py +10 -0
  118. portal/migrations/0044_auto_20150430_0959.py +6 -2
  119. portal/mixins/__init__.py +1 -0
  120. portal/mixins/cron_mixin.py +12 -0
  121. portal/permissions/__init__.py +1 -0
  122. portal/permissions/is_cron_request_from_google.py +14 -0
  123. portal/static/portal/img/10_years_anniversary.png +0 -0
  124. portal/static/portal/img/RR_logo_grass_background.png +0 -0
  125. portal/static/portal/img/coding_club_hero.jpg +0 -0
  126. portal/static/portal/img/coding_club_python_pack.png +0 -0
  127. portal/static/portal/img/facebook.png +0 -0
  128. portal/static/portal/img/gitbook.png +0 -0
  129. portal/static/portal/img/howe_dell_1.png +0 -0
  130. portal/static/portal/img/howe_dell_2.png +0 -0
  131. portal/static/portal/img/howe_dell_3.png +0 -0
  132. portal/static/portal/img/logo_cfl.png +0 -0
  133. portal/static/portal/img/logo_cfl_powered.svg +35 -0
  134. portal/static/portal/img/logo_cfl_reminder_cards.jpg +0 -0
  135. portal/static/portal/img/logo_ocado_group.png +0 -0
  136. portal/static/portal/img/logo_python_den.svg +21 -0
  137. portal/static/portal/img/long_europe_map.png +0 -0
  138. portal/static/portal/img/python_den.png +0 -0
  139. portal/static/portal/img/python_den_banner.svg +26 -0
  140. portal/static/portal/img/rapid_router_landing_hero.png +0 -0
  141. portal/static/portal/img/rr_advanced.png +0 -0
  142. portal/static/portal/img/ten_year_map_pin.svg +1 -0
  143. portal/static/portal/img/thumbnail_educate_rapid_router.png +0 -0
  144. portal/static/portal/img/thumbnail_educate_resources.png +0 -0
  145. portal/static/portal/img/thumbnail_play_rapid_router.png +0 -0
  146. portal/static/portal/img/thumbnail_python_den.png +0 -0
  147. portal/static/portal/img/twitter.png +0 -0
  148. portal/static/portal/js/carouselCards.js +25 -0
  149. portal/static/portal/js/common.js +96 -1
  150. portal/static/portal/js/independentLogin.js +16 -0
  151. portal/static/portal/js/independentRegistration.js +86 -0
  152. portal/static/portal/js/levelControl.js +77 -0
  153. portal/static/portal/js/lib/jquery.min.js +2 -0
  154. portal/static/portal/js/organisation_manage.js +142 -14
  155. portal/static/portal/js/passwordStrength.js +154 -64
  156. portal/static/portal/js/resetPassword.js +23 -0
  157. portal/static/portal/js/riveted.min.js +238 -239
  158. portal/static/portal/js/school.js +13 -0
  159. portal/static/portal/js/studentLogin.js +16 -0
  160. portal/static/portal/js/teacherEditStudent.js +23 -0
  161. portal/static/portal/js/teacherLogin.js +16 -0
  162. portal/static/portal/js/tenYearMap.js +14 -0
  163. portal/static/portal/sass/colorbox.scss +0 -1
  164. portal/static/portal/sass/modules/_colours.scss +1 -0
  165. portal/static/portal/sass/modules/_levels.scss +1 -1
  166. portal/static/portal/sass/modules/_mixins.scss +21 -0
  167. portal/static/portal/sass/partials/_banners.scss +4 -177
  168. portal/static/portal/sass/partials/_buttons.scss +12 -15
  169. portal/static/portal/sass/partials/_carousel.scss +129 -0
  170. portal/static/portal/sass/partials/_footer.scss +21 -22
  171. portal/static/portal/sass/partials/_forms.scss +60 -5
  172. portal/static/portal/sass/partials/_grids.scss +34 -61
  173. portal/static/portal/sass/partials/_header.scss +28 -20
  174. portal/static/portal/sass/partials/_images.scss +292 -39
  175. portal/static/portal/sass/partials/_popup.scss +18 -15
  176. portal/static/portal/sass/partials/_tables.scss +12 -20
  177. portal/static/portal/sass/partials/_text.scss +6 -10
  178. portal/static/portal/sass/styles.scss +0 -1
  179. portal/static/portal/video/code for life .pdf +0 -0
  180. portal/strings/about.py +5 -0
  181. portal/strings/coding_club.py +9 -0
  182. portal/strings/play.py +6 -5
  183. portal/strings/teach.py +1 -1
  184. portal/strings/teacher_resources.py +2 -8
  185. portal/strings/ten_year_map.py +13 -0
  186. portal/templates/403.html +2 -2
  187. portal/templates/404.html +1 -1
  188. portal/templates/500.html +2 -2
  189. portal/templates/{captcha → django_recaptcha}/includes/js_v2_invisible.html +3 -3
  190. portal/templates/{captcha → django_recaptcha}/widget_v2_invisible.html +2 -2
  191. portal/templates/email.html +4 -2
  192. portal/templates/maintenance.html +34 -0
  193. portal/templates/portal/about.html +94 -62
  194. portal/templates/portal/base.html +176 -152
  195. portal/templates/portal/coding_club.html +100 -0
  196. portal/templates/portal/contribute.html +56 -52
  197. portal/templates/portal/email_invitation_sent.html +1 -1
  198. portal/templates/portal/email_style_template.html +374 -0
  199. portal/templates/portal/email_verification_failed.html +1 -1
  200. portal/templates/portal/email_verification_needed.html +9 -9
  201. portal/templates/portal/form_shapes.html +20 -8
  202. portal/templates/portal/getinvolved.html +6 -6
  203. portal/templates/portal/home.html +35 -10
  204. portal/templates/portal/home_learning.html +19 -19
  205. portal/templates/portal/locked_out.html +0 -1
  206. portal/templates/portal/locked_out_school_student.html +16 -0
  207. portal/templates/portal/login/independent_student.html +31 -15
  208. portal/templates/portal/login/student.html +10 -7
  209. portal/templates/portal/login/student_class_code.html +7 -4
  210. portal/templates/portal/login/teacher.html +34 -17
  211. portal/templates/portal/partials/banner.html +18 -4
  212. portal/templates/portal/partials/benefits.html +1 -1
  213. portal/templates/portal/partials/card_list.html +34 -24
  214. portal/templates/portal/partials/character_list.html +5 -5
  215. portal/templates/portal/partials/cookie_list.html +161 -0
  216. portal/templates/portal/partials/delete_popup.html +18 -0
  217. portal/templates/portal/partials/footer.html +57 -26
  218. portal/templates/portal/partials/header.html +118 -117
  219. portal/templates/portal/partials/hero_card.html +4 -3
  220. portal/templates/portal/partials/info_popup.html +3 -3
  221. portal/templates/portal/partials/invite_admin_teacher.html +23 -0
  222. portal/templates/portal/partials/popup.html +7 -2
  223. portal/templates/portal/partials/register_newsletter_tickbox.html +2 -5
  224. portal/templates/portal/partials/screentime_popup.html +14 -0
  225. portal/templates/portal/partials/service_unavailable_popup.html +17 -0
  226. portal/templates/portal/partials/session_popup.html +19 -0
  227. portal/templates/portal/play/student_dashboard.html +42 -29
  228. portal/templates/portal/play/student_edit_account.html +64 -9
  229. portal/templates/portal/play.html +61 -41
  230. portal/templates/portal/privacy_notice.html +697 -0
  231. portal/templates/portal/register.html +122 -92
  232. portal/templates/portal/reset_password.html +20 -40
  233. portal/templates/portal/reset_password_confirm.html +9 -4
  234. portal/templates/portal/reset_password_email_sent.html +15 -13
  235. portal/templates/portal/teach/base_registering.html +1 -1
  236. portal/templates/portal/teach/class.html +4 -6
  237. portal/templates/portal/teach/dashboard.html +212 -117
  238. portal/templates/portal/teach/invited.html +90 -0
  239. portal/templates/portal/teach/onboarding_classes.html +5 -3
  240. portal/templates/portal/teach/onboarding_print.html +1 -1
  241. portal/templates/portal/teach/onboarding_school.html +26 -139
  242. portal/templates/portal/teach/onboarding_students.html +1 -1
  243. portal/templates/portal/teach/teacher_dismiss_students.html +73 -55
  244. portal/templates/portal/teach/teacher_edit_class.html +168 -11
  245. portal/templates/portal/teach/teacher_edit_student.html +12 -5
  246. portal/templates/portal/teach/teacher_move_all_classes.html +25 -38
  247. portal/templates/portal/teach/teacher_move_students_to_class.html +1 -1
  248. portal/templates/portal/teach.html +61 -42
  249. portal/templates/portal/ten_year_map.html +147 -0
  250. portal/templates/portal/terms.html +191 -42
  251. portal/templates/two_factor/core/login.html +71 -59
  252. portal/templates/two_factor/core/setup.html +58 -49
  253. portal/templates/two_factor/profile/disable.html +1 -1
  254. portal/templates/two_factor/profile/profile.html +35 -17
  255. portal/templatetags/app_tags.py +59 -84
  256. portal/templatetags/card_list_tags.py +0 -4
  257. portal/tests/base_test.py +14 -3
  258. portal/tests/conftest.py +0 -15
  259. portal/tests/migrations/test_migration_make_portaladmin_teacher.py +2 -6
  260. portal/tests/migrations/test_migration_preview_users.py +3 -9
  261. portal/tests/migrations/test_migration_remove_guardian.py +1 -3
  262. portal/tests/migrations/test_migration_use_common_models.py +2 -6
  263. portal/tests/migrations/test_migration_verify_portaladmin.py +1 -3
  264. portal/tests/pageObjects/portal/admin/admin_base_page.py +0 -21
  265. portal/tests/pageObjects/portal/base_page.py +16 -26
  266. portal/tests/pageObjects/portal/email_verification_needed_page.py +3 -2
  267. portal/tests/pageObjects/portal/game_page.py +12 -19
  268. portal/tests/pageObjects/portal/home_page.py +13 -15
  269. portal/tests/pageObjects/portal/independent_login_page.py +13 -17
  270. portal/tests/pageObjects/portal/password_reset_form_page.py +20 -4
  271. portal/tests/pageObjects/portal/password_reset_page.py +25 -0
  272. portal/tests/pageObjects/portal/play/account_page.py +18 -27
  273. portal/tests/pageObjects/portal/play/dashboard_page.py +4 -4
  274. portal/tests/pageObjects/portal/play/join_school_or_club_page.py +8 -10
  275. portal/tests/pageObjects/portal/play/play_base_page.py +5 -3
  276. portal/tests/pageObjects/portal/signup_page.py +28 -59
  277. portal/tests/pageObjects/portal/student_login_class_code.py +6 -9
  278. portal/tests/pageObjects/portal/student_login_page.py +6 -8
  279. portal/tests/pageObjects/portal/teach/add_independent_student_to_class_page.py +3 -3
  280. portal/tests/pageObjects/portal/teach/added_independent_student_to_class_page.py +3 -1
  281. portal/tests/pageObjects/portal/teach/class_page.py +36 -13
  282. portal/tests/pageObjects/portal/teach/dashboard_page.py +43 -84
  283. portal/tests/pageObjects/portal/teach/dismiss_students_page.py +7 -5
  284. portal/tests/pageObjects/portal/teach/edit_student_page.py +10 -8
  285. portal/tests/pageObjects/portal/teach/move_class_page.py +5 -10
  286. portal/tests/pageObjects/portal/teach/move_classes_page.py +4 -2
  287. portal/tests/pageObjects/portal/teach/move_students_disambiguate_page.py +4 -2
  288. portal/tests/pageObjects/portal/teach/move_students_page.py +6 -13
  289. portal/tests/pageObjects/portal/teach/onboarding_classes_page.py +5 -3
  290. portal/tests/pageObjects/portal/teach/onboarding_organisation_page.py +11 -49
  291. portal/tests/pageObjects/portal/teach/onboarding_student_list_page.py +7 -12
  292. portal/tests/pageObjects/portal/teach/onboarding_students_page.py +4 -27
  293. portal/tests/pageObjects/portal/teach/teach_base_page.py +6 -4
  294. portal/tests/pageObjects/portal/teacher_login_page.py +10 -16
  295. portal/tests/selenium_test_case.py +3 -43
  296. portal/tests/snapshots/snap_test_partials.py +11 -165
  297. portal/tests/test_2FA.py +15 -33
  298. portal/tests/test_admin.py +15 -97
  299. portal/tests/test_api.py +212 -91
  300. portal/tests/test_captcha_forms.py +2 -2
  301. portal/tests/test_class.py +374 -24
  302. portal/tests/test_emails.py +83 -20
  303. portal/tests/{test_newsletter_footer.py → test_global_forms.py} +5 -5
  304. portal/tests/test_helper_methods.py +30 -0
  305. portal/tests/test_independent_student.py +255 -144
  306. portal/tests/test_invite_teacher.py +318 -10
  307. portal/tests/test_middleware.py +96 -9
  308. portal/tests/test_organisation.py +78 -262
  309. portal/tests/test_partials.py +0 -88
  310. portal/tests/test_ratelimit.py +218 -36
  311. portal/tests/test_school_student.py +35 -40
  312. portal/tests/test_security.py +12 -31
  313. portal/tests/test_teacher.py +425 -325
  314. portal/tests/test_teacher_student.py +103 -91
  315. portal/tests/test_views.py +900 -76
  316. portal/tests/utils/classes.py +2 -2
  317. portal/tests/utils/messages.py +13 -28
  318. portal/urls.py +235 -166
  319. portal/views/admin.py +0 -332
  320. portal/views/api.py +82 -48
  321. portal/views/cron/__init__.py +1 -0
  322. portal/views/cron/user.py +322 -0
  323. portal/views/dotmailer.py +9 -1
  324. portal/views/email.py +33 -77
  325. portal/views/google_analytics.py +28 -0
  326. portal/views/home.py +126 -97
  327. portal/views/legal.py +13 -0
  328. portal/views/login/independent_student.py +5 -5
  329. portal/views/login/student.py +51 -14
  330. portal/views/login/teacher.py +2 -6
  331. portal/views/organisation.py +20 -189
  332. portal/views/registration.py +97 -17
  333. portal/views/student/edit_account_details.py +99 -72
  334. portal/views/student/play.py +81 -62
  335. portal/views/teacher/dashboard.py +421 -149
  336. portal/views/teacher/teach.py +226 -177
  337. portal/views/two_factor/core.py +22 -19
  338. portal/views/two_factor/profile.py +2 -2
  339. codeforlife_portal-5.33.5.dist-info/LICENSE.md +0 -577
  340. codeforlife_portal-5.33.5.dist-info/METADATA +0 -38
  341. deploy/permissions.py +0 -2
  342. example_project/manage.py +0 -10
  343. portal/autoconfig.py +0 -141
  344. portal/csp_config.py +0 -60
  345. portal/forms/add_game.py +0 -33
  346. portal/helpers/location.py +0 -121
  347. portal/static/portal/img/kurono_hero.jpg +0 -0
  348. portal/static/portal/img/kurono_landing_hero.png +0 -0
  349. portal/static/portal/img/kurono_logo.svg +0 -1
  350. portal/static/portal/img/kurono_logo_grey_background.svg +0 -1
  351. portal/static/portal/img/kurono_logo_mark.svg +0 -1
  352. portal/static/portal/img/kurono_resources_hero.jpg +0 -0
  353. portal/static/portal/img/kurono_story.png +0 -0
  354. portal/static/portal/img/ocado-swirl.svg +0 -22
  355. portal/static/portal/img/thumbnail_educate_kurono.png +0 -0
  356. portal/static/portal/img/thumbnail_educate_resources_and_progress_tracking.png +0 -0
  357. portal/static/portal/img/thumbnail_kurono_resources.png +0 -0
  358. portal/static/portal/img/thumbnail_play_kurono.png +0 -0
  359. portal/static/portal/img/x_close_video.png +0 -0
  360. portal/static/portal/js/aimmoGame.js +0 -106
  361. portal/static/portal/js/deleteWorkspaces.js +0 -14
  362. portal/static/portal/js/fuzzySchoolLookup.js +0 -46
  363. portal/static/portal/js/lib/jquery-3.5.1.min.js +0 -2
  364. portal/static/portal/js/lib/jquery-ui-1.12.1.min.js +0 -13
  365. portal/static/portal/sass/partials/_videos.scss +0 -10
  366. portal/static/portal/video/aimmo_play_now_background_video.mp4 +0 -0
  367. portal/strings/student_aimmo_dashboard.py +0 -6
  368. portal/templates/portal/admin/aggregated_data.html +0 -35
  369. portal/templates/portal/admin/map.html +0 -70
  370. portal/templates/portal/mouseflow.html +0 -9
  371. portal/templates/portal/partials/aimmo_games_table.html +0 -83
  372. portal/templates/portal/partials/register_over_required_age_tickbox.html +0 -9
  373. portal/templates/portal/play/independent_student_dashboard.html +0 -64
  374. portal/templates/portal/play/student_aimmo_dashboard.html +0 -63
  375. portal/templates/portal/privacy_policy.html +0 -483
  376. portal/templates/portal/reset_password_email.html +0 -9
  377. portal/templates/portal/teach/invite.html +0 -25
  378. portal/templates/portal/teach/teacher_aimmo_dashboard.html +0 -95
  379. portal/templates/portal/teach/teacher_resources.html +0 -68
  380. portal/templatetags/character_list_tags.py +0 -16
  381. portal/tests/pageObjects/portal/kurono_teacher_dashboard_page.py +0 -49
  382. portal/tests/pageObjects/portal/student_password_reset_form_page.py +0 -23
  383. portal/tests/pageObjects/portal/teach/onboarding_revoke_request_page.py +0 -20
  384. portal/tests/pageObjects/portal/teacher_password_reset_form_page.py +0 -23
  385. portal/tests/test_aimmo_dashboards.py +0 -172
  386. portal/tests/test_location.py +0 -217
  387. portal/tests/utils/aimmo_games.py +0 -30
  388. portal/views/aimmo/dashboard.py +0 -119
  389. portal/views/privacy_policy.py +0 -9
  390. portal/views/teacher/teacher_resources.py +0 -42
  391. {portal/views/aimmo → cfl_common}/__init__.py +0 -0
@@ -1,8 +1,8 @@
1
1
  from __future__ import absolute_import
2
2
 
3
- from builtins import range
3
+ import time
4
4
 
5
- from common.tests.utils import email as email_utils
5
+ from common.models import Teacher
6
6
  from common.tests.utils.classes import create_class_directly
7
7
  from common.tests.utils.organisation import (
8
8
  create_organisation,
@@ -10,11 +10,12 @@ from common.tests.utils.organisation import (
10
10
  join_teacher_to_organisation,
11
11
  )
12
12
  from common.tests.utils.student import create_school_student_directly
13
- from common.tests.utils.teacher import generate_details, signup_teacher_directly
14
- from django.core import mail
13
+ from common.tests.utils.teacher import signup_teacher_directly
14
+ from selenium.webdriver.common.by import By
15
15
 
16
16
  from portal.tests.pageObjects.portal.base_page import BasePage
17
17
  from portal.tests.pageObjects.portal.home_page import HomePage
18
+ from portal.tests.test_invite_teacher import FADE_TIME
18
19
  from .base_test import BaseTest
19
20
  from .utils.messages import is_organisation_created_message_showing
20
21
 
@@ -24,202 +25,64 @@ class TestOrganisation(BaseTest, BasePage):
24
25
  email, password = signup_teacher_directly()
25
26
 
26
27
  self.selenium.get(self.live_server_url)
27
- page = (
28
- HomePage(self.selenium)
29
- .go_to_teacher_login_page()
30
- .login_no_school(email, password)
31
- )
32
-
33
- page, name, postcode = create_organisation(page, password)
34
- assert is_organisation_created_message_showing(self.selenium, name)
35
-
36
- def test_join_empty(self):
37
- email, password = signup_teacher_directly()
38
-
39
- self.selenium.get(self.live_server_url)
40
- page = (
41
- HomePage(self.selenium)
42
- .go_to_teacher_login_page()
43
- .login_no_school(email, password)
44
- .join_empty_organisation()
45
- )
46
-
47
- assert page.__class__.__name__ == "OnboardingOrganisationPage"
48
-
49
- def test_create_clash(self):
50
- email_1, _ = signup_teacher_directly()
51
- email_2, password_2 = signup_teacher_directly()
52
- name, postcode = create_organisation_directly(email_1)
53
-
54
- self.selenium.get(self.live_server_url)
55
- page = (
56
- HomePage(self.selenium)
57
- .go_to_teacher_login_page()
58
- .login_no_school(email_2, password_2)
59
- .create_organisation_failure(name, password_2, postcode)
60
- )
28
+ page = HomePage(self.selenium).go_to_teacher_login_page().login_no_school(email, password)
61
29
 
62
- assert page.has_creation_failed()
30
+ school_name = "My School"
31
+ page.create_organisation(school_name)
32
+ assert is_organisation_created_message_showing(self.selenium, school_name)
63
33
 
64
- def test_create_invalid_postcode(self):
34
+ def test_create_invalid_name(self):
65
35
  email, password = signup_teacher_directly()
66
36
 
67
37
  self.selenium.get(self.live_server_url)
68
- page = (
69
- HomePage(self.selenium)
70
- .go_to_teacher_login_page()
71
- .login_no_school(email, password)
72
- )
73
-
74
- page = page.create_organisation_failure("School", password, " ")
75
- assert page.was_postcode_invalid()
76
-
77
- def test_revoke(self):
78
- email_1, _ = signup_teacher_directly()
79
- email_2, password_2 = signup_teacher_directly()
80
- name, postcode = create_organisation_directly(email_1)
81
-
82
- self.selenium.get(self.live_server_url)
83
- page = (
84
- HomePage(self.selenium)
85
- .go_to_teacher_login_page()
86
- .login_no_school(email_2, password_2)
87
- )
88
- page = page.join_organisation(name)
89
- assert page.__class__.__name__ == "OnboardingRevokeRequestPage"
90
- assert page.check_organisation_name(name, postcode)
91
-
92
- page = page.revoke_join()
93
- assert page.__class__.__name__ == "OnboardingOrganisationPage"
94
-
95
- def test_allow_join(self):
96
- email_1, password_1 = signup_teacher_directly()
97
- email_2, password_2 = signup_teacher_directly()
98
- name, postcode = create_organisation_directly(email_1)
99
- _, class_name, access_code = create_class_directly(email_1)
100
- create_school_student_directly(access_code)
101
-
102
- self.selenium.get(self.live_server_url)
103
- page = (
104
- HomePage(self.selenium)
105
- .go_to_teacher_login_page()
106
- .login_no_school(email_2, password_2)
107
- .join_organisation(name)
108
- )
109
-
110
- assert page.__class__.__name__ == "OnboardingRevokeRequestPage"
111
-
112
- page = page.logout().go_to_teacher_login_page().login(email_1, password_1)
113
-
114
- assert page.has_join_request(email_2)
115
- page = page.accept_join_request()
116
-
117
- assert not page.has_join_request(email_2)
118
-
119
- page = (
120
- page.logout().go_to_teacher_login_page().login_no_class(email_2, password_2)
121
- )
122
-
123
- assert page.__class__.__name__ == "OnboardingClassesPage"
124
-
125
- def test_deny_join(self):
126
- email_1, password_1 = signup_teacher_directly()
127
- email_2, password_2 = signup_teacher_directly()
128
- name, _ = create_organisation_directly(email_1)
129
- _, _, access_code = create_class_directly(email_1)
130
- create_school_student_directly(access_code)
131
-
132
- self.selenium.get(self.live_server_url)
133
- page = (
134
- HomePage(self.selenium)
135
- .go_to_teacher_login_page()
136
- .login_no_school(email_2, password_2)
137
- .join_organisation(name)
138
- )
139
-
140
- assert page.__class__.__name__ == "OnboardingRevokeRequestPage"
38
+ page = HomePage(self.selenium).go_to_teacher_login_page().login_no_school(email, password)
141
39
 
142
- page = page.logout().go_to_teacher_login_page().login(email_1, password_1)
143
-
144
- assert page.has_join_request(email_2)
145
- page = page.deny_join_request()
146
-
147
- assert not page.has_join_request(email_2)
148
-
149
- page = (
150
- page.logout()
151
- .go_to_teacher_login_page()
152
- .login_no_school(email_2, password_2)
40
+ invalid_school_name = "<a>My School</a"
41
+ page.create_organisation_failure(invalid_school_name)
42
+ assert page.was_form_invalid(
43
+ "form-create-organisation",
44
+ "School names cannot contain special characters except full stops and apostrophes.",
153
45
  )
154
46
 
155
- assert page.__class__.__name__ == "OnboardingOrganisationPage"
156
-
157
47
  def test_kick(self):
158
48
  email_1, password_1 = signup_teacher_directly()
159
- name, _ = create_organisation_directly(email_1)
49
+ email_2, password_2 = signup_teacher_directly()
50
+ school = create_organisation_directly(email_1)
160
51
  _, _, access_code = create_class_directly(email_1)
161
52
  create_school_student_directly(access_code)
162
53
 
163
- first_name, _, email_2, password_2 = generate_details()
164
-
165
- new_last_name = "New Teacher"
54
+ join_teacher_to_organisation(email_2, school.name)
166
55
 
167
56
  self.selenium.get(self.live_server_url)
168
- page = (
169
- HomePage(self.selenium)
170
- .go_to_signup_page()
171
- .signup(first_name, new_last_name, email_2, password_2, password_2)
172
- )
173
-
174
- page = email_utils.follow_verify_email_link_to_onboarding(page, mail.outbox[0])
175
- mail.outbox = []
176
-
177
- page = page.login_no_school(email_2, password_2).join_organisation(name)
178
-
179
- assert page.__class__.__name__ == "OnboardingRevokeRequestPage"
180
-
181
- page = page.logout().go_to_teacher_login_page().login(email_1, password_1)
57
+ page = HomePage(self.selenium).go_to_teacher_login_page().login(email_1, password_1)
182
58
 
183
- page = page.accept_join_request()
59
+ teacher2 = Teacher.objects.get(new_user__email=email_2)
184
60
 
185
- assert page.is_teacher_in_school(new_last_name)
61
+ assert page.is_teacher_in_school(teacher2.new_user.last_name)
186
62
 
187
63
  page = page.click_kick_button()
188
64
  assert page.is_dialog_showing()
189
65
  page = page.confirm_dialog()
190
66
 
191
- assert page.is_not_teacher_in_school(new_last_name)
67
+ assert page.is_not_teacher_in_school(teacher2.new_user.last_name)
192
68
 
193
69
  def test_move_classes_and_kick(self):
194
70
  email_1, password_1 = signup_teacher_directly()
195
- name, _ = create_organisation_directly(email_1)
71
+ email_2, password_2 = signup_teacher_directly()
72
+ school = create_organisation_directly(email_1)
196
73
  _, _, access_code_1 = create_class_directly(email_1)
197
74
  create_school_student_directly(access_code_1)
75
+ _, _, access_code_2 = create_class_directly(email_2)
76
+ create_school_student_directly(access_code_2)
198
77
 
199
- first_name, _, email_2, password_2 = generate_details()
200
-
201
- new_last_name = "New Teacher"
78
+ join_teacher_to_organisation(email_2, school.name)
202
79
 
203
80
  self.selenium.get(self.live_server_url)
204
- page = (
205
- HomePage(self.selenium)
206
- .go_to_signup_page()
207
- .signup(first_name, new_last_name, email_2, password_2, password_2)
208
- )
209
-
210
- page = email_utils.follow_verify_email_link_to_onboarding(page, mail.outbox[0])
211
- mail.outbox = []
212
-
213
- page = page.login_no_school(email_2, password_2).join_organisation(name)
81
+ page = HomePage(self.selenium).go_to_teacher_login_page().login(email_1, password_1)
214
82
 
215
- page = page.logout().go_to_teacher_login_page().login(email_1, password_1)
216
-
217
- page = page.accept_join_request()
83
+ teacher2 = Teacher.objects.get(new_user__email=email_2)
218
84
 
219
- assert page.is_teacher_in_school(new_last_name)
220
-
221
- _, _, access_code_2 = create_class_directly(email_2)
222
- create_school_student_directly(access_code_2)
85
+ assert page.is_teacher_in_school(teacher2.new_user.last_name)
223
86
 
224
87
  page = page.click_kick_button()
225
88
  assert page.is_dialog_showing()
@@ -229,40 +92,21 @@ class TestOrganisation(BaseTest, BasePage):
229
92
 
230
93
  page = page.move_and_kick()
231
94
 
232
- assert page.is_not_teacher_in_school(new_last_name)
95
+ assert page.is_not_teacher_in_school(teacher2.new_user.last_name)
233
96
 
234
97
  def test_leave_organisation(self):
235
98
  email_1, password_1 = signup_teacher_directly()
236
- name, _ = create_organisation_directly(email_1)
99
+ email_2, password_2 = signup_teacher_directly()
100
+ school = create_organisation_directly(email_1)
237
101
  _, _, access_code_1 = create_class_directly(email_1)
238
102
  create_school_student_directly(access_code_1)
239
-
240
- first_name, _, email_2, password_2 = generate_details()
241
-
242
- new_last_name = "New Teacher"
243
-
244
- self.selenium.get(self.live_server_url)
245
- page = (
246
- HomePage(self.selenium)
247
- .go_to_signup_page()
248
- .signup(first_name, new_last_name, email_2, password_2, password_2)
249
- )
250
-
251
- page = email_utils.follow_verify_email_link_to_onboarding(page, mail.outbox[0])
252
- mail.outbox = []
253
-
254
- page = page.login_no_school(email_2, password_2).join_organisation(name)
255
-
256
- page = page.logout().go_to_teacher_login_page().login(email_1, password_1)
257
-
258
- page = page.accept_join_request()
259
-
260
- assert page.is_teacher_in_school(new_last_name)
261
-
262
103
  _, class_name_2, access_code_2 = create_class_directly(email_2)
263
104
  create_school_student_directly(access_code_2)
264
105
 
265
- page = page.logout().go_to_teacher_login_page().login(email_2, password_2)
106
+ join_teacher_to_organisation(email_2, school.name)
107
+
108
+ self.selenium.get(self.live_server_url)
109
+ page = HomePage(self.selenium).go_to_teacher_login_page().login(email_2, password_2)
266
110
 
267
111
  page = page.leave_organisation_with_students()
268
112
 
@@ -274,28 +118,28 @@ class TestOrganisation(BaseTest, BasePage):
274
118
 
275
119
  page = page.logout().go_to_teacher_login_page().login(email_1, password_1)
276
120
 
277
- assert page.is_not_teacher_in_school(new_last_name)
121
+ teacher2 = Teacher.objects.get(new_user__email=email_2)
122
+
123
+ assert page.is_not_teacher_in_school(teacher2.new_user.last_name)
278
124
 
279
125
  def test_toggle_admin(self):
280
126
  email_1, password_1 = signup_teacher_directly()
281
127
  email_2, _ = signup_teacher_directly()
282
- name, postcode = create_organisation_directly(email_1)
128
+ school = create_organisation_directly(email_1)
283
129
  _, _, access_code = create_class_directly(email_1)
284
130
  create_school_student_directly(access_code)
285
- join_teacher_to_organisation(email_2, name, postcode)
131
+ join_teacher_to_organisation(email_2, school.name)
286
132
 
287
133
  self.selenium.get(self.live_server_url)
288
- page = (
289
- HomePage(self.selenium)
290
- .go_to_teacher_login_page()
291
- .login(email_1, password_1)
292
- )
134
+ page = HomePage(self.selenium).go_to_teacher_login_page().login(email_1, password_1)
293
135
 
294
136
  assert page.__class__.__name__ == "TeachDashboardPage"
295
137
 
296
138
  page = page.click_make_admin_button()
297
- assert page.is_dialog_showing()
298
- page = page.confirm_dialog()
139
+ time.sleep(FADE_TIME)
140
+ popup_make_admin_button = page.browser.find_element(By.ID, "add_admin_button")
141
+ assert popup_make_admin_button.text == "Add as admin"
142
+ popup_make_admin_button.click()
299
143
 
300
144
  assert page.is_teacher_admin()
301
145
 
@@ -306,23 +150,22 @@ class TestOrganisation(BaseTest, BasePage):
306
150
  def test_disable_2FA(self):
307
151
  email_1, password_1 = signup_teacher_directly()
308
152
  email_2, _ = signup_teacher_directly()
309
- name, postcode = create_organisation_directly(email_1)
153
+ school = create_organisation_directly(email_1)
310
154
  _, _, access_code = create_class_directly(email_1)
311
155
  create_school_student_directly(access_code)
312
- join_teacher_to_organisation(email_2, name, postcode)
156
+ join_teacher_to_organisation(email_2, school.name)
313
157
 
314
158
  self.selenium.get(self.live_server_url)
315
- page = (
316
- HomePage(self.selenium)
317
- .go_to_teacher_login_page()
318
- .login(email_1, password_1)
319
- )
159
+ page = HomePage(self.selenium).go_to_teacher_login_page().login(email_1, password_1)
320
160
 
321
161
  assert page.__class__.__name__ == "TeachDashboardPage"
322
162
 
323
163
  page = page.click_make_admin_button()
324
- assert page.is_dialog_showing()
325
- page = page.confirm_dialog()
164
+ # check if the new popup appears
165
+ time.sleep(FADE_TIME)
166
+ make_admin_button = page.browser.find_element(By.ID, "add_admin_button")
167
+ assert make_admin_button.text == "Add as admin"
168
+ make_admin_button.click()
326
169
 
327
170
  assert page.is_teacher_admin()
328
171
 
@@ -330,64 +173,45 @@ class TestOrganisation(BaseTest, BasePage):
330
173
 
331
174
  assert page.is_teacher_non_admin()
332
175
 
333
- def test_multiple_schools(self):
334
- # There was a bug where join requests to school 35 say would go to school 3,
335
- # 62 would go to 6, etc... this test checks for that
336
-
337
- n = 12
338
-
339
- emails, passwords, names, postcodes = self.initialise_data(n)
340
-
341
- for i in range(n):
342
- emails[i], passwords[i] = signup_teacher_directly()
343
- names[i], postcodes[i] = create_organisation_directly(emails[i])
344
-
176
+ def test_edit_details(self):
345
177
  email, password = signup_teacher_directly()
178
+ school = create_organisation_directly(email)
179
+ _, _, access_code = create_class_directly(email)
180
+ create_school_student_directly(access_code)
346
181
 
347
182
  self.selenium.get(self.live_server_url)
348
- page = (
349
- HomePage(self.selenium)
350
- .go_to_teacher_login_page()
351
- .login_no_school(email, password)
352
- )
183
+ page = HomePage(self.selenium).go_to_teacher_login_page().login(email, password)
353
184
 
354
- page = page.join_organisation(names[n - 1])
355
- assert page.__class__.__name__ == "OnboardingRevokeRequestPage"
356
- assert page.check_organisation_name(names[n - 1], postcodes[n - 1])
185
+ assert page.check_organisation_details({"name": school.name})
357
186
 
358
- def initialise_data(self, n):
359
- emails = ["" for i in range(n)]
360
- passwords = ["" for i in range(n)]
361
- names = ["" for i in range(n)]
362
- postcodes = ["" for i in range(n)]
187
+ new_name = f"new {school.name}"
363
188
 
364
- return emails, passwords, names, postcodes
189
+ page.change_organisation_details({"name": new_name})
190
+ assert page.check_organisation_details({"name": new_name})
365
191
 
366
- def test_edit_details(self):
192
+ def test_edit_details_invalid_name(self):
367
193
  email, password = signup_teacher_directly()
368
- school_name, postcode = create_organisation_directly(email)
194
+ school = create_organisation_directly(email)
369
195
  _, _, access_code = create_class_directly(email)
370
196
  create_school_student_directly(access_code)
371
197
 
372
198
  self.selenium.get(self.live_server_url)
373
199
  page = HomePage(self.selenium).go_to_teacher_login_page().login(email, password)
374
200
 
375
- assert page.check_organisation_details(
376
- {"name": school_name, "postcode": postcode}
377
- )
201
+ assert page.check_organisation_details({"name": school.name})
202
+
203
+ new_name = f"<a>{school.name}</a>"
378
204
 
379
- new_name = "new " + school_name
380
- new_postcode = "OX2 6LE"
205
+ page.change_organisation_details({"name": new_name})
381
206
 
382
- page.change_organisation_details({"name": new_name, "postcode": new_postcode})
383
- assert page.check_organisation_details(
384
- {"name": new_name, "postcode": new_postcode}
207
+ assert page.was_form_invalid(
208
+ "edit_form", "School names cannot contain special characters except full stops and apostrophes."
385
209
  )
386
210
 
387
211
  def test_edit_clash(self):
388
212
  email_1, _ = signup_teacher_directly()
389
213
  email_2, password_2 = signup_teacher_directly()
390
- school_name_1, postcode_1 = create_organisation_directly(email_1)
214
+ school1 = create_organisation_directly(email_1)
391
215
  create_organisation_directly(email_2)
392
216
  _, _, access_code_1 = create_class_directly(email_1)
393
217
  _, _, access_code_2 = create_class_directly(email_2)
@@ -395,18 +219,10 @@ class TestOrganisation(BaseTest, BasePage):
395
219
  create_school_student_directly(access_code_2)
396
220
 
397
221
  self.selenium.get(self.live_server_url)
398
- page = (
399
- HomePage(self.selenium)
400
- .go_to_teacher_login_page()
401
- .login(email_2, password_2)
402
- )
222
+ page = HomePage(self.selenium).go_to_teacher_login_page().login(email_2, password_2)
403
223
 
404
- assert not page.check_organisation_details(
405
- {"name": school_name_1, "postcode": postcode_1}
406
- )
224
+ assert not page.check_organisation_details({"name": school1.name})
407
225
 
408
- page = page.change_organisation_details(
409
- {"name": school_name_1, "postcode": postcode_1}
410
- )
226
+ page = page.change_organisation_details({"name": school1.name})
411
227
 
412
- assert page.has_edit_failed()
228
+ assert page.was_form_invalid("edit_form", "There is already a school or club registered with that name")
@@ -1,4 +1,3 @@
1
- import pytest
2
1
  from django.template import Context, Template
3
2
 
4
3
 
@@ -61,90 +60,3 @@ def test_benefits(snapshot):
61
60
  rendered_template = template_to_render.render(context)
62
61
 
63
62
  snapshot.assert_match(rendered_template)
64
-
65
-
66
- def test_hero_card(snapshot):
67
- test_hero_card = {
68
- "image": "images/worksheets/future_active.png",
69
- "title": "Test title",
70
- "description": "Test description",
71
- "button1": {
72
- "text": "Test button 1",
73
- "url": "https://www.codeforlife.education",
74
- },
75
- "button2": {"text": "Test button 2", "url": "kurono/play", "url_args": 1},
76
- }
77
-
78
- context = Context({"HERO_CARD": test_hero_card})
79
-
80
- template_to_render = Template(
81
- "{% load hero_card_tags %}" "{% hero_card hero_card_name='HERO_CARD' %}"
82
- )
83
-
84
- rendered_template = template_to_render.render(context)
85
-
86
- snapshot.assert_match(rendered_template)
87
-
88
-
89
- def test_card_list(snapshot):
90
- test_card_list = {
91
- "cards": [
92
- {
93
- "image": "images/worksheets/future2.jpg",
94
- "title": "Test card 1",
95
- "description": "Test description 1",
96
- "thumbnail_image": "images/worksheets/lock.png",
97
- },
98
- {
99
- "image": "images/worksheets/ancient.jpg",
100
- "title": "Test card 2",
101
- "description": "Test description 2",
102
- "thumbnail_text": "Coming Soon",
103
- },
104
- {
105
- "image": "images/worksheets/modern_day.jpg",
106
- "title": "Test card 3",
107
- "description": "Test description 3",
108
- "thumbnail_text": "Coming Soon",
109
- },
110
- {
111
- "image": "images/worksheets/prehistory.jpg",
112
- "title": "Test card 4",
113
- "description": "Test description 4",
114
- "thumbnail_text": "Coming Soon",
115
- },
116
- {
117
- "image": "images/worksheets/broken_future.jpg",
118
- "title": "Test card 5",
119
- "description": "Test description 5",
120
- "thumbnail_text": "Coming Soon",
121
- },
122
- {
123
- "image": "images/worksheets/kurono_logo.svg",
124
- "title": "Test card 6",
125
- "button_text": "Test button",
126
- "button_link": "home",
127
- },
128
- ]
129
- }
130
-
131
- context = Context({"CARD_LIST": test_card_list})
132
-
133
- template_to_render = Template("{% load card_list_tags %}" "{% card_list %}")
134
-
135
- rendered_template = template_to_render.render(context)
136
-
137
- snapshot.assert_match(rendered_template)
138
-
139
-
140
- @pytest.mark.django_db
141
- def test_character_list(snapshot):
142
- context = Context()
143
-
144
- template_to_render = Template(
145
- "{% load character_list_tags %}" "{% character_list %}"
146
- )
147
-
148
- rendered_template = template_to_render.render(context)
149
-
150
- snapshot.assert_match(rendered_template)