def test_view_topic_page_contains_reordering_javascript_for_admin_user_only( test_app_client): rdu_user = UserFactory(user_type=TypeOfUser.RDU_USER) admin_user = UserFactory(user_type=TypeOfUser.ADMIN_USER) topic = TopicFactory(title="Test topic page") with test_app_client.session_transaction() as session: session["user_id"] = admin_user.id resp = test_app_client.get( url_for("static_site.topic", topic_slug=topic.slug)) assert resp.status_code == 200 page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert page.h1.text.strip() == "Test topic page" assert len( page.find_all("script", text=re.compile("setupReorderableTables"))) == 1 with test_app_client.session_transaction() as session: session["user_id"] = rdu_user.id resp = test_app_client.get( url_for("static_site.topic", topic_slug=topic.slug)) assert resp.status_code == 200 page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert page.h1.text.strip() == "Test topic page" assert len( page.find_all("script", text=re.compile("setupReorderableTables"))) == 0
def test_admin_user_can_grant_or_remove_rdu_user_admin_rights(test_app_client, logged_in_admin_user): rdu_user = UserFactory(user_type=TypeOfUser.RDU_USER) assert not rdu_user.is_admin_user() resp = test_app_client.get(url_for("admin.make_admin_user", user_id=rdu_user.id), follow_redirects=True) assert resp.status_code == 200 page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert ( page.find("div", class_="eff-flash-message__body").get_text(strip=True) == "User %s is now an admin user" % rdu_user.email ) assert rdu_user.is_admin_user() resp = test_app_client.get(url_for("admin.make_rdu_user", user_id=rdu_user.id), follow_redirects=True) assert resp.status_code == 200 page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert ( page.find("div", class_="eff-flash-message__body").get_text(strip=True) == "User %s is now a standard RDU user" % rdu_user.email ) assert rdu_user.is_rdu_user()
def test_admin_user_cannot_grant_departmental_user_admin_rights(test_app_client, logged_in_admin_user): dept_user = UserFactory(user_type=TypeOfUser.DEPT_USER) assert not dept_user.is_admin_user() resp = test_app_client.get(url_for("admin.make_admin_user", user_id=dept_user.id), follow_redirects=True) assert resp.status_code == 200 page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert page.find("div", class_="eff-flash-message__body").get_text(strip=True) == "Only RDU users can be made admin" assert not dept_user.is_admin_user()
def test_create_new_version_of_page_duplicates_dimension_categorisations( self): user = UserFactory(user_type=TypeOfUser.RDU_USER) # given an existing page with a dimension with known classification measure_version = MeasureVersionWithDimensionFactory( dimensions__classification_links__classification__id= "my-classification", dimensions__classification_links__includes_parents=False, dimensions__classification_links__includes_all=True, dimensions__classification_links__includes_unknown=True, ) assert measure_version.dimensions[0].classification_links.count() > 0 # when we copy the page new_version = page_service.create_measure_version( measure_version, NewVersionType.MINOR_UPDATE, user=user) # then assert new_version.dimensions.count() > 0 assert new_version.dimensions[0].classification_links.count() > 0 new_link = new_version.dimensions[0].classification_links[0] assert new_link.dimension_guid == new_version.dimensions[0].guid assert new_link.classification_id == "my-classification" assert new_link.includes_parents is False assert new_link.includes_all is True assert new_link.includes_unknown is True
def test_create_new_version_of_page(self): measure_version = MeasureVersionFactory(latest=True) user = UserFactory(user_type=TypeOfUser.RDU_USER) assert measure_version.latest is True new_version = page_service.create_measure_version( measure_version, NewVersionType.MINOR_UPDATE, user=user) assert new_version.version == "1.1" assert new_version.status == "DRAFT" assert new_version.internal_edit_summary is None assert new_version.external_edit_summary is None assert new_version.published_at is None assert user.email == new_version.created_by assert new_version.latest is True assert new_version.get_previous_version().latest is False next_version = page_service.create_measure_version( measure_version, NewVersionType.MAJOR_UPDATE, user=user) assert next_version.get_previous_version().latest is False assert next_version.version == "2.0" assert next_version.status == "DRAFT" assert next_version.internal_edit_summary is None assert next_version.external_edit_summary is None assert next_version.published_at is None assert user.email == new_version.created_by assert next_version.latest is True
def test_first_version_of_page_title_and_url_match(self): subtopic = SubtopicFactory() user = UserFactory(user_type=TypeOfUser.RDU_USER) created_measure_version = page_service.create_measure( subtopic=subtopic, measure_version_form=MeasureVersionForm( is_minor_update=False, title="the title", published_at=datetime.now().date()), created_by_email=user.email, ) assert "the title" == created_measure_version.title assert "the-title" == created_measure_version.measure.slug updated_measure_version = page_service.update_measure_version( created_measure_version, measure_version_form=MeasureVersionForm( is_minor_update=True, title="an updated title", db_version_id=created_measure_version.db_version_id), data_source_forms=[], last_updated_by_email=user.email, ) assert "an updated title" == updated_measure_version.title assert "an-updated-title" == updated_measure_version.measure.slug
def test_update_measure_version_raises_if_page_not_editable(self): user = UserFactory(user_type=TypeOfUser.RDU_USER) measure_version = MeasureVersionFactory(version="1.0", status="DRAFT") measure_version_from_db = page_service.get_measure_version_by_measure_id_and_version( measure_version.measure.id, measure_version.version) assert measure_version_from_db.status == "DRAFT" page_service.update_measure_version( measure_version, measure_version_form=MeasureVersionForm( is_minor_update=True, title="Who cares", db_version_id=measure_version.db_version_id), data_source_forms=[], last_updated_by_email=user.email, **{"status": "APPROVED"}, ) measure_version_from_db = page_service.get_measure_version_by_measure_id_and_version( measure_version.measure.id, measure_version.version) assert measure_version_from_db.status == "APPROVED" with pytest.raises(PageUnEditable): page_service.update_measure_version( measure_version, measure_version_form=MeasureVersionForm( is_minor_update=True, title="I care too much!", db_version_id=measure_version.db_version_id), data_source_forms=[], last_updated_by_email=user.email, )
def test_script_creates_one_new_measure_version_and_updates_dimension_titles_for_two_dimensions( self, single_use_app, db_session ): user = UserFactory(user_type=TypeOfUser.ADMIN_USER, email="*****@*****.**") mv = MeasureVersionFactory.build( status="APPROVED", version="1.0", title="my measure", measure__id=1, uploads=[] ) mv.dimensions = [ DimensionFactory.build(guid="dimension-guid-1", title="my dimension 1"), DimensionFactory.build(guid="dimension-guid-2", title="my dimension 2"), ] db_session.session.add(mv) db_session.session.commit() dimension_rows = [ ["dimension-guid-1", "my measure", "my dimension 1", "my new dimension 1"], ["dimension-guid-2", "my measure", "my dimension 2", "my new dimension 2"], ] import_dimension_titles(user_email=user.email, app=single_use_app, dimension_rows=dimension_rows) measure = Measure.query.get(1) assert len(measure.versions) == 2 assert measure.versions[0].version == "1.1" assert measure.versions[0].status == "APPROVED" assert measure.versions[0].dimensions[0].title == "my new dimension 1" assert measure.versions[0].dimensions[1].title == "my new dimension 2" assert measure.versions[0].external_edit_summary == STANDARD_EDIT_SUMMARY assert measure.versions[1].version == "1.0" assert measure.versions[1].dimensions[0].title == "my dimension 1" assert measure.versions[1].dimensions[1].title == "my dimension 2"
def test_new_measure_version_not_created_if_any_new_dimension_titles_are_blank(self, single_use_app, db_session): user = UserFactory(user_type=TypeOfUser.ADMIN_USER, email="*****@*****.**") mv = MeasureVersionFactory.build( status="APPROVED", version="1.0", title="my measure", measure__id=1, uploads=[] ) mv.dimensions = [ DimensionFactory.build(guid="dimension-guid-1", title="my dimension 1"), DimensionFactory.build(guid="dimension-guid-2", title="my dimension 2"), ] db_session.session.add(mv) db_session.session.commit() dimension_rows = [ ["dimension-guid-1", "my measure", "my dimension 1", ""], ["dimension-guid-2", "my measure", "my dimension 2", "my new dimension 2"], ] error_count = import_dimension_titles(user_email=user.email, app=single_use_app, dimension_rows=dimension_rows) measure = Measure.query.get(1) assert error_count == 0 assert len(measure.versions) == 1 assert measure.versions[0].version == "1.0" assert measure.versions[0].dimensions[0].title == "my dimension 1" assert measure.versions[0].dimensions[1].title == "my dimension 2"
def test_script_creates_new_measure_version_and_updates_dimension_title(self, single_use_app): user = UserFactory(user_type=TypeOfUser.ADMIN_USER, email="*****@*****.**") MeasureVersionWithDimensionFactory( status="APPROVED", version="1.0", title="my measure", measure__id=1, dimensions__guid="dimension-guid", dimensions__title="my dimension", uploads=[], ) dimension_rows = [["dimension-guid", "my measure", "my dimension", "my new dimension"]] import_dimension_titles(user_email=user.email, app=single_use_app, dimension_rows=dimension_rows) measure = Measure.query.get(1) assert len(measure.versions) == 2 assert measure.versions[0].version == "1.1" assert measure.versions[0].status == "APPROVED" assert measure.versions[0].dimensions[0].title == "my new dimension" assert measure.versions[0].external_edit_summary == STANDARD_EDIT_SUMMARY assert measure.versions[0].created_by == "*****@*****.**" assert ( datetime.utcnow() - measure.versions[0].created_at ).seconds < 5, "Creation time should be within the last 5 seconds" assert measure.versions[0].update_corrects_data_mistake is False assert measure.versions[0].published_by == "*****@*****.**" assert measure.versions[0].published_at is None assert measure.versions[0].last_updated_by == "*****@*****.**" assert measure.versions[1].version == "1.0" assert measure.versions[1].dimensions[0].title == "my dimension"
def test_only_allowed_users_can_see_copy_measure_button_on_edit_page( test_app_client, user_type, can_see_copy_button): user = UserFactory(user_type=user_type) measure_version = MeasureVersionFactory() with test_app_client.session_transaction() as session: session["user_id"] = user.id response = test_app_client.get( url_for( "cms.edit_measure_version", topic_slug=measure_version.measure.subtopic.topic.slug, subtopic_slug=measure_version.measure.subtopic.slug, measure_slug=measure_version.measure.slug, version=measure_version.version, ), follow_redirects=True, ) page = BeautifulSoup(response.data.decode("utf-8"), "html.parser") page_button_texts = [ button.text.strip().lower() for button in page.find_all("button") ] assert ("create a copy of this measure" in page_button_texts) is can_see_copy_button
def test_create_copy_of_page(self): user = UserFactory(user_type=TypeOfUser.RDU_USER) measure_version = MeasureVersionFactory(latest=True, measure__slug="slug") assert measure_version.latest first_copy = page_service.create_measure_version( measure_version, NewVersionType.NEW_MEASURE, user=user) first_copy_measure_id = first_copy.measure_id first_copy_title = first_copy.title first_copy_slug = first_copy.measure.slug assert first_copy.version == "1.0" assert first_copy.status == "DRAFT" assert first_copy.internal_edit_summary is None assert first_copy.external_edit_summary is None assert first_copy.published_at is None assert first_copy.created_by == user.email assert first_copy.latest second_copy = page_service.create_measure_version( first_copy, NewVersionType.NEW_MEASURE, user=user) assert second_copy.version == "1.0" assert second_copy.status == "DRAFT" assert second_copy.internal_edit_summary is None assert second_copy.external_edit_summary is None assert second_copy.published_at is None assert user.email == first_copy.created_by assert second_copy.latest assert first_copy_measure_id != second_copy.measure_id assert second_copy.title == f"COPY OF {first_copy_title}" assert second_copy.measure.slug == f"{first_copy_slug}-copy"
def test_login_with_bad_credentials_shows_errors(test_app_client): rdu_user = UserFactory(user_type=TypeOfUser.RDU_USER, password="******", active=True) # Wrong username response = test_app_client.post( url_for("security.login"), data={ "email": "*****@*****.**", "password": rdu_user.password }, follow_redirects=True, ) assert response.status_code == 200 assert page_displays_error_matching_message(response, "Check your email address") assert page_displays_error_matching_message(response, "Check your password") # Wrong password response = test_app_client.post(url_for("security.login"), data={ "email": rdu_user.email, "password": "******" }, follow_redirects=True) assert response.status_code == 200 assert page_displays_error_matching_message(response, "Check your email address") assert page_displays_error_matching_message(response, "Check your password")
def test_admin_user_can_remove_share_of_page_with_dept_user(test_app_client): dept_user = UserFactory(user_type=TypeOfUser.DEPT_USER) admin_user = UserFactory(user_type=TypeOfUser.ADMIN_USER) measure_version = MeasureVersionFactory(status="DRAFT", measure__shared_with=[dept_user]) with test_app_client.session_transaction() as session: session["user_id"] = dept_user.id resp = test_app_client.get( url_for( "static_site.measure_version", topic_slug=measure_version.measure.subtopic.topic.slug, subtopic_slug=measure_version.measure.subtopic.slug, measure_slug=measure_version.measure.slug, version=measure_version.version, ) ) assert resp.status_code == 200 # admin user removes share with test_app_client.session_transaction() as session: session["user_id"] = admin_user.id resp = test_app_client.get( url_for("admin.remove_shared_page_from_user", measure_id=measure_version.measure_id, user_id=dept_user.id), follow_redirects=True, ) assert resp.status_code == 200 # dept user can no longer access page with test_app_client.session_transaction() as session: session["user_id"] = dept_user.id resp = test_app_client.get( url_for( "static_site.measure_version", topic_slug=measure_version.measure.subtopic.topic.slug, subtopic_slug=measure_version.measure.subtopic.slug, measure_slug=measure_version.measure.slug, version=measure_version.version, ) ) assert resp.status_code == 403
def test_error_count_return_if_dimension_cannot_be_found(self, single_use_app): user = UserFactory(user_type=TypeOfUser.ADMIN_USER, email="*****@*****.**") MeasureVersionFactory(status="DRAFT", version="1.0", title="my measure", measure__id=1, uploads=[]) dimension_rows = [["dimension-guid", "my measure", "my dimension", "my new dimension"]] error_count = import_dimension_titles(user_email=user.email, app=single_use_app, dimension_rows=dimension_rows) assert error_count == 1
def test_create_new_major_version_does_not_duplicate_uploads(self): user = UserFactory(user_type=TypeOfUser.RDU_USER) measure_version = MeasureVersionFactory(latest=True) new_version = page_service.create_measure_version( measure_version, NewVersionType.MAJOR_UPDATE, user=user) assert len(measure_version.uploads) == 1 assert len(new_version.uploads) == 0
def test_new_measure_version_not_created_if_script_thinks_it_has_already_created_one( self, single_use_app, db_session ): user = UserFactory(user_type=TypeOfUser.ADMIN_USER, email="*****@*****.**") mv = MeasureVersionWithDimensionFactory( status="APPROVED", version="1.0", title="my measure", external_edit_summary=None, measure__id=1, dimensions__guid="dimension-guid-1.0", dimensions__title="my dimension", uploads=[], ) MeasureVersionWithDimensionFactory( status="APPROVED", version="1.1", title="my measure", external_edit_summary=STANDARD_EDIT_SUMMARY, measure=mv.measure, dimensions__guid="dimension-guid-1.1", dimensions__title="my new dimension", uploads=[], ) MeasureVersionWithDimensionFactory( status="DRAFT", version="2.0", title="my measure", external_edit_summary=None, measure=mv.measure, dimensions__guid="dimension-guid-2.0", dimensions__title="my dimension", uploads=[], ) dimension_rows = [["dimension-guid-1.0", "my measure", "my dimension", "my new dimension"]] error_count = import_dimension_titles(user_email=user.email, app=single_use_app, dimension_rows=dimension_rows) measure = Measure.query.get(1) assert error_count == 0 assert len(measure.versions) == 3 assert measure.versions[0].version == "2.0" assert measure.versions[0].status == "DRAFT" assert measure.versions[0].dimensions[0].title == "my dimension" assert measure.versions[0].external_edit_summary is None assert measure.versions[1].version == "1.1" assert measure.versions[1].status == "APPROVED" assert measure.versions[1].dimensions[0].title == "my new dimension" assert measure.versions[1].external_edit_summary == STANDARD_EDIT_SUMMARY assert measure.versions[2].version == "1.0" assert measure.versions[2].dimensions[0].title == "my dimension"
def test_reset_password_accepts_good_password(app, test_app_client): rdu_user = UserFactory(user_type=TypeOfUser.RDU_USER) token = generate_token(rdu_user.email, app) confirmation_url = url_for("auth.reset_password", token=token, _external=True) user_details = {"password": "******", "confirm_password": "******"} resp = test_app_client.post(confirmation_url, data=user_details) page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert page.find("h1").text.strip() == "Password updated"
def test_admin_user_cannot_add_user_if_case_insensitive_email_in_use(test_app_client, logged_in_admin_user): existing_rdu_user = UserFactory(email="*****@*****.**", user_type=TypeOfUser.RDU_USER) user_details = {"email": existing_rdu_user.email.upper(), "user_type": TypeOfUser.RDU_USER.name} resp = test_app_client.post(url_for("admin.add_user"), data=user_details, follow_redirects=True) page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert ( page.find("div", class_="eff-flash-message__body").text.strip() == f"User: {existing_rdu_user.email} is already in the system" )
def test_unhashed_user_password_automatically_hashed_on_login_attempt( test_app_client): user = UserFactory(password="******", active=True) assert user.password == "password123" test_app_client.post(url_for("security.login"), data={ "email": user.email, "password": "******" }, follow_redirects=True) assert user.password != "password123"
def test_admin_user_can_deactivate_user_account(test_app_client, logged_in_admin_user): user = UserFactory(active=True, user_type=TypeOfUser.RDU_USER) assert user.active is True resp = test_app_client.get(url_for("admin.deactivate_user", user_id=user.id), follow_redirects=True) assert resp.status_code == 200 page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert ( page.find("div", class_="eff-flash-message__body").get_text(strip=True) == f"User account for: {user.email} deactivated" ) assert user.active is False
def test_can_build_tables(driver, app, live_server, government_departments, frequencies_of_release): rdu_user = UserFactory(user_type=TypeOfUser.RDU_USER, active=True) measure_version = MeasureVersionFactory(status="APPROVED") table_builder_page = construct_test_table_builder_page(driver, live_server, measure_version, rdu_user) run_simple_table_scenarios(table_builder_page, driver) run_complex_table_by_row_scenario(table_builder_page, driver) run_complex_table_by_column_scenario(table_builder_page, driver) run_save_and_load_scenario(table_builder_page, driver)
def test_measure_versions_in_all_states_are_available_to_share(test_app_client, logged_in_admin_user): dept_user = UserFactory(user_type=TypeOfUser.DEPT_USER) num_measures = len(publish_status.keys()) for status in publish_status.keys(): MeasureVersionFactory(status=status) resp = test_app_client.get(url_for("admin.user_by_id", user_id=dept_user.id), follow_redirects=True) assert resp.status_code == 200 page = BeautifulSoup(resp.data.decode("utf-8"), "html." "parser") select = page.find("select", {"id": "measure-picker"}) # There should be an option for "select a measure", plus one for each actual measure. assert len(select.findAll("option")) == num_measures + 1
def test_successfully_logged_in_user_goes_to_main_page(test_app_client): rdu_user = UserFactory(user_type=TypeOfUser.RDU_USER, password="******", active=True) resp = test_app_client.post(url_for("security.login"), data={ "email": rdu_user.email, "password": rdu_user.password }, follow_redirects=True) assert resp.status_code == 200 page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert page.h1.string.strip() == "Ethnicity facts and figures"
def test_admin_user_can_delete_non_admin_user_account(test_app_client, logged_in_admin_user): user = UserFactory(email="*****@*****.**", active=True, user_type=TypeOfUser.RDU_USER) assert user.active resp = test_app_client.get(url_for("admin.delete_user", user_id=user.id), follow_redirects=True) assert resp.status_code == 200 page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert ( page.find("div", class_="eff-flash-message__body").get_text(strip=True) == "User account for: [email protected] deleted" ) assert User.query.filter_by(email="*****@*****.**").first() is None
def test_create_new_minor_version_duplicates_uploads(self): user = UserFactory(user_type=TypeOfUser.RDU_USER) measure_version = MeasureVersionFactory(latest=True) assert len(measure_version.uploads) == 1 original_upload = measure_version.uploads[0] new_version = page_service.create_measure_version( measure_version, NewVersionType.MINOR_UPDATE, user=user) assert len(new_version.uploads) == 1 new_upload = new_version.uploads[0] assert new_upload.guid != original_upload.guid assert new_upload.file_name == original_upload.file_name assert new_upload.title == original_upload.title assert new_upload.description == original_upload.description
def test_reset_password_rejects_easy_password(app, test_app_client): rdu_user = UserFactory(user_type=TypeOfUser.RDU_USER) token = generate_token(rdu_user.email, app) confirmation_url = url_for("auth.reset_password", token=token, _external=True) user_details = {"password": "******", "confirm_password": "******"} resp = test_app_client.post(confirmation_url, data=user_details) page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert ( page.find("div", class_="eff-flash-message__body").text.strip() == """Your password is too weak. It has to be at least 10 characters long and use a mix of numbers, special characters as well as upper and lowercase letters. Avoid using common patterns and repeated characters.""" )
def test_major_version_update_has_no_linked_data_sourceS(self): data_source_1 = DataSourceFactory() data_source_2 = DataSourceFactory() measure_version = MeasureVersionFactory( version="1.0", data_sources=[data_source_1, data_source_2]) user = UserFactory(user_type=TypeOfUser.RDU_USER) assert len(measure_version.data_sources) == 2 assert DataSource.query.count() == 2 new_version = page_service.create_measure_version( measure_version, NewVersionType.MAJOR_UPDATE, user=user) assert DataSource.query.count() == 2 assert new_version.data_sources == []
def test_topic_page_only_shows_empty_subtopics_if_user_can_create_a_measure( user_type, empty_subtopic_should_be_visible, test_app_client): user = UserFactory(user_type=user_type) SubtopicFactory(title="Test subtopic page", topic__slug="test-topic") with test_app_client.session_transaction() as session: session["user_id"] = user.id resp = test_app_client.get( url_for("static_site.topic", topic_slug="test-topic")) page = BeautifulSoup(resp.data.decode("utf-8"), "html.parser") assert resp.status_code == 200 assert bool(page(string=re.compile( "Test subtopic page"))) is empty_subtopic_should_be_visible
def test_create_page_trims_whitespace(self): subtopic = SubtopicFactory() user = UserFactory(user_type=TypeOfUser.RDU_USER) created_measure_version = page_service.create_measure( subtopic=subtopic, measure_version_form=MeasureVersionForm( is_minor_update=False, title="\n\t I care\n", published_at=datetime.now().date(), methodology="\n\n\n\n\n\n", ), created_by_email=user.email, ) assert created_measure_version.title == "I care" assert created_measure_version.methodology is None