async def test_user_can_change_favorite_state( app: FastAPI, authorized_client: AsyncClient, test_article: Article, test_user: UserInDB, pool: Pool, api_method: str, route_name: str, favorite_state: bool, ) -> None: if not favorite_state: async with pool.acquire() as connection: articles_repo = ArticlesRepository(connection) await articles_repo.add_article_into_favorites( article=test_article, user=test_user) await authorized_client.request( api_method, app.url_path_for(route_name, slug=test_article.slug)) response = await authorized_client.get( app.url_path_for("articles:get-article", slug=test_article.slug)) article = ArticleInResponse(**response.json()) assert article.article.favorited == favorite_state assert article.article.favorites_count == int(favorite_state)
async def test_filtering_with_limit_and_offset(app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, pool: Pool) -> None: async with pool.acquire() as connection: articles_repo = ArticlesRepository(connection) for i in range(5, 10): await articles_repo.create_article( slug=f"slug-{i}", title="tmp", description="tmp", body="tmp", author=test_user, ) full_response = await authorized_client.get( app.url_path_for("articles:list-articles")) full_articles = ListOfArticlesInResponse(**full_response.json()) response = await authorized_client.get( app.url_path_for("articles:list-articles"), params={ "limit": 2, "offset": 3 }) articles_from_response = ListOfArticlesInResponse(**response.json()) assert full_articles.articles[3:] == articles_from_response.articles
async def test_user_can_change_following_for_another_user( app: FastAPI, authorized_client: AsyncClient, pool: Pool, test_user: UserInDB, api_method: str, route_name: str, following: bool, ) -> None: async with pool.acquire() as conn: users_repo = UsersRepository(conn) user = await users_repo.create_user( username="******", email="*****@*****.**", password="******", ) if not following: profiles_repo = ProfilesRepository(conn) await profiles_repo.add_user_into_followers( target_user=user, requested_user=test_user) change_following_response = await authorized_client.request( api_method, app.url_path_for(route_name, username=user.username)) assert change_following_response.status_code == status.HTTP_200_OK response = await authorized_client.get( app.url_path_for("profiles:get-profile", username=user.username)) profile = ProfileInResponse(**response.json()) assert profile.profile.username == user.username assert profile.profile.following == following
async def test_user_can_delete_own_comment(app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: created_comment_response = await authorized_client.post( app.url_path_for("comments:create-comment-for-article", slug=test_article.slug), json={"comment": { "body": "comment" }}, ) created_comment = CommentInResponse(**created_comment_response.json()) await authorized_client.delete( app.url_path_for( "comments:delete-comment-from-article", slug=test_article.slug, comment_id=str(created_comment.comment.id_), )) comments_for_article_response = await authorized_client.get( app.url_path_for("comments:get-comments-for-article", slug=test_article.slug)) comments = ListOfCommentsInResponse(**comments_for_article_response.json()) assert len(comments.comments) == 0
async def test_empty_feed_if_user_has_not_followings( app: FastAPI, authorized_client: AsyncClient, test_article: Article, test_user: UserInDB, pool: Pool, ) -> None: async with pool.acquire() as connection: users_repo = UsersRepository(connection) articles_repo = ArticlesRepository(connection) for i in range(5): user = await users_repo.create_user(username=f"user-{i}", email=f"user-{i}@email.com", password="******") for j in range(5): await articles_repo.create_article( slug=f"slug-{i}-{j}", title="tmp", description="tmp", body="tmp", author=user, tags=[f"tag-{i}-{j}"], ) response = await authorized_client.get( app.url_path_for("articles:get-user-feed-articles")) articles = ListOfArticlesInResponse(**response.json()) assert articles.articles == []
async def test_user_can_not_modify_article_that_is_not_authored_by_him( app: FastAPI, authorized_client: AsyncClient, pool: Pool, api_method: str, route_name: str, ) -> None: async with pool.acquire() as connection: users_repo = UsersRepository(connection) user = await users_repo.create_user(username="******", email="*****@*****.**", password="******") articles_repo = ArticlesRepository(connection) await articles_repo.create_article( slug="test-slug", title="Test Slug", description="Slug for tests", body="Test " * 100, author=user, tags=["tests", "testing", "pytest"], ) response = await authorized_client.request( api_method, app.url_path_for(route_name, slug="test-slug"), json={"article": { "title": "Updated Title" }}, ) assert response.status_code == status.HTTP_403_FORBIDDEN
async def test_user_successful_login( app: FastAPI, client: AsyncClient, test_user: UserInDB ) -> None: login_json = {"user": {"email": "*****@*****.**", "password": "******"}} response = await client.post(app.url_path_for("auth:login"), json=login_json) assert response.status_code == HTTP_200_OK
async def test_unregistered_user_will_receive_profile_without_following( app: FastAPI, client: AsyncClient, test_user: UserInDB) -> None: response = await client.get( app.url_path_for("profiles:get-profile", username=test_user.username)) profile = ProfileInResponse(**response.json()) assert profile.profile.username == test_user.username assert not profile.profile.following
async def test_user_can_not_change_following_state_to_the_same_twice( app: FastAPI, authorized_client: AsyncClient, pool: Pool, test_user: UserInDB, api_method: str, route_name: str, following: bool, ) -> None: async with pool.acquire() as conn: users_repo = UsersRepository(conn) user = await users_repo.create_user( username="******", email="*****@*****.**", password="******", ) if following: profiles_repo = ProfilesRepository(conn) await profiles_repo.add_user_into_followers( target_user=user, requested_user=test_user) response = await authorized_client.request( api_method, app.url_path_for(route_name, username=user.username)) assert response.status_code == status.HTTP_400_BAD_REQUEST
async def test_user_can_retrieve_article_if_exists( app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: response = await authorized_client.get( app.url_path_for("articles:get-article", slug=test_article.slug)) article = ArticleInResponse(**response.json()) assert article.article == test_article
async def test_user_can_update_article( app: FastAPI, authorized_client: AsyncClient, test_article: Article, update_field: str, update_value: str, extra_updates: dict, ) -> None: # type: ignore response = await authorized_client.put( app.url_path_for("articles:update-article", slug=test_article.slug), json={"article": { update_field: update_value }}, ) assert response.status_code == status.HTTP_200_OK article = ArticleInResponse(**response.json()).article article_as_dict = article.dict() assert article_as_dict[update_field] == update_value for extra_field, extra_value in extra_updates.items(): assert article_as_dict[extra_field] == extra_value exclude_fields = {update_field, *extra_updates.keys(), "updated_at"} assert article.dict(exclude=exclude_fields) == test_article.dict( exclude=exclude_fields)
async def test_article_will_contain_only_attached_tags( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, pool: Pool) -> None: attached_tags = ["tag1", "tag3"] async with pool.acquire() as connection: articles_repo = ArticlesRepository(connection) await articles_repo.create_article( slug=f"test-slug", title="tmp", description="tmp", body="tmp", author=test_user, tags=attached_tags, ) for i in range(5): await articles_repo.create_article( slug=f"slug-{i}", title="tmp", description="tmp", body="tmp", author=test_user, tags=[f"tag-{i}"], ) response = await authorized_client.get( app.url_path_for("articles:get-article", slug="test-slug")) article = ArticleInResponse(**response.json()) assert len(article.article.tags) == len(attached_tags) assert set(article.article.tags) == set(attached_tags)
async def test_unable_to_login_with_wrong_jwt_prefix(app: FastAPI, client: AsyncClient, token: str) -> None: response = await client.get( app.url_path_for("users:get-current-user"), headers={"Authorization": f"WrongPrefix {token}"}, ) assert response.status_code == HTTP_403_FORBIDDEN
async def test_unable_to_login_when_user_does_not_exist_any_more( app: FastAPI, client: AsyncClient, authorization_prefix: str) -> None: token = create_access_token_for_user( User(username="******", email="*****@*****.**"), "secret") response = await client.get( app.url_path_for("users:get-current-user"), headers={"Authorization": f"{authorization_prefix} {token}"}, ) assert response.status_code == HTTP_403_FORBIDDEN
async def test_user_receiving_feed_with_limit_and_offset( app: FastAPI, authorized_client: AsyncClient, test_article: Article, test_user: UserInDB, pool: Pool, ) -> None: async with pool.acquire() as connection: users_repo = UsersRepository(connection) profiles_repo = ProfilesRepository(connection) articles_repo = ArticlesRepository(connection) for i in range(5): user = await users_repo.create_user(username=f"user-{i}", email=f"user-{i}@email.com", password="******") if i == 2: await profiles_repo.add_user_into_followers( target_user=user, requested_user=test_user) for j in range(5): await articles_repo.create_article( slug=f"slug-{i}-{j}", title="tmp", description="tmp", body="tmp", author=user, tags=[f"tag-{i}-{j}"], ) full_response = await authorized_client.get( app.url_path_for("articles:get-user-feed-articles")) full_articles = ListOfArticlesInResponse(**full_response.json()) response = await authorized_client.get( app.url_path_for("articles:get-user-feed-articles"), params={ "limit": 2, "offset": 3 }, ) articles_from_response = ListOfArticlesInResponse(**response.json()) assert full_articles.articles[3:] == articles_from_response.articles
async def test_user_can_not_retrieve_not_existing_article( app: FastAPI, authorized_client: AsyncClient, test_article: Article, api_method: str, route_name: str, ) -> None: response = await authorized_client.request( api_method, app.url_path_for(route_name, slug="wrong-slug")) assert response.status_code == status.HTTP_404_NOT_FOUND
async def test_user_will_receive_error_for_not_existing_comment( app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: not_found_response = await authorized_client.delete( app.url_path_for( "comments:delete-comment-from-article", slug=test_article.slug, comment_id="1", )) assert not_found_response.status_code == status.HTTP_404_NOT_FOUND
async def test_user_can_not_change_following_state_for_him_self( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, api_method: str, route_name: str, ) -> None: response = await authorized_client.request( api_method, app.url_path_for(route_name, username=test_user.username)) assert response.status_code == status.HTTP_400_BAD_REQUEST
async def test_user_can_add_comment_for_article(app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: created_comment_response = await authorized_client.post( app.url_path_for("comments:create-comment-for-article", slug=test_article.slug), json={"comment": { "body": "comment" }}, ) created_comment = CommentInResponse(**created_comment_response.json()) comments_for_article_response = await authorized_client.get( app.url_path_for("comments:get-comments-for-article", slug=test_article.slug)) comments = ListOfCommentsInResponse(**comments_for_article_response.json()) assert created_comment.comment == comments.comments[0]
async def test_user_login_when_credential_part_does_not_match( app: FastAPI, client: AsyncClient, test_user: UserInDB, credentials_part: str, credentials_value: str, ) -> None: login_json = {"user": {"email": "*****@*****.**", "password": "******"}} login_json["user"][credentials_part] = credentials_value response = await client.post(app.url_path_for("auth:login"), json=login_json) assert response.status_code == HTTP_400_BAD_REQUEST
async def test_user_can_not_create_article_with_duplicated_slug( app: FastAPI, authorized_client: AsyncClient, test_article: Article) -> None: article_data = { "title": "Test Slug", "body": "does not matter", "description": "¯\\_(ツ)_/¯", } response = await authorized_client.post( app.url_path_for("articles:create-article"), json={"article": article_data}) assert response.status_code == status.HTTP_400_BAD_REQUEST
async def test_list_of_tags_when_tags_exist( app: FastAPI, client: AsyncClient, pool: Pool ) -> None: tags = ["tag1", "tag2", "tag3", "tag4", "tag1"] async with pool.acquire() as conn: tags_repo = TagsRepository(conn) await tags_repo.create_tags_that_dont_exist(tags=tags) response = await client.get(app.url_path_for("tags:get-all")) tags_from_response = response.json()["tags"] assert len(tags_from_response) == len(set(tags)) assert all((tag in tags for tag in tags_from_response))
async def test_user_can_delete_his_article( app: FastAPI, authorized_client: AsyncClient, test_article: Article, pool: Pool, ) -> None: await authorized_client.delete( app.url_path_for("articles:delete-article", slug=test_article.slug)) async with pool.acquire() as connection: articles_repo = ArticlesRepository(connection) with pytest.raises(EntityDoesNotExist): await articles_repo.get_article_by_slug(slug=test_article.slug)
async def test_filtering_by_favorited( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, pool: Pool, favorited: str, result: int, ) -> None: async with pool.acquire() as connection: users_repo = UsersRepository(connection) articles_repo = ArticlesRepository(connection) fan1 = await users_repo.create_user(username="******", email="*****@*****.**", password="******") fan2 = await users_repo.create_user(username="******", email="*****@*****.**", password="******") article1 = await articles_repo.create_article(slug=f"slug-1", title="tmp", description="tmp", body="tmp", author=test_user) article2 = await articles_repo.create_article(slug=f"slug-2", title="tmp", description="tmp", body="tmp", author=test_user) await articles_repo.add_article_into_favorites(article=article1, user=fan1) await articles_repo.add_article_into_favorites(article=article1, user=fan2) await articles_repo.add_article_into_favorites(article=article2, user=fan2) for i in range(5, 10): await articles_repo.create_article( slug=f"slug-{i}", title="tmp", description="tmp", body="tmp", author=test_user, ) response = await authorized_client.get( app.url_path_for("articles:list-articles"), params={"favorited": favorited}) articles = ListOfArticlesInResponse(**response.json()) assert articles.articles_count == result
async def test_user_can_create_article(app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB) -> None: article_data = { "title": "Test Slug", "body": "does not matter", "description": "¯\\_(ツ)_/¯", } response = await authorized_client.post( app.url_path_for("articles:create-article"), json={"article": article_data}) article = ArticleInResponse(**response.json()) assert article.article.title == article_data["title"] assert article.article.author.username == test_user.username
async def test_not_existing_tags_will_be_created_without_duplication( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB) -> None: article_data = { "title": "Test Slug", "body": "does not matter", "description": "¯\\_(ツ)_/¯", "tagList": ["tag1", "tag2", "tag3", "tag3"], } response = await authorized_client.post( app.url_path_for("articles:create-article"), json={"article": article_data}) article = ArticleInResponse(**response.json()) assert set(article.article.tags) == {"tag1", "tag2", "tag3"}
async def test_user_that_does_not_follows_another_will_receive_profile_without_follow( app: FastAPI, authorized_client: AsyncClient, pool: Pool) -> None: async with pool.acquire() as conn: users_repo = UsersRepository(conn) user = await users_repo.create_user( username="******", email="*****@*****.**", password="******", ) response = await authorized_client.get( app.url_path_for("profiles:get-profile", username=user.username)) profile = ProfileInResponse(**response.json()) assert profile.profile.username == user.username assert not profile.profile.following
async def test_user_success_registration( app: FastAPI, client: AsyncClient, pool: Pool ) -> None: email, username, password = "******", "username", "password" registration_json = { "user": {"email": email, "username": username, "password": password} } response = await client.post( app.url_path_for("auth:register"), json=registration_json ) assert response.status_code == HTTP_201_CREATED async with pool.acquire() as conn: repo = UsersRepository(conn) user = await repo.get_user_by_email(email=email) assert user.email == email assert user.username == username assert user.check_password(password)
async def test_filtering_by_tags( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, pool: Pool, tag: str, result: int, ) -> None: async with pool.acquire() as connection: articles_repo = ArticlesRepository(connection) await articles_repo.create_article( slug=f"slug-1", title="tmp", description="tmp", body="tmp", author=test_user, tags=["tag1", "tag2"], ) await articles_repo.create_article( slug=f"slug-2", title="tmp", description="tmp", body="tmp", author=test_user, tags=["tag2"], ) for i in range(5, 10): await articles_repo.create_article( slug=f"slug-{i}", title="tmp", description="tmp", body="tmp", author=test_user, tags=[f"tag-{i}"], ) response = await authorized_client.get( app.url_path_for("articles:list-articles"), params={"tag": tag}) articles = ListOfArticlesInResponse(**response.json()) assert articles.articles_count == result
async def test_failed_user_registration_when_some_credentials_are_taken( app: FastAPI, client: AsyncClient, test_user: UserInDB, credentials_part: str, credentials_value: str, ) -> None: registration_json = { "user": { "email": "*****@*****.**", "username": "******", "password": "******", } } registration_json["user"][credentials_part] = credentials_value response = await client.post( app.url_path_for("auth:register"), json=registration_json ) assert response.status_code == HTTP_400_BAD_REQUEST