@@ -210,3 +210,50 @@ async def test_archive_nonexistent_todo(client: AsyncClient):
210210 response = await client .post ("/api/todos/9999/archive" )
211211 assert response .status_code == 404
212212 assert response .json ()["detail" ] == "Todo not found"
213+
214+
215+ @pytest .mark .asyncio
216+ async def test_search_matches_title_and_description_case_insensitively (client : AsyncClient ):
217+ """Test searching todos by text in the title or description."""
218+ await client .post ("/api/todos" , json = {"title" : "Buy Milk" })
219+ await client .post (
220+ "/api/todos" ,
221+ json = {"title" : "Plan trip" , "description" : "Book flights and a MILK run" },
222+ )
223+ await client .post ("/api/todos" , json = {"title" : "Unrelated" })
224+
225+ response = await client .get ("/api/todos?search=milk" )
226+ assert response .status_code == 200
227+ assert sorted (todo ["title" ] for todo in response .json ()) == ["Buy Milk" , "Plan trip" ]
228+
229+
230+ @pytest .mark .asyncio
231+ async def test_search_without_matches_returns_empty_list (client : AsyncClient ):
232+ """Test that a search with no matches returns an empty list."""
233+ await client .post ("/api/todos" , json = {"title" : "Buy milk" })
234+
235+ response = await client .get ("/api/todos?search=bread" )
236+ assert response .status_code == 200
237+ assert response .json () == []
238+
239+
240+ @pytest .mark .asyncio
241+ async def test_search_treats_wildcards_literally (client : AsyncClient ):
242+ """Test that % and _ in the search term are not interpreted as LIKE wildcards."""
243+ await client .post ("/api/todos" , json = {"title" : "Reach 100% coverage" })
244+ await client .post ("/api/todos" , json = {"title" : "Reach 100 points" })
245+
246+ response = await client .get ("/api/todos?search=100%25" )
247+ assert [todo ["title" ] for todo in response .json ()] == ["Reach 100% coverage" ]
248+
249+
250+ @pytest .mark .asyncio
251+ async def test_search_combines_with_completed_filter (client : AsyncClient ):
252+ """Test combining search with the completed filter."""
253+ open_todo = await client .post ("/api/todos" , json = {"title" : "Write report" })
254+ done_todo = await client .post ("/api/todos" , json = {"title" : "Write changelog" })
255+ await client .patch (f"/api/todos/{ done_todo .json ()['id' ]} " , json = {"completed" : True })
256+
257+ response = await client .get ("/api/todos?search=write&completed=true" )
258+ assert [todo ["id" ] for todo in response .json ()] == [done_todo .json ()["id" ]]
259+ assert open_todo .json ()["id" ] not in [todo ["id" ] for todo in response .json ()]
0 commit comments